Modifying the value of a float-like object

E

Eric.Le.Bigot

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed? The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.

I thought of two solutions, both of which I can't make to work:

1) Use a class that inherits from float. This takes care of the
"behave like float" part. But is it possible to change the value of
the float associated with an instance? That is, is it possible to
do: "x = MyFloat(1.23); x.change_value(3.14)" so that x's float value
becomes 3.14?

2) The other possibility I thought of was: use a class that defines a
'value' member (x.value). This takes care of the "value can be
changed" part. But is it possible/easy to make it fully behave like a
float (including when passed to functions like math.sin)?

Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=3.0 +/- 0.1 and b=1.00 +/-
0.01").

Any idea would be much appreciated!
 
E

Eric.Le.Bigot

It looks like what is needed here are a kind of "mutable float". Is
there a simple way of creating such a type? I don't mind changing the
value through x.value = 1.23 instead of x = 1.23... :)
 
D

David Smith

It looks like what is needed here are a kind of "mutable float". Is
there a simple way of creating such a type? I don't mind changing the
value through x.value = 1.23 instead of x = 1.23... :)

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed? The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.

I thought of two solutions, both of which I can't make to work:

1) Use a class that inherits from float. This takes care of the
"behave like float" part. But is it possible to change the value of
the float associated with an instance? That is, is it possible to
do: "x = MyFloat(1.23); x.change_value(3.14)" so that x's float value
becomes 3.14?

2) The other possibility I thought of was: use a class that defines a
'value' member (x.value). This takes care of the "value can be
changed" part. But is it possible/easy to make it fully behave like a
float (including when passed to functions like math.sin)?

Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=3.0 +/- 0.1 and b=1.00 +/-
0.01").

Any idea would be much appreciated!

I think you'll have to describe your use case a little better. I don't
see why you'd need a mutable float. As long as the reference x is
visible to the other parts of your code, when that code uses x, it'll
always get the right instance of a float object.


--David
 
D

David Robinow

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed?  The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.
It's not clear what your requirement is.
Why can't you just use floats?
For your list, why can't you use a list of floats?
Something is missing from your explanation.
 
M

MRAB

Christian said:
Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed? The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.


Your approach doesn't follow the Python philosophy thus it's most likely
to fail. It is possible to implement a mutable float like object --
Python doesn't stop you from shooting yourself in the knee -- but please
don't harm yourself.
[snip]
The saying is actually "shooting yourself in the foot", but then that's
like what happens when you don't follow the Python philosophy! :)
 
P

Peter Otten

Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=3.0 +/- 0.1 and b=1.00 +/-
0.01").

Naive no warranties implementation:

from math import sin, sqrt

class Value(object):
def __init__(self, value, err):
self.value = value
self.err = err
def __str__(self):
return "%s +- %s" % (self.value, self.err)

def derive(f, values, i, eps=1e-5):
x1 = f(*values)
values = list(values)
values += eps
x2 = f(*values)
return (x2-x1)/eps

def calc(f, *args):
values = [v.value for v in args]
errs = [v.err for v in args]

sigma = 0
for i, (v, e) in enumerate(zip(values, errs)):
x = derive(f, values, i)*e
sigma += x*x
return Value(f(*values), sqrt(sigma))

a = Value(3.0, 0.1)
b = Value(1.0, 0.01)

def f(x, y):
return x * sin(y)

print "a = %s" % a
print "b = %s" % b
print "c = %s" % calc(f, a, b)

Peter
 
D

Dave Angel

It looks like what is needed here are a kind of "mutable float". Is
there a simple way of creating such a type? I don't mind changing the
value through x.value =.23 instead of x = 1.23... :)

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed? The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value =.14) so that any expression like "x
+y" uses the new value.

I thought of two solutions, both of which I can't make to work:

1) Use a class that inherits from float. This takes care of the
"behave like float" part. But is it possible to change the value of
the float associated with an instance? That is, is it possible to
do: "x =yFloat(1.23); x.change_value(3.14)" so that x's float value
becomes 3.14?

2) The other possibility I thought of was: use a class that defines a
'value' member (x.value). This takes care of the "value can be
changed" part. But is it possible/easy to make it fully behave like a
float (including when passed to functions like math.sin)?

Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=0 +/- 0.1 and b=1.00 +/-
0.01").

