Modifying the value of a float-like object

Eric.Le.Bigot at spectro.jussieu.fr Eric.Le.Bigot at spectro.jussieu.fr
Tue Apr 14 15:36:02 EDT 2009


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!



More information about the Python-list mailing list