openmath / py-openmath Goto Github PK
View Code? Open in Web Editor NEWAn OpenMath 2.0 implementation in Python
License: MIT License
An OpenMath 2.0 implementation in Python
License: MIT License
I tried the example at the bottom of page https://github.com/OpenMath/py-openmath: I tried to copy and paste each line, but it didn't work for me:
Finally, this class contains a mechanism for registering converters.
$ python3
Python 3.8.2 (default, Mar 13 2020, 10:14:16)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from fractions import Fraction
>>> from openmath import openmath as om
>>> from openmath.convert import DefaultConverter as converter
>>> def to_om_rat(obj):
... return om.OMApplication(om.OMSymbol('rational', cd='nums1'),
... list(map(converter.to_openmath, [obj.numerator, obj.denominator])))
...
>>> def to_py_rat(obj):
... return Fraction(converter.to_python(obj.arguments[0]), converter.to_python(obj.arguments[1]))
...
>>> converter.register(Fraction, to_om_rat, 'nums1', 'rational', to_py_rat)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'BasicPythonConverter' object has no attribute 'register'
>>>
The empty set is converted from Python to OpenMath as
<OMS cdbase="http://www.openmath.org/cd" name="emptyset" cd="set1"/>
which is correct but not the best choice. It would be better to convert it as
<OMA><OMS cdbase=\"http://www.openmath.org/cd\" cd=\"set1\" name=\"set\"/></OMA>
it such way, the empty set is handled as a set and not as a special case.
About this, please consider what is said in
http://www.catb.org/~esr/writings/taoup/html/ch01s06.html , which is
especially relevant for OpenMath, which is intended to be used by
computers:
For robustness, designing in tolerance for unusual or extremely bulky
inputs is also important. Bearing in mind the Rule of Composition helps;
input generated by other programs is notorious for stress-testing software
(e.g., the original Unix C compiler
reportedly needed small upgrades to cope well with Yacc output). The forms
involved often seem useless to humans. For example, accepting empty
lists/strings/etc., even in places where a human would seldom or never
supply an empty string, avoids having to
special-case such situations when generating the input mechanically.
-- Henry Spencer
One very important tactic for being robust under odd inputs is to avoid
having special cases in your code. Bugs often lurk in the code for
handling special cases, and in the interactions among parts of the code
intended to handle different special cases.
My attention was drawn today to a variation of this behaviour:
In [15]: import openmath.openmath as om
In [16]: a = om.OMObject(1, 2)
In [17]: b = om.OMObject(1, '2')
In [18]: a == b
Out[18]: False
In [19]: a
Out[19]: OMObject(1, version=2, id=None, cdbase=None)
In [20]: b
Out[20]: OMObject(1, version='2', id=None, cdbase=None)
In [21]: a.version
Out[21]: '2'
In [22]: b.version
Out[22]: '2'
which shows that we're not using CaseClass
the way it is supposed to (we should not modify parameters in __init__
, that is).
It is unfortunate that Python has no decent way of implementing structs with inheritance (I won't go as far as calling them algebraic datatypes), but I think we should stick to something simpler and more pythonic.
I'm working on a few-lines-solution (ab)using named tuples, I'll link it shortly. That would also have the benefit of eliminating one dependency.
I'd be interested in hearing your opinion, @tkw1536.
It would be good to have a better README for a release (see #5). The py-scscp
package sets a good standard to strive for.
The functions in convert do not cover OMBIND and OMV, which will be needed eventually.
This seems to be a low-priority issue for now, but I'm adding for future reference.
The convert methods maintains global state, which is awkward.
The code should be wrapped into a class that encapsulates the state.
The binary encoding is like the XML encoding for OpenMath but is much much more space efficient.
The treatment of the OpenMath literals (integer, float, string, byte array) is currently hard-coded in the convert methods.
The current treatment is a good defualt, but it should be possible to customize it.
One option, considering issue #12, is to simply use methods for this that can be overridden by other classes.
When making a PR I noticed that tests for older python versions are broken. In particular in Python2 the following test fails:
File "/home/travis/build/OpenMath/py-openmath/openmath/convert_pickle.py", line 14, in openmath.convert_pickle
Failed example:
to_openmath('coucou')
Expected:
OMString(string='coucou', id=None)
Got:
OMBytes(bytes='coucou', id=None)
(see https://travis-ci.org/github/OpenMath/py-openmath/jobs/689618027#L207
Furthermore the Python 3.3 and Python 3.4 tests are failing because the python
binaries can not be installed on Travis anymore.
We should consider if we want to keep supporting or testing these old versions of Python, in particular as all of them have reached end of life.
Currently one can register a callback for converting to Python an OpenMath symbol, based on cd and name.
A more general mechanism would be to support registering callbacks based on:
Taking the cdbase into account is required anyway by the OpenMath standard.
The others are practical in situations where all symbols in a given context (cd, cdbase) are handled identically, typically by loading the eponymous global Python object / functions.
Practical use case: in the pickle-based serialization, Florian recommends using a plain OMS symbol to represent a global Python objects; something like:
<OMS cdbase=python cd=sagemath name=sage.foo.bar.baz/>
In that case, having to register all symbols would be unpractical.
>>> converter.to_python( decoder.decode_bytes( b"<OMA><OMS cdbase=\"http://www.openmath.org/cd\" cd=\"interval1\" name=\"integer_interval\"/><OMI>1</OMI><OMI>4</OMI></OMA>", snippet=True ) )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 146, in to_python
elem = self.to_python(omobj.elem)
File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 143, in to_python
return self._lookup_to_python(omobj.cdbase, omobj.cd, omobj.name)
File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 133, in _lookup_to_python
raise ValueError("no entry found")
ValueError: no entry found
>>>
This should be converted to Python as range(1,5)
OpenMath integer_interval
is already supported by the OpenMath implementations of Gap, Macaulay2, Ruby, Yacas, and range
in the standard library of Python without importing anything
The expected output is in both cases the empty string ''
$ python3
Python 3.8.2 (default, Apr 27 2020, 15:53:34)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from openmath import encoder, decoder, openmath as om
>>> from openmath.convert import DefaultConverter as converter
>>> converter.to_python( decoder.decode_bytes( b"<OMSTR></OMSTR>", snippet=True ) )
>>> converter.to_python( decoder.decode_bytes( b"<OMSTR/>", snippet=True ) )
>>>
I can not get the tests for OMBytes to pass, it seems that the encoding to / from base64 is a bit weird across python versions.
@defeo Can you try and figure this out?
We should really announce the availability of this via the OpenMath (Tom?) and and ODK (Luca?) channels (once it is sufficiently ready and tested).
Do good and talk about it.
For this we need
The OpenMath standard requires the OMOBJ tag, and hence, when converting from OpenMath to Python, py-openmath should accept also OpenMath objects with that tag, even if that tag is not generated when converting in the opposite direction.
Implementing the OMOBJ tag is easy, just take the child of the OMOBJ node, and call again converter.to_python applied to it.
>>> converter.to_python( decoder.decode_bytes( b'<OMOBJ xmlns="http://www.openmath.org/OpenMath" version="2.0" cdbase="http://www.openmath.org/cd"><OMI>3</OMI></OMOBJ>', snippet=True ) )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 149, in to_python
raise ValueError('Cannot convert object of class %s to Python.' % omobj.__class__.__name__)
ValueError: Cannot convert object of class OMObject to Python.
>>>
the XML standard requires that the floats are without the + in the exponent, see https://docstore.mik.ua/orelly/xml/schema/ch04_04.htm
Hence 10.0**20 should be converted as <OMF dec="1e20"/>
, not as <OMF dec="1e+20"/>
>>> encoder.encode_bytes(converter.to_openmath([10.0**20]))
b'<OMA xmlns="http://www.openmath.org/OpenMath"><OMS cdbase="http://www.openmath.org/cd" name="list" cd="list1"/><OMF dec="1e+20"/></OMA>'
>>>
This output in fact doesn't validate, even if the OMOBJ tag is added, see
https://www.openmath.org/validation/omvalidate.html
To validate OpenMath, it can be used also the online validator
https://www.liquid-technologies.com/online-relaxng-validator
with the grammar copied from
https://www.openmath.org/standard/om20-2019-07-01/omstd20.html#app_openmath.rng
As of MathML 3 OpenMath and Content MathML are equivalent.
/cc @kohlhase
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.