Any idea would be much appreciated!

The answer to your original question is no. If the value can be changed, then it doesn't behave like a float. And that's not just a pedantic answer, it's a serious consideration.

You have to decide what characteristics of a float you need to mimic, and which ones you don't care about, and which ones you want to change. Only after having a pretty good handle on those answers can you pick a "best" implementation.

Let's call this new type a nfloat, and let's assume you have a function that returns one. That might be a constructor, but it may not, so we're keeping our options open.
myval = newfunction(42.0)



What do you want to happen when you execute b = myval ? Presumably
you want them to be "equal" but in what sense? Suppose you then change
one of them with your suggested attribute/method.
myval.value = newfunction("aaa")

is b the same as it was (like a float would be), or is b also changed?

Do you need lots of functions to work on one of these nfloats, or could
you use them as follows:
sin( b.value )

Instead of using .value to change the underlying float, how about if you
use [0] ? Just use a list of size 1.
 
E

Eric.Le.Bigot

Thank you all for your input. It is not yet obvious how to achieve
the goal/need that I had in mind in the original post. Basically, I
would need to be able to calculate the derive() function of Peter, but
without knowing what arguments are passed to the function f under
study. Here is why:


I'll give more details, as David S. and David R. were asking for. The
code could look like this:

import crystals
my_crystal = crystals.Crystal("Quartz 111")

which would set some attributes of my_crystal as "floats with
uncertainty" FloatWithUncert, which behave exactly like floats in
calculations (they return the central value of the confidence
interval: x returns the value, as for floats, while, x.uncert returns
the uncertainty). Now, I'd like to perform a calculation of some
physical quantity associated to the crystal:

print my_crystal.lattice_spacing(temperature = 273.15)
setup = Experiment(my_crystal, my_mirror); print setup.bragg_angle
() # An Experiment object also defines and uses FloatWithUncert
objects

Everything is fine up to now (I have a FloatWithUncert class which
inherits from float).

Now, I would like to get the uncertainty on the result, even though we
have no idea of what quantities are used in lattice_spacing() for the
calculation (it can be attribute that are floats, attributes that are
FloatWithUncert, module globals defined as FloatWithUncert, etc.).
The idea that prompted my initial post was as follows: perform the
same calculation of lattice_spacing() many times, but each time change
on of existing FloatWithUncert numbers (this is akin to the derive()
function of Peter) and deduce the uncertainty on lattice_spacing() (as
with the calc() function of Peter). So I thought that the
FloatWithUncert class could keep a list createdNumbers of all created
FloatWithUncert numbers, be instructed to change the "float" value of
the n-th float to "central value + uncertainty", and the calculation
would then be performed again, but with a single updated number (as in
calc() above):

FloatWithUncert.shift_number(n = 3) # The 3rd FloatWithUncert ever
created will return "central value + uncertainty"; others return the
central value
print my_crystal.lattice_spacing(temperature = 273.15) # This
should give a new result

The original post was essentially asking: is it possible to write
shift_number() in Python? i.e., we have objects 'x' of type
FloatWithUncert, which return a single float value when used in
expressions such as 'x+1', which can be tracked in a list
FloatWithUncert.createdNumbers (created by FloatWithUncert), and
modified later (FloatWithUncert.createdNumbers[3].value = ...). In
other words, as I was saying in my second post, a kind of mutable
float would effectively be needed.

Now, to respond to David S., David R. and Christian, it's not possible
to use a simple list of floats [x, y,...] because this would not help
making the result of "x+y" change when you change one of the floats
_through the list_ (again, I have no other information on what
variables, globals, instance attributes, etc. are used in the
calculation whose uncertainty is being calculated). I would not like
to write my numerous mathematical expressions as list_of_floats
[0]+list_of_floats[1]*sin(...), etc. (This would be illegible, and
would not be robust.)

Peter's solution is nice when you call functions with explicit
arguments. But my class methods perform calculations through instance
attributes, globals, etc., and I don't want to modify all my
calculation code in order to implement error propagation.

I hope that the problem is clearer, now. :)


A couple of ideas I had:

