Is it possible to round reals inside a symbolic expression?
Example,
sage: x = var('x')
sage: r = 0.1*0.1 - 0.01
sage: sr = 0.1*0.1*x - 0.01*x
sage: r
1.73472347597681e-18
sage: sr
(1.73472347597681e-18)*x
sage: round(r,10)
0.0
is OK, but
sage: round(sr,10)
doesn't output 0.0 but raises an error instead (and I understand why, as the
expression evaluation really depends on the value of x).
But, is there any way of round reals even if they are inside a symbolic
expression?
Thanks,
Cristóvão Sousa
On Mon, 25 Oct 2010 00:41:07 -0700 (PDT)
Simon King <simon...@nuigalway.ie> wrote:
> @symbolic experts (Burcin et al):
> Is it really necessary that x.operator() returns None and x.operands()
> returns []? What about an identity operator?
The operator and operands don't have a meaning if you have a single
variable. I agree that the current behavior is confusing:
sage: x.operands()
[]
sage: x.operator() is None
True
I suggest we raise a ValueError when there is no operator or operands.
This is already done for iterators of symbolic expressions in #7537:
http://trac.sagemath.org/sage_trac/ticket/7537
Can you open a ticket to do the same for operands() and operator()?
> Is it really necessary to break s.operands() into smaller pieces in
> order to reconstruct a sum? Why can' op_add accept an argument list of
> arbitrary length, in particular since the list of operands of a sum
> can be longer than two?
You are right, for add and mul we should return a function that can
handle multiple arguments. I am not sure if the top level sum() and
prod() functions would be suitable here though.
Can you open a ticket for this as well?
Thank you.
Burcin
On Mon, 25 Oct 2010 05:09:06 -0700 (PDT)
Simon King <simon...@uni-jena.de> wrote:
> I only opened one ticket, namely #10169, aiming at making
> s==s.operator()(*s.operands()) work uniformely.
I don't think this makes sense for variables, numeric objects, or
constants, in other words, objects for which .operator() returns None
at the moment.
If we return an identity operator for these cases, how do you plan to
test for it in your code:
sage: def symround(x, ndigits=0):
....: if hasattr(x,'operator') and x.operator():
....: return x.operator()(*map(lambda
y:symround(y,ndigits=ndigits), x.operands()))
....: try:
....: return round(x,ndigits=ndigits)
....: except TypeError:
....: return x
....:
Isn't it simpler (and faster) to check for None?
Cheers,
Burcin
This initializes a list with a single element for objects which return
None for operator() now. IMHO, this approach is inefficient. In this
case, you should act on the object directly.
In any case, we should wrap the following ginac interfaces to provide a
better way of doing this:
* A way to apply a function to the operands of an expression:
http://www.ginac.de/tutorial/Applying-a-function-on-subexpressions.html
* or tree traversal:
http://www.ginac.de/tutorial/Visitors-and-tree-traversal.html
Cheers,
Burcin
I propose a generic function mapexpression in order operate in the tree
of the expression.
You can use it over leaf (ie the numbers or the variables) or over
functions (by the fctfct parameter)
I like this function because we can use this same function for numerical
transforms (for Christavo)
and rewrite rules (with trigonometric rules).
There are 2 fuzzy cases for operator add and mul because the
fct(*operand) doesn't work for add and mul.
import operator
def mapexpression (expr, fctleaf, fctfct, param, level, addDepth=0,
mulDepth=0) :
def mapex (expr, depth) : # a very local function
opor = expr.operator()
opands = expr.operands()
if (opor == None) :
return fctleaf(expr,param) # a leaf in the expression tree
if (opor == operator.add) : # recursive call thru sum
opands = map (lambda ex : mapex (ex, depth+addDepth), opands)
return add (opands)
if (opor == operator.mul) : # recursive call thru mul
opands = map (lambda ex : mapex (ex, depth+mulDepth), opands)
return mul (opands)
if (level == -1) or (level[-1] >= depth) : # recursive call over
operands
opands = map (lambda ex : mapex (ex, depth+1), opands)
if level == -1 or depth in level : # root of the subtree must be
changed
return fctfct (opor, opands, param)
return opor (*opands) # opands may or maynot be changed by a
recursive call
return mapex (expr, 0)
def nn (ex, p) :
if ex._is_numeric() or ex==pi: return ex.n(prec=p)
else : return ex
sage: mapexpression (sin(5*pi/7)+exp(i*pi/13),nn, lambda x,y,z:x(*y),20,-1)
1.7528 + 0.23932*I
Method __.n() doesn't work over partial numerical formula, but this
mapexpression allows this.
Francois