ASKSAGE: Sage Q&A Forum - Individual question feedhttp://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Mon, 09 Mar 2015 11:43:33 -0500units testshttp://ask.sagemath.org/question/10218/units-tests/I just stumbled over a problem again that I reported years ago in sage-devel, but perhaps someone here can help.
I am still after the quick and dirty way for using the existing units package in sage to test symbolic equations for consistent units. This is currently not possible because units are treated as conventional variables, meaning that:
`units.x.y - units.x.y`
> 0
The only thing that really stops me right now is that I don't know how to get it to
return:
`units.x.y + units.x.y`
> units.x.y
`units.x.y - units.x.y`
> units.x.y
Is there an easy way to write a function or create a subclass that would do that while keeping the rest (multiplication, division, exponents etc.) the way it
is?
UPDATE:
A modification of the first answer by tmonteil does part of the job:
class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
Now this works:
`type(meter*2)`
>class '__main__.MYExp'
But this does not:
`type(2*meter)`
>type 'sage.symbolic.expression.Expression'
Similar for division. Is there a way to somehow modify the above to make any expressions involving MYExp return a MYExp, rather than just those expressions that start with MYExp? Tue, 11 Jun 2013 03:28:55 -0500http://ask.sagemath.org/question/10218/units-tests/Comment by stan for <p>I just stumbled over a problem again that I reported years ago in sage-devel, but perhaps someone here can help.
I am still after the quick and dirty way for using the existing units package in sage to test symbolic equations for consistent units. This is currently not possible because units are treated as conventional variables, meaning that:</p>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>0</p>
</blockquote>
<p>The only thing that really stops me right now is that I don't know how to get it to
return:</p>
<p><code>units.x.y + units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p>Is there an easy way to write a function or create a subclass that would do that while keeping the rest (multiplication, division, exponents etc.) the way it
is?</p>
<p>UPDATE:
A modification of the first answer by tmonteil does part of the job:</p>
<pre><code>class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
</code></pre>
<p>Now this works:</p>
<p><code>type(meter*2)</code></p>
<blockquote>
<p>class '__main__.MYExp'</p>
</blockquote>
<p>But this does not:</p>
<p><code>type(2*meter)</code></p>
<blockquote>
<p>type 'sage.symbolic.expression.Expression'</p>
</blockquote>
<p>Similar for division. Is there a way to somehow modify the above to make any expressions involving MYExp return a MYExp, rather than just those expressions that start with MYExp? </p>
http://ask.sagemath.org/question/10218/units-tests/?comment=26096#post-id-26096Adding reverse multiplication and division did the trick (see my proposed solution below). Defining coercions seems outside my area of comfort.Mon, 09 Mar 2015 11:43:33 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=26096#post-id-26096Comment by tmonteil for <p>I just stumbled over a problem again that I reported years ago in sage-devel, but perhaps someone here can help.
I am still after the quick and dirty way for using the existing units package in sage to test symbolic equations for consistent units. This is currently not possible because units are treated as conventional variables, meaning that:</p>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>0</p>
</blockquote>
<p>The only thing that really stops me right now is that I don't know how to get it to
return:</p>
<p><code>units.x.y + units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p>Is there an easy way to write a function or create a subclass that would do that while keeping the rest (multiplication, division, exponents etc.) the way it
is?</p>
<p>UPDATE:
A modification of the first answer by tmonteil does part of the job:</p>
<pre><code>class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
</code></pre>
<p>Now this works:</p>
<p><code>type(meter*2)</code></p>
<blockquote>
<p>class '__main__.MYExp'</p>
</blockquote>
<p>But this does not:</p>
<p><code>type(2*meter)</code></p>
<blockquote>
<p>type 'sage.symbolic.expression.Expression'</p>
</blockquote>
<p>Similar for division. Is there a way to somehow modify the above to make any expressions involving MYExp return a MYExp, rather than just those expressions that start with MYExp? </p>
http://ask.sagemath.org/question/10218/units-tests/?comment=26095#post-id-26095This was explained at the end of my answer : if you want `2*meter` lead to a `MYExp` expression, you have to define a coercion.Mon, 09 Mar 2015 10:37:54 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=26095#post-id-26095Answer by tmonteil for <p>I just stumbled over a problem again that I reported years ago in sage-devel, but perhaps someone here can help.
I am still after the quick and dirty way for using the existing units package in sage to test symbolic equations for consistent units. This is currently not possible because units are treated as conventional variables, meaning that:</p>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>0</p>
</blockquote>
<p>The only thing that really stops me right now is that I don't know how to get it to
return:</p>
<p><code>units.x.y + units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p>Is there an easy way to write a function or create a subclass that would do that while keeping the rest (multiplication, division, exponents etc.) the way it
is?</p>
<p>UPDATE:
A modification of the first answer by tmonteil does part of the job:</p>
<pre><code>class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
</code></pre>
<p>Now this works:</p>
<p><code>type(meter*2)</code></p>
<blockquote>
<p>class '__main__.MYExp'</p>
</blockquote>
<p>But this does not:</p>
<p><code>type(2*meter)</code></p>
<blockquote>
<p>type 'sage.symbolic.expression.Expression'</p>
</blockquote>
<p>Similar for division. Is there a way to somehow modify the above to make any expressions involving MYExp return a MYExp, rather than just those expressions that start with MYExp? </p>
http://ask.sagemath.org/question/10218/units-tests/?answer=15058#post-id-15058You can define a class MYExp, that inherits from symbolic expressions (so that you keep all other operations), but owerwrites substraction and addition to avoid cancellations:
class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
return self.__add__(other)
def __add__(self,other):
if self == other:
return self
else:
return MYExp(SR,super(MYExp, self).__add__(other))
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
U = lambda x: MYExp(SR,x)
watt = U(units.power.watt)
meter = U(units.length.meter)
newton = U(units.force.newton)
second = U(units.time.second)
joule = U(units.energy.joule)
Then, you can do something like:
sage: watt-watt
watt
sage: watt+watt
watt
sage: (watt-watt)*(newton+meter) - (watt-watt)*(newton+meter)
(meter + newton)*watt
But use with caution. You wil have to adapt if you want to use some other operation in your computation:
sage: sqrt(watt) - sqrt(watt)
0
sage: type(sqrt(watt))
<type 'sage.symbolic.expression.Expression'>
sage: watt^2 - watt^2 # __pow__ method is called, not the product by itsef
0
sage: watt*watt - watt*watt
watt^2
Also, some "external" operations use coercion, that should be defined as well:
sage: 2*watt-2*watt
0
sage: watt*2-watt*2
2*watt
sage: type(watt*2)
<class 'sage.all_cmdline.MYExp'>
sage: type(2*watt)
<type 'sage.symbolic.expression.Expression'>
If you want also to deal with such external products, you will have to define a class `MYSR` at the same level as `SR` (`Symbolic Ring`), and define the `.parent()` method of an element of `MYExp` to be `MYSR`, and define the coercion in `MYSR`. See those pages if you want to deal with such external products :
- [Parents, Conversion and Coercion](http://www.sagemath.org/doc/tutorial/tour_coercion.html)
- [Coercion](http://www.sagemath.org/doc/reference/coercion/)
- [The Coercion Model](http://www.sagemath.org/doc/reference/coercion/sage/structure/coerce.html)
Tue, 11 Jun 2013 09:45:24 -0500http://ask.sagemath.org/question/10218/units-tests/?answer=15058#post-id-15058Comment by stan for <p>You can define a class MYExp, that inherits from symbolic expressions (so that you keep all other operations), but owerwrites substraction and addition to avoid cancellations:</p>
<pre><code>class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
return self.__add__(other)
def __add__(self,other):
if self == other:
return self
else:
return MYExp(SR,super(MYExp, self).__add__(other))
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
U = lambda x: MYExp(SR,x)
watt = U(units.power.watt)
meter = U(units.length.meter)
newton = U(units.force.newton)
second = U(units.time.second)
joule = U(units.energy.joule)
</code></pre>
<p>Then, you can do something like:</p>
<pre><code>sage: watt-watt
watt
sage: watt+watt
watt
sage: (watt-watt)*(newton+meter) - (watt-watt)*(newton+meter)
(meter + newton)*watt
</code></pre>
<p>But use with caution. You wil have to adapt if you want to use some other operation in your computation:</p>
<pre><code>sage: sqrt(watt) - sqrt(watt)
0
sage: type(sqrt(watt))
<type 'sage.symbolic.expression.Expression'>
sage: watt^2 - watt^2 # __pow__ method is called, not the product by itsef
0
sage: watt*watt - watt*watt
watt^2
</code></pre>
<p>Also, some "external" operations use coercion, that should be defined as well:</p>
<pre><code>sage: 2*watt-2*watt
0
sage: watt*2-watt*2
2*watt
sage: type(watt*2)
<class 'sage.all_cmdline.MYExp'>
sage: type(2*watt)
<type 'sage.symbolic.expression.Expression'>
</code></pre>
<p>If you want also to deal with such external products, you will have to define a class <code>MYSR</code> at the same level as <code>SR</code> (<code>Symbolic Ring</code>), and define the <code>.parent()</code> method of an element of <code>MYExp</code> to be <code>MYSR</code>, and define the coercion in <code>MYSR</code>. See those pages if you want to deal with such external products : </p>
<ul>
<li><a href="http://www.sagemath.org/doc/tutorial/tour_coercion.html">Parents, Conversion and Coercion</a></li>
<li><a href="http://www.sagemath.org/doc/reference/coercion/">Coercion</a></li>
<li><a href="http://www.sagemath.org/doc/reference/coercion/sage/structure/coerce.html">The Coercion Model</a></li>
</ul>
http://ask.sagemath.org/question/10218/units-tests/?comment=17521#post-id-17521This is awesome, thanks!! Now the way I would like to use it is to save the units of all my symbolic variables in a dictionary (e.g. udict) and substitute them in a given equation. Unfortunately, (var1 - var2).subs(udict) still gives 0. However, if I do udict[var1] - udict[var2], I get the desired units as in your example. Any ideas?
UPDATE:
Apparently, expression.subs(somethingelse), even if all elements of expression are substituted by a different type, always stays an expression.Tue, 11 Jun 2013 21:48:16 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=17521#post-id-17521Answer by tmonteil for <p>I just stumbled over a problem again that I reported years ago in sage-devel, but perhaps someone here can help.
I am still after the quick and dirty way for using the existing units package in sage to test symbolic equations for consistent units. This is currently not possible because units are treated as conventional variables, meaning that:</p>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>0</p>
</blockquote>
<p>The only thing that really stops me right now is that I don't know how to get it to
return:</p>
<p><code>units.x.y + units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p>Is there an easy way to write a function or create a subclass that would do that while keeping the rest (multiplication, division, exponents etc.) the way it
is?</p>
<p>UPDATE:
A modification of the first answer by tmonteil does part of the job:</p>
<pre><code>class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
</code></pre>
<p>Now this works:</p>
<p><code>type(meter*2)</code></p>
<blockquote>
<p>class '__main__.MYExp'</p>
</blockquote>
<p>But this does not:</p>
<p><code>type(2*meter)</code></p>
<blockquote>
<p>type 'sage.symbolic.expression.Expression'</p>
</blockquote>
<p>Similar for division. Is there a way to somehow modify the above to make any expressions involving MYExp return a MYExp, rather than just those expressions that start with MYExp? </p>
http://ask.sagemath.org/question/10218/units-tests/?answer=15059#post-id-15059Now, another possibe point of view (perhaps more pedagogical) could be not to allow adding things with incompatible units (you can use the `convert()` function to test that: this function transforms your units in the international system standard). For this, you have to modify the `.__add__()` method in the class i defined above.
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Physics do not like such additions')
sage: (joule + second*watt)*newton
joule*newton
sage: joule-joule
joule
sage: joule - second
TypeError: Physics do not like such additions
If you also define `.__pow__()` method as of above (imitate the product), i guess you have a way to test wether an expression makes sense, and in which units wil be the result.
Tue, 11 Jun 2013 11:04:42 -0500http://ask.sagemath.org/question/10218/units-tests/?answer=15059#post-id-15059Comment by tmonteil for <p>Now, another possibe point of view (perhaps more pedagogical) could be not to allow adding things with incompatible units (you can use the <code>convert()</code> function to test that: this function transforms your units in the international system standard). For this, you have to modify the <code>.__add__()</code> method in the class i defined above.</p>
<pre><code>def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Physics do not like such additions')
sage: (joule + second*watt)*newton
joule*newton
sage: joule-joule
joule
sage: joule - second
TypeError: Physics do not like such additions
</code></pre>
<p>If you also define <code>.__pow__()</code> method as of above (imitate the product), i guess you have a way to test wether an expression makes sense, and in which units wil be the result.</p>
http://ask.sagemath.org/question/10218/units-tests/?comment=17495#post-id-17495Concerning your second comment, see the explanation on the previous answer, this is because the `.sqrt()` method is inherited from Symbolic Expression.
Concerning your first comment, if we want to have this included in Sage, this will require much more work (for example, we will have to teach Sage that cos(x) is defined only if x has no physical dimension, define `.sqrt()` method as above, and so on until the module can eat most of the symbolic expressions, also we will have to write all the related documentation).
Do you feel you could work on this ? We can do it together if needed, so we can first work on a common file until we get something good, and then transform it into a patch. Drop me an email if you are interested, and i will open a ticket !
Sun, 16 Jun 2013 10:37:29 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=17495#post-id-17495Comment by stan for <p>Now, another possibe point of view (perhaps more pedagogical) could be not to allow adding things with incompatible units (you can use the <code>convert()</code> function to test that: this function transforms your units in the international system standard). For this, you have to modify the <code>.__add__()</code> method in the class i defined above.</p>
<pre><code>def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Physics do not like such additions')
sage: (joule + second*watt)*newton
joule*newton
sage: joule-joule
joule
sage: joule - second
TypeError: Physics do not like such additions
</code></pre>
<p>If you also define <code>.__pow__()</code> method as of above (imitate the product), i guess you have a way to test wether an expression makes sense, and in which units wil be the result.</p>
http://ask.sagemath.org/question/10218/units-tests/?comment=17517#post-id-17517Works perfectly with the .__pow__() method, but what should I do with sqrt()? Example: joule^(1/2) - joule^(1/2) gives sqrt(joule), but sqrt(joule) - sqrt(joule) gives 0.Wed, 12 Jun 2013 04:49:57 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=17517#post-id-17517Comment by stan for <p>Now, another possibe point of view (perhaps more pedagogical) could be not to allow adding things with incompatible units (you can use the <code>convert()</code> function to test that: this function transforms your units in the international system standard). For this, you have to modify the <code>.__add__()</code> method in the class i defined above.</p>
<pre><code>def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Physics do not like such additions')
sage: (joule + second*watt)*newton
joule*newton
sage: joule-joule
joule
sage: joule - second
TypeError: Physics do not like such additions
</code></pre>
<p>If you also define <code>.__pow__()</code> method as of above (imitate the product), i guess you have a way to test wether an expression makes sense, and in which units wil be the result.</p>
http://ask.sagemath.org/question/10218/units-tests/?comment=17476#post-id-17476An alternative would be to just write a function that dissects an equation into powers, logs, numerators, denominators, terms, checks each term separately and puts it back together. How can I contact you by email? Wed, 19 Jun 2013 00:43:16 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=17476#post-id-17476Comment by stan for <p>Now, another possibe point of view (perhaps more pedagogical) could be not to allow adding things with incompatible units (you can use the <code>convert()</code> function to test that: this function transforms your units in the international system standard). For this, you have to modify the <code>.__add__()</code> method in the class i defined above.</p>
<pre><code>def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Physics do not like such additions')
sage: (joule + second*watt)*newton
joule*newton
sage: joule-joule
joule
sage: joule - second
TypeError: Physics do not like such additions
</code></pre>
<p>If you also define <code>.__pow__()</code> method as of above (imitate the product), i guess you have a way to test wether an expression makes sense, and in which units wil be the result.</p>
http://ask.sagemath.org/question/10218/units-tests/?comment=17520#post-id-17520This is exactly what I want to do, and believe me, it is not just pedagogical, but you'd be surprised how many equations in the scientific literature fail this test, only that it is often less obvious than this. Would be good to add something like this to the units package in sage.Tue, 11 Jun 2013 22:13:09 -0500http://ask.sagemath.org/question/10218/units-tests/?comment=17520#post-id-17520Answer by stan for <p>I just stumbled over a problem again that I reported years ago in sage-devel, but perhaps someone here can help.
I am still after the quick and dirty way for using the existing units package in sage to test symbolic equations for consistent units. This is currently not possible because units are treated as conventional variables, meaning that:</p>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>0</p>
</blockquote>
<p>The only thing that really stops me right now is that I don't know how to get it to
return:</p>
<p><code>units.x.y + units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p><code>units.x.y - units.x.y</code></p>
<blockquote>
<p>units.x.y</p>
</blockquote>
<p>Is there an easy way to write a function or create a subclass that would do that while keeping the rest (multiplication, division, exponents etc.) the way it
is?</p>
<p>UPDATE:
A modification of the first answer by tmonteil does part of the job:</p>
<pre><code>class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
</code></pre>
<p>Now this works:</p>
<p><code>type(meter*2)</code></p>
<blockquote>
<p>class '__main__.MYExp'</p>
</blockquote>
<p>But this does not:</p>
<p><code>type(2*meter)</code></p>
<blockquote>
<p>type 'sage.symbolic.expression.Expression'</p>
</blockquote>
<p>Similar for division. Is there a way to somehow modify the above to make any expressions involving MYExp return a MYExp, rather than just those expressions that start with MYExp? </p>
http://ask.sagemath.org/question/10218/units-tests/?answer=26093#post-id-26093A small edit to tmonteil's first answer allows handling multiplications and divisions in the above framework. Need to define reverse multiplication and division (http://www.rafekettler.com/magicmethods.pdf):
class MYExp(sage.symbolic.expression.Expression):
def __sub__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Subtraction of non-matching units')
def __add__(self,other):
if self.convert() == other.convert():
return self
else:
raise TypeError('Sum of non-matching units')
def __mul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __rmul__(self,other):
return MYExp(SR, super(MYExp, self).__mul__(other))
def __div__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __rdiv__(self,other):
return MYExp(SR, super(MYExp, self).__div__(other))
def __pow__(self,other):
return MYExp(SR, super(MYExp, self).__pow__(other))
U = lambda x: MYExp(SR,x)
for s in units.length.trait_names():
globals()[s] = U(getattr(units.length,s))
Now we can write:
`meter - meter`
>meter
`1*meter - 1*meter`
>meter
`meter^2 - meter^2`
>meter^2
However, note that external functions can still result in problems, e.g.
`sqrt(meter) - sqrt(meter)`
>0
`sin(meter) - sin(meter)`
>0
Actually, I found a more practical way to automatically check for consistent units. Provided a dictionary containing all variables of eq as keys and each variable multiplied by its units as entries:
def units_check(eq, i0 = 1):
'''
Checks whether all arguments are keys in udict and returns simplified units
If units cancel out on one side while they should not, set i0=2 or something other than 1.
Example:
sage: var('a b c d')
sage: udict = {a: a*units.length.meter^3, b: b*units.length.meter, c: c*units.length.meter, d: d*units.length.meter}
sage: eq = a == b*c*d
sage: units_check(eq)
meter^3 == meter^3
'''
valdict = {}
i = i0
for arg in eq.arguments():
valdict[arg] = i
i = i + 1
udict[arg]
eq_val = eq.subs(valdict)
return (eq.subs(udict).subs(valdict))/eq_valMon, 09 Mar 2015 09:12:50 -0500http://ask.sagemath.org/question/10218/units-tests/?answer=26093#post-id-26093