1) Define a FloatWithUncert object, but get instance values as x(), as
in "x()+y()". The code is relatively legible. 'x' is mutable. But
formulas don't look so good, and you can't drop a float replacement
for 'x', as floats are not callable.

2) Write all expressions that could contain FloatWithUncert objects
with a 'float()' wrapper ("float(x)+float(y)"), after defining the
FloatWithUncert.__float__() method. FloatWithUncert would be
mutable. The code is a little bit heavy, but it is explicit. 'x'
could be a pure float.


Sorry for this long post. Any thought/idea/remark would be most
welcome!
 
E

Eric.Le.Bigot

Thanks Dave for your thoughtful remarks, which you sent right when I
was writing a response to the previous posts.

I was wondering about a kind "mutable float"; so you're right, it's
not fully a float, because it's mutable. I'd like to have an object
that behaves like a float in numerical calculations. I understand
that mutability would require to handle such objects with care, as in
your example, but Python programmers are used to this with any mutable
object. All my calculations use "constants with an uncertainty" (or
regular floats).

There are many such calculations in my code, and I'd like it to be
very clean. The first idea I mentioned (using "x()") is essentially
what you propose with using "x[0]" in calculations.

So, it looks like it's not possible to have float-like objects
(calculation/formula-wise) that are mutable?! and it also looks like
the price to pay for the mutability is to have to write "heavier"
versions of any formula that uses these "special floats" (that carry
an uncertainty): "x[0]+y[0]*sin(...)", "x()+y()", "float(x)+float
(y)",... which, by the way, essentially prevents any float-like
object from being used as a float in formulas that you don't write
yourself.

This does not look good. Python is failing me!!! :/ I heard that
this would be easy to do in Ruby (not confirmed, though)...

More ideas and thoughts would still be most welcome!

It looks like what is needed here are a kind of "mutable float".  Is
there a simple way of creating such a type?  I don't mind changing the
value through x.value =.23 instead of x = 1.23... :)
On Apr 14, 3:03 pm, (e-mail address removed) wrote:
Hello,
Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed?  The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value =.14) so that any expression like "x
+y" uses the new value.
I thought of two solutions, both of which I can't make to work:
1) Use a class that inherits from float.  This takes care of the
"behave like float" part.  But is it possible to change the value of
the float associated with an instance?  That is, is it possible to
do:  "x =yFloat(1.23); x.change_value(3.14)" so that x's float value
becomes 3.14?
2) The other possibility I thought of was: use a class that defines a
'value' member (x.value).  This takes care of the "value can be
changed" part.  But is it possible/easy to make it fully behave like a
float (including when passed to functions like math.sin)?
Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=0 +/- 0.1 and b=1.00 +/-
0.01").
Any idea would be much appreciated!

The answer to your original question is no.  If the value can be changed, then it doesn't behave like a float.  And that's not just a pedantic answer, it's a serious consideration.

You have to decide what characteristics of a float you need to mimic, and which ones you don't care about, and which ones you want to change.  Only after having a pretty good handle on those answers can you pick a "best" implementation.

Let's call this new type a nfloat, and let's assume you have a function that returns one.  That might be a constructor, but it may not, so we're keeping our options open.
  myval = newfunction(42.0)

What do you want to happen when you execute   b = myval ?   Presumably
you want them to be "equal" but in what sense?  Suppose you then change
one of them with your suggested attribute/method.
     myval.value = newfunction("aaa")

is b the same as it was (like a float would be), or is b also changed?

Do you need lots of functions to work on one of these nfloats, or could
you use them as follows:
     sin( b.value )

Instead of using .value to change the underlying float, how about if you
use [0] ?  Just use a list of size 1.
 
S

Steven D'Aprano

The answer to your original question is no. If the value can be
changed, then it doesn't behave like a float. And that's not just a
pedantic answer, it's a serious consideration.

Oh nonsense. Many programming languages have mutable floats.
 
S

Steven D'Aprano

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed?

Yes, have a look at the source code for UserString.MutableString for some
ideas.

The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.

Why is that the goal? If you want to change the value of x, just change
the value of x.
 
S

Steven D'Aprano

I'll give more details, as David S. and David R. were asking for. The
code could look like this:

import crystals
my_crystal = crystals.Crystal("Quartz 111")

