Ask Your Question
1

Numerical approximation of symbolic equation

asked 2010-12-30 18:51:37 +0100

lxman gravatar image

updated 2011-01-03 21:14:17 +0100

kcrisman gravatar image

What I would like to do is the following:

sage: var('theta')
theta
sage: theta=25*units.angles.degree
sage: print theta
25*degree
sage: a=sin(theta)
sage: print a
sin(25*degree)

At this point, I type 'a.' and tab and in the popup list of functions I find numerical_approx. So I type in:

sage: a.numerical_approx()
Traceback (click to the left of this block for traceback)
...
TypeError: cannot evaluate symbolic expression numerically

Okay, it would appear that adding the units to theta turns it into a symbolic variable which turns my expression a into a symbolic expression. But what I would like to do is enter my angle theta in either degrees or radians and get a numerical approximation of the answer based on the units of the input. Is there a clean way to do this?

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
3

answered 2010-12-30 23:37:57 +0100

DSM gravatar image

updated 2010-12-30 23:42:17 +0100

In the show-your-work spirit, here was my line of thought. First, I thought that maybe all that was missing was adding a .n method to degree, to get degree to pretend as if it were pi/180, but that didn't work like I was hoping. Then I realized that this was silly: pi already behaves the way I want it to, I just want to define a new pi-like constant with name "degree" and value "pi/180". So looking at how pi is implemented, it subclasses Constant and then takes the expression from that. So in a similar spirit:


from sage.symbolic.constants import Constant

class ConstantFromExpression(Constant):
    def __init__(self, name, expr):
        conversions = dict(maxima=repr(maxima.coerce(expr)))
        Constant.__init__(self, name,conversions=conversions)
        self._expr = expr
    def __float__(self): return float(self._expr)
    def __complex__(self): return complex(self._expr)
    def _mpfr_(self, R): return R(self._expr)
    def _real_double_(self, R): return R(self._expr)

def NamedExpression(name, expr):
    return ConstantFromExpression(name,expr).expression()

which should allow you to do what you want:


sage: degree = NamedExpression('degree', pi/180)
sage: degree
degree
sage: float(degree)
0.017453292519943292
sage: 
sage: sin(25*degree)
sin(25*degree)
sage: a = sin(25*degree)
sage: a.n()
0.422618261740699
sage: RealField(100)(a)
0.42261826174069943618697848965
sage: 
sage: sin(90*degree)
sin(90*degree)
sage: simplify(sin(90*degree))
1
sage: sin(45*degree)
sin(45*degree)
sage: simplify(sin(45*degree))
1/2*sqrt(2)

There are lots of conversions and features I didn't implement, of course, but I had to do at least the maxima one to get simplify to work correctly. I don't know enough about the maxima coercion repr to trust it entirely -- should probably put some tests in, to make sure the result tests equal to the input. But for this trivial case, it seems to work okay.

Maybe a NamedExpression wrapper would be useful?

edit flag offensive delete link more

Comments

Thank you for all the hard work. This definitely looks promising. I will experiment with it to see how it goes. It seems to me that if this sort of thing was implemented generally it would make sage a *much* more attractive package.

lxman gravatar imagelxman ( 2010-12-31 19:03:50 +0100 )edit

Let me know if there's something you need it to do that it doesn't. And if it works, come back here and accept my answer. :^)

DSM gravatar imageDSM ( 2011-01-02 06:33:27 +0100 )edit

If this works out, presumably all the dimensionless angle units in sage.symbolic.units should be treated this way - hopefully it wouldn't be too hard to do so. DSM, if so, this would be worth raising on sage-devel, since there was a lot of discussion of the best way to implement units there when it happened.

kcrisman gravatar imagekcrisman ( 2011-01-03 21:21:56 +0100 )edit

@kcrisman: ISTM modifying the above to make it a real unit so that sin(5*degree) would work but sin(5*degree**2) didn't would be a bit tough though.

DSM gravatar imageDSM ( 2011-01-04 22:21:34 +0100 )edit

Good point. What do unit packages in general programming languages do in these cases?

kcrisman gravatar imagekcrisman ( 2011-01-05 00:09:55 +0100 )edit
0

answered 2011-10-14 12:05:36 +0100

ADuC812 gravatar image

updated 2011-10-14 13:13:26 +0100

Is there any way to split up a symbolic expression like '25*degree' into units and value? some function like:

sage: t = 25*units.angles.degree;
sage: get_numeric(t)
25.0
sage: t/get_numeric(t)
degree

This will make possible the usage of all functions, designed for numeric arguments, with units of measurement,after some simple redefinition. As the units work like symbolic variables, we can set them to unity to get a numerical value:

sage: float(t(units.angles.degree=1))
25.0

For that, one has to know the units involved. it can be achieved by arguments() function:

sage: t.arguments() 
(degree,)

Putting all together:

def get_numeric(t)
    dic={};
    for arg in t.arguments():
        dic[arg]=1;
    return (float(t(dic)));

Don't know about the performance of such method.

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

Stats

Asked: 2010-12-30 18:51:37 +0100

Seen: 4,397 times

Last updated: Oct 14 '11