which would set some attributes of my_crystal as "floats with
uncertainty" FloatWithUncert, which behave exactly like floats in
calculations (they return the central value of the confidence interval:
x returns the value, as for floats, while, x.uncert returns the
uncertainty).

So far so good -- this is just straight-forward interval arithmetic.
Nothing about this requires mutability.

Now, I'd like to perform a calculation of some physical
quantity associated to the crystal:

print my_crystal.lattice_spacing(temperature = 273.15) setup =
Experiment(my_crystal, my_mirror); print setup.bragg_angle
() # An Experiment object also defines and uses FloatWithUncert objects

Everything is fine up to now (I have a FloatWithUncert class which
inherits from float).

Your programming model is not clear. Does the Experiment class represent
the things you do to perform the experimental procedure? Or does it
represent the result(s) you get after you perform the experimental
procedure?

Now, I would like to get the uncertainty on the result,

What's "the result"? Is setup "the result"? Or setup.bragg_angle? Or
something else?

even though we
have no idea of what quantities are used in lattice_spacing() for the
calculation (it can be attribute that are floats, attributes that are
FloatWithUncert, module globals defined as FloatWithUncert, etc.).


I'm going to assume that you have a valid way of combining floats with
FloatWithUncert that doesn't invalidate your error estimates.

Still there's nothing here that requires mutability.

The
idea that prompted my initial post was as follows: perform the same
calculation of lattice_spacing() many times, but each time change on of
existing FloatWithUncert numbers (this is akin to the derive() function
of Peter) and deduce the uncertainty on lattice_spacing()

I think you are asking for this behaviour:
(4.567, 0.003)

If so, that is bad and evil. You might think it is a good idea now, but
trust me, it will lead to tears.


Do this instead:
(4.567, 0.003)



You might think mutable values changing by magic is a good thing now, but
trust me, it isn't. Let me put it this way... if you were doing a real
experiment, and you had a note pad and *wrote down* the lattice spacing
after an experiment, and then a week later somebody came into the lab and
changed some component in the experimental setup, and the numbers in your
notepad changed, that would be a disaster. What you're suggesting (or at
least what I think you're suggesting) is the same thing, only not quite
as extreme.
 
P

Peter Otten

Now, I would like to get the uncertainty on the result, even though we
have no idea of what quantities are used in lattice_spacing() for the
calculation (it can be attribute that are floats, attributes that are
FloatWithUncert, module globals defined as FloatWithUncert, etc.).

I think this is your main problem. What you describe is a source of hard to
find bugs and a maintenance nightmare.

I also don't understand what you want to do with the results. Consider a
simple example

a = 1 +- 0.1
b = 1 +- 0.1

Now let's calculate a + b. With my approach you get

a + b = 2 +- 0.14

i. e. the result falls in the interval 1.86...2.14 with the same likelihood
that a and b are within 0.9...1.1. You don't get 2 +- 0.2 because the
errors sometimes cancel out.

With your approach you get (some permutation of)

a + b = [1.9, 1.9, 2.0, 2.0, 2.1, 2.1]

What is that supposed to mean? Let's assume you have one additional variable

c = 42 +- 7 # whatever

Your result will become

a + b = [1.9, 1.9, 2.0, 2.0, 2.0, 2.0, 2.0, 2.1, 2.1]

Hmm...

Here's the code I used to get that result:

class F(object):
all = []
def __init__(self, value, err):
self.value = value
self.err = err
self.shift = 0
self.all.append(self)

def __float__(self):
return self.value + self.err * self.shift

def __add__(self, other):
return float(self) + float(other)
__radd__ = __add__
def __mul__(self, other):
return float(self) * float(other)
__rmul__ = __mul__

def __str__(self):
return "F(%s)" % float(self)

a = F(1.0, 0.1)
b = F(1.0, 0.1)
unused = F(42.0, 7.0)

results = []
for f in F.all:
for f.shift in [-1, 0, 1]:
print "a = %s, b = %s, a+b = %s" % (a, b, a + b)
results.append(a+b)
f.shift = 0
print "[%s]" % ", ".join("%.1f" % r for r in sorted(results))

If you add enough arithmetic operations it might even "work" with your
codebase.

Peter
 
E

Eric.Le.Bigot

Ben F., you're right on the money! You expressed exactly what I'm
looking for. Why should I want this? because the place in the code
where (foo, baz) is calculated has _no idea_ of what foo and baz are,
of where they were defined, etc.; on the other hand, the floatref
class can keep track of the values that were constructed, and I'm
looking for a way of modifying them from its perspective
(floatref.change_value(index, new_value)).

Steven, t

To Steven: Thank you for your suggestion about checking
UserString.MutableString.
I do understand that mutable objects can be surprising, but, again,
Python programmers constantly use such objects (lists, dicts,....): I
don't think that manipulating a mutable float is more of a problem
than using a list, for a Python programmer.
As for your idea of "straight-forward interval arithmetic", it's a
good one, but I'd have to redefine lots of functions from the math
module, to use them explicitly in my code, etc.: this is heavy; I was
looking for a light-weight alternative, where all calculations are
expressed in Python as if all numbers were regular floats, and where
you don't have to redefine any mathematical operation. In other
words, I'm looking for a robust way of implementing the derive()
function of Peter without knowing anything about which function uses
which "numbers with an uncertainty": the equivalent of Peter's derive
() would simply successively change all "numbers with uncertainty"
defined so far and see how the result of a given calculation varies--
the variables that are not used in the calculated expression don't
change the result, for instance. I understand that this is
computationally inefficient (too many variables might be changed), but
I don't need speed, only robustness in the propagation of errors, and
a simple and very legible calculation code, and ideally with only a
few lines of Python.

Anyway, Steven gave me hope that some kind of mutable float is
possible in Python, and Ben perfectly expressed my need. Again,
alternatively, any module that handles in a convenient manner
calculations with error propagation would be great, but I have not
found any single such module!


Steven D'Aprano said:
The goal is to maintain a list [x, y,…] of these float-like
objects, and to modify their value on the fly (with something like
x.value = 3.14) so that any expression like "x
+y" uses the new value.
Why is that the goal? If you want to change the value of x, just
change the value of x.

As you're aware (but Eric may not be), Python doesn't have “change the
value of x”. The closest would be to re-bind the name ‘x’ to a different
value, which would not be what Eric is asking for.

If I understand correctly, Eric wants something with the following
behaviour:

    >>> foo = [floatref(3.14), floatref(1.41)]
    >>> bar = foo[0]
    >>> baz = foo[1]
    >>> foo
    [3.14, 1.41]
    >>> (bar, baz)
    (3.14, 1.41)

    >>> foo[1].changevalue(1.62)
    >>> foo
    [3.14, 1.62]
    >>> (bar, baz)
    (3.14, 1.62)

and is asking how to get such a ‘floatref’.

--
 \        “If you go parachuting, and your parachute doesn't open, and |
  `\        you friends are all watching you fall, I think a funny gag |
_o__)             would be to pretend you were swimming.” —Jack Handey |
Ben Finney
 
D

Dan Goodman

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed? The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.

Hi Eric,

Numpy's array object can do something like what you want:

In [27]: x=array(0.0)

In [28]: print x, sin(x)
0.0 0.0

In [29]: x.itemset(pi/2)

In [30]: print x, sin(x)
1.57079632679 1.0

Not sure if this a recommended way of using array or not, but it seems
to work. The problem is that any calculation you do with such an object
will result in a float, and not another numpy array (although inplace
operations work):

In [40]: print (x*2).__class__
<type 'numpy.float64'>

In [41]: x *= 2

In [42]: print x.__class__
<type 'numpy.ndarray'>

So it's not a perfect solution, but it might be OK for what you need.

Dan
 
E

Eric.Le.Bigot

To Peter: What I had in mind was to implement your calc() function;
you could do something similar with your loop in the previous post by
replacing "for f.shift..." by "f.shift = 1"; this would give you 2
values, which you can combine with your unused variable in order to
obtain the same value as with your calc() function.

To Peter and Steven: I now realize that the interval arithmetic that
you propose is not trivial, if one wants optimal confidence intervals:
correlations between uncertainties are very hard to handle. The most
robust method is to implement Peter's calc() method. But again, when
calculations are not done through explicit argument passing, as in
Peter's example, mutable floats are useful!
 
S

Steven D'Aprano

Ben F., you're right on the money! You expressed exactly what I'm
looking for. Why should I want this? because the place in the code
where (foo, baz) is calculated has _no idea_ of what foo and baz are, of
where they were defined, etc.;


This makes no sense. The piece of code which calculates (foo, baz) knows
EXACTLY what foo and baz are, because it has just calculated them. It has
them *right there*. If it wants to know what they are, it can just look
at them:

def calculate():
# lots of calculations
result = (foo, baz)
# what is foo?
foo
# what is baz?
baz
# what are their types?
type(foo)
type(baz)

As for where they were defined... why do you care where they were
defined? What's important is *what they are*, and you know what they are,
because you have them, right there.

on the other hand, the floatref class can
keep track of the values that were constructed,

What advantage does that give you? I can think of big disadvantages: it
is complicated and inefficient and will lead to bugs in your code.


[...]
To Steven: Thank you for your suggestion about checking
UserString.MutableString.
I do understand that mutable objects can be surprising, but, again,
Python programmers constantly use such objects (lists, dicts,....): I
don't think that manipulating a mutable float is more of a problem than
using a list, for a Python programmer.

Lists and floats tend to be used in completely different ways.

I don't have (much) problem with the idea of having mutable floats per
se, although I think they are unnecessary. But even given mutable floats,
the use you seem to want to put them will lead you into trouble.

As for your idea of
"straight-forward interval arithmetic", it's a good one, but I'd have to
redefine lots of functions from the math module, to use them explicitly
in my code, etc.:

But you need to do that anyway, because the math module doesn't calculate
the error estimates that you need. Given some FloatWithError x, if you
call math.sin(x) the math.sin() function makes no effort to calculate an
error term.

this is heavy; I was looking for a light-weight
alternative, where all calculations are expressed in Python as if all
numbers were regular floats, and where you don't have to redefine any
mathematical operation. In other words, I'm looking for a robust way of
implementing the derive() function of Peter without knowing anything
about which function uses which "numbers with an uncertainty": the
equivalent of Peter's derive () would simply successively change all
"numbers with uncertainty" defined so far and see how the result of a
given calculation varies-- the variables that are not used in the
calculated expression don't change the result, for instance. I
understand that this is computationally inefficient (too many variables
might be changed), but I don't need speed, only robustness in the
propagation of errors, and a simple and very legible calculation code,
and ideally with only a few lines of Python.

Nothing you have described gives me any confidence in the robustness of
your solution. In fact the opposite: given the description of what you
are planning, I'd have ZERO confidence in ANY calculation you did,
because I'd wonder how all the other calculations being performed were
effecting the calculations you've already done.

As far as I can tell, you are conflating four different issues as if they
were one:

(1) how to calculate and propagate errors and do interval arithmetic;

(2) how to use the functions in the math module with arguments which
aren't floats;

(3) how to make a mutable float type;

(4) how to have the result of a calculation magically change when you
change the arguments, without re-doing the calculation (at least not
explicitly re-doing the calculation).

(1) - (3) are reasonable; (3) is I think pointless but not actively
harmful; but (4) is just creating a world of pain and almost-impossible
to track down bugs.

Anyway, Steven gave me hope that some kind of mutable float is possible
in Python, and Ben perfectly expressed my need. Again, alternatively,
any module that handles in a convenient manner calculations with error
propagation would be great, but I have not found any single such module!


http://pyinterval.googlecode.com/svn/trunk/html/index.html

http://docs.sympy.org/modules/mpmath/intervals.html

You should also read this:
http://conference.scipy.org/proceedings/SciPy2008/paper_3/
 
E

Eric.Le.Bigot

Dan, wow! This looks extremely promising!


I initially tried to create a Float_ref class that inherits from
numpy.array, so that objects of the new class behave like numpy.array
in calculations, but also contain an "uncertainty" atribute, but this
is apparently not allowed ("cannot create 'builtin_function_or_method'
instances").

So I thought I'd directly add an attribute to a numpy.array: "x =
numpy.array(3.14); x.uncertainty = 0.01", but this is not allowed
either.

Thus, it is not obvious for me to extend the 1x1 numpy.array object so
that it also contains an "uncertainty" attribute.


However, I think your suggestion can largely solve the original
problem, with a small price to pay: numbers with uncertainties can be
defined in a module that keeps declared values in a list of
numpy.arrays, and the associated uncertainties in another list: after
"registering" many "mutable float" objects, the modules would contain
the following lists:
mutable_floats = [ numpy.array(3.14), numpy.array(1.41),...]
uncertainties = [ 0.01, 0.01 ,...]

The floatref class could instead be a simple function that returns the
last numpy.array created, after adding an element to both the
mutable_float and uncertainties lists. What we lose here is that it's
hard to get the uncertainty associated to a given variable (this is
obviously possible if no other variable has the same value, though).

Dan, you gave me hope that precise error propagation calculations can
be done by repeated calls to unmodified calculation code designed for
floats! Thanks!

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed?  The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value = 3.14) so that any expression like "x
+y" uses the new value.

Hi Eric,

Numpy's array object can do something like what you want:

In [27]: x=array(0.0)

In [28]: print x, sin(x)
0.0 0.0

In [29]: x.itemset(pi/2)

In [30]: print x, sin(x)
1.57079632679 1.0

Not sure if this a recommended way of using array or not, but it seems
to work. The problem is that any calculation you do with such an object
will result in a float, and not another numpy array (although inplace
operations work):

In [40]: print (x*2).__class__
<type 'numpy.float64'>

In [41]: x *= 2

In [42]: print x.__class__
<type 'numpy.ndarray'>

So it's not a perfect solution, but it might be OK for what you need.

Dan
 
D

Dave Angel

Thanks Dave for your thoughtful remarks, which you sent right when I
was writing a response to the previous posts.

I was wondering about a kind "mutable float"; so you're right, it's
not fully a float, because it's mutable. I'd like to have an object
that behaves like a float in numerical calculations. I understand
that mutability would require to handle such objects with care, as in
your example, but Python programmers are used to this with any mutable
object. All my calculations use "constants with an uncertainty" (or
regular floats).

There are many such calculations in my code, and I'd like it to be
very clean. The first idea I mentioned (using "x()") is essentially
what you propose with using "x[0]" in calculations.

So, it looks like it's not possible to have float-like objects
(calculation/formula-wise) that are mutable?! and it also looks like
the price to pay for the mutability is to have to write "heavier"
versions of any formula that uses these "special floats" (that carry
an uncertainty): "x[0]+y[0]*sin(...)", "x()+y()", "float(x)+float
(y)",... which, by the way, essentially prevents any float-like
object from being used as a float in formulas that you don't write
yourself.

This does not look good. Python is failing me!!! :/ I heard that
this would be easy to do in Ruby (not confirmed, though)...

More ideas and thoughts would still be most welcome!

It looks like what is needed here are a kind of "mutable float". Is
there a simple way of creating such a type? I don't mind changing the
value through x.value =3 instead of x = 1.23... :)

On Apr 14, 3:03 pm, (e-mail address removed) wrote:

Hello,

Is there a way to easily build an object that behaves exactly like a
float, but whose value can be changed? The goal is to maintain a list
[x, y,…] of these float-like objects, and to modify their value on the
fly (with something like x.value =4) so that any expression like "x
+y" uses the new value.

I thought of two solutions, both of which I can't make to work:

1) Use a class that inherits from float. This takes care of the
"behave like float" part. But is it possible to change the value of
the float associated with an instance? That is, is it possible to
do: "x =loat(1.23); x.change_value(3.14)" so that x's float value
becomes 3.14?

2) The other possibility I thought of was: use a class that defines a
'value' member (x.value). This takes care of the "value can be
changed" part. But is it possible/easy to make it fully behave like a
float (including when passed to functions like math.sin)?

Alternatively, I'd be happy with a way of handling numerical
uncertainties in Python calculations (such as in "calculate the value
and uncertainty of a*sin(b) knowing that a=+/- 0.1 and b=1.00 +/-
0.01").

Any idea would be much appreciated!
The answer to your original question is no. If the value can be changed, then it doesn't behave like a float. And that's not just a pedantic answer, it's a serious consideration.

You have to decide what characteristics of a float you need to mimic, and which ones you don't care about, and which ones you want to change. Only after having a pretty good handle on those answers can you pick a "best" implementation.

Let's call this new type a nfloat, and let's assume you have a function that returns one. That might be a constructor, but it may not, so we're keeping our options open.
myval =ewfunction(42.0)

What do you want to happen when you execute b =yval ? Presumably
you want them to be "equal" but in what sense? Suppose you then change
one of them with your suggested attribute/method.
myval.value =ewfunction("aaa")

is b the same as it was (like a float would be), or is b also changed?

Do you need lots of functions to work on one of these nfloats, or could
you use them as follows:
sin( b.value )

Instead of using .value to change the underlying float, how about if you
use [0] ? Just use a list of size 1.
OK, your other recent message clarified for me some of what you're
after. Seems to me you're going to have a specific list of values, which
you want to be able to individually tweak each time you do the
calculations. And you want to have a name for each of those values, so
that the formulas look pretty straightforward.

I'm not convinced this is the best approach for uncertainty
calculations, but if those numbers do form a fairly easily specified
list (and one that's not dynamic), what you probably want is an object
that's a reference to a list item, while the list item is itself a
float. And you want the object to support many of the usual floating
point operations. So why not define a single static list (could be a
class object), and define a class whose instances contain an index into
that list. The class could have methods __add__() and __mul__() etc. And
it could have one more method for storing to the list.


class IndirectFloat(object):
liss = []
def __init__(self, value=0.0):
self.index = len(self.liss)
self.liss.append(value)

def modify(self, newvalue):
self.liss[self.index]= newvalue

def __add__(self, val): #handle IndirectFloat + float
return self.liss[self.index] + float(val)

__radd__ = __add__ #handle float + IndirectFloat

def __float__(self): #just in case someone wants to explicitly convert
return self.liss[self.index]

x = IndirectFloat(12.0)
y = IndirectFloat(20.0)
print x + 13.0
print x + y
print 3.0 + x
x.modify(15.0)
print x + 13.0

Notice that if you ever do things like z = y, you'll be using the *same*
object, and modifying one will also modify the other.
Now, in addition to __add__ and __radd__, you want __mul__ and __rmul__,
and many others, presumably. Notice that for the non-commutative
methods, you can't just use the same method for both, the way we do for
add and multiply.

I still think an error-propagation class would be better.
Something like:
class ErrorPropFloat(object):
def __init__(self, value=0.0, err=0.0):
self.value = value
self.err = err

def __add__(self, val):
res = self.value + float(val)
if type(val) == type(0.0):
err = self.err
else:
err = self.err + val.err
return ErrorPropFloat(res, err)

__radd__ = __add__

def __float__(self): #just in case someone wants to explicitly convert
return self.value
def __repr__(self):
return "ErrorProp(%g, %g)" % (self.value, self.err)
#return "ErrorProp(" + self.value + "," + self.err + ")"

x = ErrorPropFloat(12.0, 0.1)
y = ErrorPropFloat(20.0, 0.2)
print x, y
print x + 13.0
print x + y
print 3.0 + x
 
P

Piet van Oostrum

(e-mail address removed) (ELB) wrote:

[snip]
ELB> A couple of ideas I had:
ELB> 1) Define a FloatWithUncert object, but get instance values as x(), as
ELB> in "x()+y()". The code is relatively legible. 'x' is mutable. But
ELB> formulas don't look so good, and you can't drop a float replacement
ELB> for 'x', as floats are not callable.
ELB> 2) Write all expressions that could contain FloatWithUncert objects
ELB> with a 'float()' wrapper ("float(x)+float(y)"), after defining the
ELB> FloatWithUncert.__float__() method. FloatWithUncert would be
ELB> mutable. The code is a little bit heavy, but it is explicit. 'x'
ELB> could be a pure float.

Would this be what you want?

class Float(object):
def __init__(self, value, uncert=0.0):
self.value = value
self.uncert = uncert

def __float__(self):
return self.value

def __str__(self):
return str(self.value)

def __add__(self, other):
return self.value + other

__radd__ = __add__

# etc for all other arithmetic and logical operators (but this can be
# automated, see the thread "Automatically generating arithmetic
# operations for a subclass")

If you write your own functions they might have to coerce your Float
objects to real floats ocassionally by using float(param) instead of
param.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,291
Messages
2,571,493
Members
48,160
Latest member
KieranKisc

Latest Threads

Top