chore: 添加虚拟环境到仓库
- 添加 backend_service/venv 虚拟环境 - 包含所有Python依赖包 - 注意:虚拟环境约393MB,包含12655个文件
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
"""Used for translating a string into a SymPy expression. """
|
||||
__all__ = ['parse_expr']
|
||||
|
||||
from .sympy_parser import parse_expr
|
||||
@@ -0,0 +1,79 @@
|
||||
"""
|
||||
This module implements the functionality to take any Python expression as a
|
||||
string and fix all numbers and other things before evaluating it,
|
||||
thus
|
||||
|
||||
1/2
|
||||
|
||||
returns
|
||||
|
||||
Integer(1)/Integer(2)
|
||||
|
||||
We use the ast module for this. It is well documented at docs.python.org.
|
||||
|
||||
Some tips to understand how this works: use dump() to get a nice
|
||||
representation of any node. Then write a string of what you want to get,
|
||||
e.g. "Integer(1)", parse it, dump it and you'll see that you need to do
|
||||
"Call(Name('Integer', Load()), [node], [], None, None)". You do not need
|
||||
to bother with lineno and col_offset, just call fix_missing_locations()
|
||||
before returning the node.
|
||||
"""
|
||||
|
||||
from sympy.core.basic import Basic
|
||||
from sympy.core.sympify import SympifyError
|
||||
|
||||
from ast import parse, NodeTransformer, Call, Name, Load, \
|
||||
fix_missing_locations, Constant, Tuple
|
||||
|
||||
class Transform(NodeTransformer):
|
||||
|
||||
def __init__(self, local_dict, global_dict):
|
||||
NodeTransformer.__init__(self)
|
||||
self.local_dict = local_dict
|
||||
self.global_dict = global_dict
|
||||
|
||||
def visit_Constant(self, node):
|
||||
if isinstance(node.value, int):
|
||||
return fix_missing_locations(Call(func=Name('Integer', Load()),
|
||||
args=[node], keywords=[]))
|
||||
elif isinstance(node.value, float):
|
||||
return fix_missing_locations(Call(func=Name('Float', Load()),
|
||||
args=[node], keywords=[]))
|
||||
return node
|
||||
|
||||
def visit_Name(self, node):
|
||||
if node.id in self.local_dict:
|
||||
return node
|
||||
elif node.id in self.global_dict:
|
||||
name_obj = self.global_dict[node.id]
|
||||
|
||||
if isinstance(name_obj, (Basic, type)) or callable(name_obj):
|
||||
return node
|
||||
elif node.id in ['True', 'False']:
|
||||
return node
|
||||
return fix_missing_locations(Call(func=Name('Symbol', Load()),
|
||||
args=[Constant(node.id)], keywords=[]))
|
||||
|
||||
def visit_Lambda(self, node):
|
||||
args = [self.visit(arg) for arg in node.args.args]
|
||||
body = self.visit(node.body)
|
||||
n = Call(func=Name('Lambda', Load()),
|
||||
args=[Tuple(args, Load()), body], keywords=[])
|
||||
return fix_missing_locations(n)
|
||||
|
||||
def parse_expr(s, local_dict):
|
||||
"""
|
||||
Converts the string "s" to a SymPy expression, in local_dict.
|
||||
|
||||
It converts all numbers to Integers before feeding it to Python and
|
||||
automatically creates Symbols.
|
||||
"""
|
||||
global_dict = {}
|
||||
exec('from sympy import *', global_dict)
|
||||
try:
|
||||
a = parse(s.strip(), mode="eval")
|
||||
except SyntaxError:
|
||||
raise SympifyError("Cannot parse %s." % repr(s))
|
||||
a = Transform(local_dict, global_dict).visit(a)
|
||||
e = compile(a, "<string>", "eval")
|
||||
return eval(e, global_dict, local_dict)
|
||||
@@ -0,0 +1,118 @@
|
||||
grammar Autolev;
|
||||
|
||||
options {
|
||||
language = Python3;
|
||||
}
|
||||
|
||||
prog: stat+;
|
||||
|
||||
stat: varDecl
|
||||
| functionCall
|
||||
| codeCommands
|
||||
| massDecl
|
||||
| inertiaDecl
|
||||
| assignment
|
||||
| settings
|
||||
;
|
||||
|
||||
assignment: vec equals expr #vecAssign
|
||||
| ID '[' index ']' equals expr #indexAssign
|
||||
| ID diff? equals expr #regularAssign;
|
||||
|
||||
equals: ('='|'+='|'-='|':='|'*='|'/='|'^=');
|
||||
|
||||
index: expr (',' expr)* ;
|
||||
|
||||
diff: ('\'')+;
|
||||
|
||||
functionCall: ID '(' (expr (',' expr)*)? ')'
|
||||
| (Mass|Inertia) '(' (ID (',' ID)*)? ')';
|
||||
|
||||
varDecl: varType varDecl2 (',' varDecl2)*;
|
||||
|
||||
varType: Newtonian|Frames|Bodies|Particles|Points|Constants
|
||||
| Specifieds|Imaginary|Variables ('\'')*|MotionVariables ('\'')*;
|
||||
|
||||
varDecl2: ID ('{' INT ',' INT '}')? (('{' INT ':' INT (',' INT ':' INT)* '}'))? ('{' INT '}')? ('+'|'-')? ('\'')* ('=' expr)?;
|
||||
|
||||
ranges: ('{' INT ':' INT (',' INT ':' INT)* '}');
|
||||
|
||||
massDecl: Mass massDecl2 (',' massDecl2)*;
|
||||
|
||||
massDecl2: ID '=' expr;
|
||||
|
||||
inertiaDecl: Inertia ID ('(' ID ')')? (',' expr)+;
|
||||
|
||||
matrix: '[' expr ((','|';') expr)* ']';
|
||||
matrixInOutput: (ID (ID '=' (FLOAT|INT)?))|FLOAT|INT;
|
||||
|
||||
codeCommands: units
|
||||
| inputs
|
||||
| outputs
|
||||
| codegen
|
||||
| commands;
|
||||
|
||||
settings: ID (EXP|ID|FLOAT|INT)?;
|
||||
|
||||
units: UnitSystem ID (',' ID)*;
|
||||
inputs: Input inputs2 (',' inputs2)*;
|
||||
id_diff: ID diff?;
|
||||
inputs2: id_diff '=' expr expr?;
|
||||
outputs: Output outputs2 (',' outputs2)*;
|
||||
outputs2: expr expr?;
|
||||
codegen: ID functionCall ('['matrixInOutput (',' matrixInOutput)*']')? ID'.'ID;
|
||||
|
||||
commands: Save ID'.'ID
|
||||
| Encode ID (',' ID)*;
|
||||
|
||||
vec: ID ('>')+
|
||||
| '0>'
|
||||
| '1>>';
|
||||
|
||||
expr: expr '^'<assoc=right> expr # Exponent
|
||||
| expr ('*'|'/') expr # MulDiv
|
||||
| expr ('+'|'-') expr # AddSub
|
||||
| EXP # exp
|
||||
| '-' expr # negativeOne
|
||||
| FLOAT # float
|
||||
| INT # int
|
||||
| ID('\'')* # id
|
||||
| vec # VectorOrDyadic
|
||||
| ID '['expr (',' expr)* ']' # Indexing
|
||||
| functionCall # function
|
||||
| matrix # matrices
|
||||
| '(' expr ')' # parens
|
||||
| expr '=' expr # idEqualsExpr
|
||||
| expr ':' expr # colon
|
||||
| ID? ranges ('\'')* # rangess
|
||||
;
|
||||
|
||||
// These are to take care of the case insensitivity of Autolev.
|
||||
Mass: ('M'|'m')('A'|'a')('S'|'s')('S'|'s');
|
||||
Inertia: ('I'|'i')('N'|'n')('E'|'e')('R'|'r')('T'|'t')('I'|'i')('A'|'a');
|
||||
Input: ('I'|'i')('N'|'n')('P'|'p')('U'|'u')('T'|'t')('S'|'s')?;
|
||||
Output: ('O'|'o')('U'|'u')('T'|'t')('P'|'p')('U'|'u')('T'|'t');
|
||||
Save: ('S'|'s')('A'|'a')('V'|'v')('E'|'e');
|
||||
UnitSystem: ('U'|'u')('N'|'n')('I'|'i')('T'|'t')('S'|'s')('Y'|'y')('S'|'s')('T'|'t')('E'|'e')('M'|'m');
|
||||
Encode: ('E'|'e')('N'|'n')('C'|'c')('O'|'o')('D'|'d')('E'|'e');
|
||||
Newtonian: ('N'|'n')('E'|'e')('W'|'w')('T'|'t')('O'|'o')('N'|'n')('I'|'i')('A'|'a')('N'|'n');
|
||||
Frames: ('F'|'f')('R'|'r')('A'|'a')('M'|'m')('E'|'e')('S'|'s')?;
|
||||
Bodies: ('B'|'b')('O'|'o')('D'|'d')('I'|'i')('E'|'e')('S'|'s')?;
|
||||
Particles: ('P'|'p')('A'|'a')('R'|'r')('T'|'t')('I'|'i')('C'|'c')('L'|'l')('E'|'e')('S'|'s')?;
|
||||
Points: ('P'|'p')('O'|'o')('I'|'i')('N'|'n')('T'|'t')('S'|'s')?;
|
||||
Constants: ('C'|'c')('O'|'o')('N'|'n')('S'|'s')('T'|'t')('A'|'a')('N'|'n')('T'|'t')('S'|'s')?;
|
||||
Specifieds: ('S'|'s')('P'|'p')('E'|'e')('C'|'c')('I'|'i')('F'|'f')('I'|'i')('E'|'e')('D'|'d')('S'|'s')?;
|
||||
Imaginary: ('I'|'i')('M'|'m')('A'|'a')('G'|'g')('I'|'i')('N'|'n')('A'|'a')('R'|'r')('Y'|'y');
|
||||
Variables: ('V'|'v')('A'|'a')('R'|'r')('I'|'i')('A'|'a')('B'|'b')('L'|'l')('E'|'e')('S'|'s')?;
|
||||
MotionVariables: ('M'|'m')('O'|'o')('T'|'t')('I'|'i')('O'|'o')('N'|'n')('V'|'v')('A'|'a')('R'|'r')('I'|'i')('A'|'a')('B'|'b')('L'|'l')('E'|'e')('S'|'s')?;
|
||||
|
||||
fragment DIFF: ('\'')*;
|
||||
fragment DIGIT: [0-9];
|
||||
INT: [0-9]+ ; // match integers
|
||||
FLOAT: DIGIT+ '.' DIGIT*
|
||||
| '.' DIGIT+;
|
||||
EXP: FLOAT 'E' INT
|
||||
| FLOAT 'E' '-' INT;
|
||||
LINE_COMMENT : '%' .*? '\r'? '\n' -> skip ;
|
||||
ID: [a-zA-Z][a-zA-Z0-9_]*;
|
||||
WS: [ \t\r\n&]+ -> skip ; // toss out whitespace
|
||||
@@ -0,0 +1,97 @@
|
||||
from sympy.external import import_module
|
||||
from sympy.utilities.decorator import doctest_depends_on
|
||||
|
||||
@doctest_depends_on(modules=('antlr4',))
|
||||
def parse_autolev(autolev_code, include_numeric=False):
|
||||
"""Parses Autolev code (version 4.1) to SymPy code.
|
||||
|
||||
Parameters
|
||||
=========
|
||||
autolev_code : Can be an str or any object with a readlines() method (such as a file handle or StringIO).
|
||||
include_numeric : boolean, optional
|
||||
If True NumPy, PyDy, or other numeric code is included for numeric evaluation lines in the Autolev code.
|
||||
|
||||
Returns
|
||||
=======
|
||||
sympy_code : str
|
||||
Equivalent SymPy and/or numpy/pydy code as the input code.
|
||||
|
||||
|
||||
Example (Double Pendulum)
|
||||
=========================
|
||||
>>> my_al_text = ("MOTIONVARIABLES' Q{2}', U{2}'",
|
||||
... "CONSTANTS L,M,G",
|
||||
... "NEWTONIAN N",
|
||||
... "FRAMES A,B",
|
||||
... "SIMPROT(N, A, 3, Q1)",
|
||||
... "SIMPROT(N, B, 3, Q2)",
|
||||
... "W_A_N>=U1*N3>",
|
||||
... "W_B_N>=U2*N3>",
|
||||
... "POINT O",
|
||||
... "PARTICLES P,R",
|
||||
... "P_O_P> = L*A1>",
|
||||
... "P_P_R> = L*B1>",
|
||||
... "V_O_N> = 0>",
|
||||
... "V2PTS(N, A, O, P)",
|
||||
... "V2PTS(N, B, P, R)",
|
||||
... "MASS P=M, R=M",
|
||||
... "Q1' = U1",
|
||||
... "Q2' = U2",
|
||||
... "GRAVITY(G*N1>)",
|
||||
... "ZERO = FR() + FRSTAR()",
|
||||
... "KANE()",
|
||||
... "INPUT M=1,G=9.81,L=1",
|
||||
... "INPUT Q1=.1,Q2=.2,U1=0,U2=0",
|
||||
... "INPUT TFINAL=10, INTEGSTP=.01",
|
||||
... "CODE DYNAMICS() some_filename.c")
|
||||
>>> my_al_text = '\\n'.join(my_al_text)
|
||||
>>> from sympy.parsing.autolev import parse_autolev
|
||||
>>> print(parse_autolev(my_al_text, include_numeric=True))
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
<BLANKLINE>
|
||||
q1, q2, u1, u2 = _me.dynamicsymbols('q1 q2 u1 u2')
|
||||
q1_d, q2_d, u1_d, u2_d = _me.dynamicsymbols('q1_ q2_ u1_ u2_', 1)
|
||||
l, m, g = _sm.symbols('l m g', real=True)
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_b = _me.ReferenceFrame('b')
|
||||
frame_a.orient(frame_n, 'Axis', [q1, frame_n.z])
|
||||
frame_b.orient(frame_n, 'Axis', [q2, frame_n.z])
|
||||
frame_a.set_ang_vel(frame_n, u1*frame_n.z)
|
||||
frame_b.set_ang_vel(frame_n, u2*frame_n.z)
|
||||
point_o = _me.Point('o')
|
||||
particle_p = _me.Particle('p', _me.Point('p_pt'), _sm.Symbol('m'))
|
||||
particle_r = _me.Particle('r', _me.Point('r_pt'), _sm.Symbol('m'))
|
||||
particle_p.point.set_pos(point_o, l*frame_a.x)
|
||||
particle_r.point.set_pos(particle_p.point, l*frame_b.x)
|
||||
point_o.set_vel(frame_n, 0)
|
||||
particle_p.point.v2pt_theory(point_o,frame_n,frame_a)
|
||||
particle_r.point.v2pt_theory(particle_p.point,frame_n,frame_b)
|
||||
particle_p.mass = m
|
||||
particle_r.mass = m
|
||||
force_p = particle_p.mass*(g*frame_n.x)
|
||||
force_r = particle_r.mass*(g*frame_n.x)
|
||||
kd_eqs = [q1_d - u1, q2_d - u2]
|
||||
forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x)), (particle_r.point,particle_r.mass*(g*frame_n.x))]
|
||||
kane = _me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs)
|
||||
fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList)
|
||||
zero = fr+frstar
|
||||
from pydy.system import System
|
||||
sys = System(kane, constants = {l:1, m:1, g:9.81},
|
||||
specifieds={},
|
||||
initial_conditions={q1:.1, q2:.2, u1:0, u2:0},
|
||||
times = _np.linspace(0.0, 10, 10/.01))
|
||||
<BLANKLINE>
|
||||
y=sys.integrate()
|
||||
<BLANKLINE>
|
||||
"""
|
||||
|
||||
_autolev = import_module(
|
||||
'sympy.parsing.autolev._parse_autolev_antlr',
|
||||
import_kwargs={'fromlist': ['X']})
|
||||
|
||||
if _autolev is not None:
|
||||
return _autolev.parse_autolev(autolev_code, include_numeric)
|
||||
@@ -0,0 +1,5 @@
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
@@ -0,0 +1,253 @@
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
from antlr4 import *
|
||||
from io import StringIO
|
||||
import sys
|
||||
if sys.version_info[1] > 5:
|
||||
from typing import TextIO
|
||||
else:
|
||||
from typing.io import TextIO
|
||||
|
||||
|
||||
def serializedATN():
|
||||
return [
|
||||
4,0,49,393,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
|
||||
2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,
|
||||
13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,
|
||||
19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,
|
||||
26,7,26,2,27,7,27,2,28,7,28,2,29,7,29,2,30,7,30,2,31,7,31,2,32,7,
|
||||
32,2,33,7,33,2,34,7,34,2,35,7,35,2,36,7,36,2,37,7,37,2,38,7,38,2,
|
||||
39,7,39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,2,44,7,44,2,45,7,
|
||||
45,2,46,7,46,2,47,7,47,2,48,7,48,2,49,7,49,2,50,7,50,1,0,1,0,1,1,
|
||||
1,1,1,2,1,2,1,3,1,3,1,3,1,4,1,4,1,4,1,5,1,5,1,5,1,6,1,6,1,6,1,7,
|
||||
1,7,1,7,1,8,1,8,1,8,1,9,1,9,1,10,1,10,1,11,1,11,1,12,1,12,1,13,1,
|
||||
13,1,14,1,14,1,15,1,15,1,16,1,16,1,17,1,17,1,18,1,18,1,19,1,19,1,
|
||||
20,1,20,1,21,1,21,1,21,1,22,1,22,1,22,1,22,1,23,1,23,1,24,1,24,1,
|
||||
25,1,25,1,26,1,26,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,
|
||||
27,1,27,1,28,1,28,1,28,1,28,1,28,1,28,3,28,184,8,28,1,29,1,29,1,
|
||||
29,1,29,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,31,1,
|
||||
31,1,31,1,31,1,31,1,31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,
|
||||
32,1,32,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,34,1,
|
||||
34,1,34,1,34,1,34,1,34,3,34,232,8,34,1,35,1,35,1,35,1,35,1,35,1,
|
||||
35,3,35,240,8,35,1,36,1,36,1,36,1,36,1,36,1,36,1,36,1,36,1,36,3,
|
||||
36,251,8,36,1,37,1,37,1,37,1,37,1,37,1,37,3,37,259,8,37,1,38,1,38,
|
||||
1,38,1,38,1,38,1,38,1,38,1,38,1,38,3,38,270,8,38,1,39,1,39,1,39,
|
||||
1,39,1,39,1,39,1,39,1,39,1,39,1,39,3,39,282,8,39,1,40,1,40,1,40,
|
||||
1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,41,1,41,1,41,1,41,1,41,1,41,
|
||||
1,41,1,41,1,41,3,41,303,8,41,1,42,1,42,1,42,1,42,1,42,1,42,1,42,
|
||||
1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,3,42,320,8,42,1,43,5,43,
|
||||
323,8,43,10,43,12,43,326,9,43,1,44,1,44,1,45,4,45,331,8,45,11,45,
|
||||
12,45,332,1,46,4,46,336,8,46,11,46,12,46,337,1,46,1,46,5,46,342,
|
||||
8,46,10,46,12,46,345,9,46,1,46,1,46,4,46,349,8,46,11,46,12,46,350,
|
||||
3,46,353,8,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,3,47,
|
||||
364,8,47,1,48,1,48,5,48,368,8,48,10,48,12,48,371,9,48,1,48,3,48,
|
||||
374,8,48,1,48,1,48,1,48,1,48,1,49,1,49,5,49,382,8,49,10,49,12,49,
|
||||
385,9,49,1,50,4,50,388,8,50,11,50,12,50,389,1,50,1,50,1,369,0,51,
|
||||
1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,
|
||||
27,14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,
|
||||
49,25,51,26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34,69,35,
|
||||
71,36,73,37,75,38,77,39,79,40,81,41,83,42,85,43,87,0,89,0,91,44,
|
||||
93,45,95,46,97,47,99,48,101,49,1,0,24,2,0,77,77,109,109,2,0,65,65,
|
||||
97,97,2,0,83,83,115,115,2,0,73,73,105,105,2,0,78,78,110,110,2,0,
|
||||
69,69,101,101,2,0,82,82,114,114,2,0,84,84,116,116,2,0,80,80,112,
|
||||
112,2,0,85,85,117,117,2,0,79,79,111,111,2,0,86,86,118,118,2,0,89,
|
||||
89,121,121,2,0,67,67,99,99,2,0,68,68,100,100,2,0,87,87,119,119,2,
|
||||
0,70,70,102,102,2,0,66,66,98,98,2,0,76,76,108,108,2,0,71,71,103,
|
||||
103,1,0,48,57,2,0,65,90,97,122,4,0,48,57,65,90,95,95,97,122,4,0,
|
||||
9,10,13,13,32,32,38,38,410,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,
|
||||
7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,
|
||||
1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,
|
||||
1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,
|
||||
1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,47,
|
||||
1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,57,
|
||||
1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67,
|
||||
1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,
|
||||
1,0,0,0,0,79,1,0,0,0,0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,91,
|
||||
1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,0,0,101,
|
||||
1,0,0,0,1,103,1,0,0,0,3,105,1,0,0,0,5,107,1,0,0,0,7,109,1,0,0,0,
|
||||
9,112,1,0,0,0,11,115,1,0,0,0,13,118,1,0,0,0,15,121,1,0,0,0,17,124,
|
||||
1,0,0,0,19,127,1,0,0,0,21,129,1,0,0,0,23,131,1,0,0,0,25,133,1,0,
|
||||
0,0,27,135,1,0,0,0,29,137,1,0,0,0,31,139,1,0,0,0,33,141,1,0,0,0,
|
||||
35,143,1,0,0,0,37,145,1,0,0,0,39,147,1,0,0,0,41,149,1,0,0,0,43,151,
|
||||
1,0,0,0,45,154,1,0,0,0,47,158,1,0,0,0,49,160,1,0,0,0,51,162,1,0,
|
||||
0,0,53,164,1,0,0,0,55,169,1,0,0,0,57,177,1,0,0,0,59,185,1,0,0,0,
|
||||
61,192,1,0,0,0,63,197,1,0,0,0,65,208,1,0,0,0,67,215,1,0,0,0,69,225,
|
||||
1,0,0,0,71,233,1,0,0,0,73,241,1,0,0,0,75,252,1,0,0,0,77,260,1,0,
|
||||
0,0,79,271,1,0,0,0,81,283,1,0,0,0,83,293,1,0,0,0,85,304,1,0,0,0,
|
||||
87,324,1,0,0,0,89,327,1,0,0,0,91,330,1,0,0,0,93,352,1,0,0,0,95,363,
|
||||
1,0,0,0,97,365,1,0,0,0,99,379,1,0,0,0,101,387,1,0,0,0,103,104,5,
|
||||
91,0,0,104,2,1,0,0,0,105,106,5,93,0,0,106,4,1,0,0,0,107,108,5,61,
|
||||
0,0,108,6,1,0,0,0,109,110,5,43,0,0,110,111,5,61,0,0,111,8,1,0,0,
|
||||
0,112,113,5,45,0,0,113,114,5,61,0,0,114,10,1,0,0,0,115,116,5,58,
|
||||
0,0,116,117,5,61,0,0,117,12,1,0,0,0,118,119,5,42,0,0,119,120,5,61,
|
||||
0,0,120,14,1,0,0,0,121,122,5,47,0,0,122,123,5,61,0,0,123,16,1,0,
|
||||
0,0,124,125,5,94,0,0,125,126,5,61,0,0,126,18,1,0,0,0,127,128,5,44,
|
||||
0,0,128,20,1,0,0,0,129,130,5,39,0,0,130,22,1,0,0,0,131,132,5,40,
|
||||
0,0,132,24,1,0,0,0,133,134,5,41,0,0,134,26,1,0,0,0,135,136,5,123,
|
||||
0,0,136,28,1,0,0,0,137,138,5,125,0,0,138,30,1,0,0,0,139,140,5,58,
|
||||
0,0,140,32,1,0,0,0,141,142,5,43,0,0,142,34,1,0,0,0,143,144,5,45,
|
||||
0,0,144,36,1,0,0,0,145,146,5,59,0,0,146,38,1,0,0,0,147,148,5,46,
|
||||
0,0,148,40,1,0,0,0,149,150,5,62,0,0,150,42,1,0,0,0,151,152,5,48,
|
||||
0,0,152,153,5,62,0,0,153,44,1,0,0,0,154,155,5,49,0,0,155,156,5,62,
|
||||
0,0,156,157,5,62,0,0,157,46,1,0,0,0,158,159,5,94,0,0,159,48,1,0,
|
||||
0,0,160,161,5,42,0,0,161,50,1,0,0,0,162,163,5,47,0,0,163,52,1,0,
|
||||
0,0,164,165,7,0,0,0,165,166,7,1,0,0,166,167,7,2,0,0,167,168,7,2,
|
||||
0,0,168,54,1,0,0,0,169,170,7,3,0,0,170,171,7,4,0,0,171,172,7,5,0,
|
||||
0,172,173,7,6,0,0,173,174,7,7,0,0,174,175,7,3,0,0,175,176,7,1,0,
|
||||
0,176,56,1,0,0,0,177,178,7,3,0,0,178,179,7,4,0,0,179,180,7,8,0,0,
|
||||
180,181,7,9,0,0,181,183,7,7,0,0,182,184,7,2,0,0,183,182,1,0,0,0,
|
||||
183,184,1,0,0,0,184,58,1,0,0,0,185,186,7,10,0,0,186,187,7,9,0,0,
|
||||
187,188,7,7,0,0,188,189,7,8,0,0,189,190,7,9,0,0,190,191,7,7,0,0,
|
||||
191,60,1,0,0,0,192,193,7,2,0,0,193,194,7,1,0,0,194,195,7,11,0,0,
|
||||
195,196,7,5,0,0,196,62,1,0,0,0,197,198,7,9,0,0,198,199,7,4,0,0,199,
|
||||
200,7,3,0,0,200,201,7,7,0,0,201,202,7,2,0,0,202,203,7,12,0,0,203,
|
||||
204,7,2,0,0,204,205,7,7,0,0,205,206,7,5,0,0,206,207,7,0,0,0,207,
|
||||
64,1,0,0,0,208,209,7,5,0,0,209,210,7,4,0,0,210,211,7,13,0,0,211,
|
||||
212,7,10,0,0,212,213,7,14,0,0,213,214,7,5,0,0,214,66,1,0,0,0,215,
|
||||
216,7,4,0,0,216,217,7,5,0,0,217,218,7,15,0,0,218,219,7,7,0,0,219,
|
||||
220,7,10,0,0,220,221,7,4,0,0,221,222,7,3,0,0,222,223,7,1,0,0,223,
|
||||
224,7,4,0,0,224,68,1,0,0,0,225,226,7,16,0,0,226,227,7,6,0,0,227,
|
||||
228,7,1,0,0,228,229,7,0,0,0,229,231,7,5,0,0,230,232,7,2,0,0,231,
|
||||
230,1,0,0,0,231,232,1,0,0,0,232,70,1,0,0,0,233,234,7,17,0,0,234,
|
||||
235,7,10,0,0,235,236,7,14,0,0,236,237,7,3,0,0,237,239,7,5,0,0,238,
|
||||
240,7,2,0,0,239,238,1,0,0,0,239,240,1,0,0,0,240,72,1,0,0,0,241,242,
|
||||
7,8,0,0,242,243,7,1,0,0,243,244,7,6,0,0,244,245,7,7,0,0,245,246,
|
||||
7,3,0,0,246,247,7,13,0,0,247,248,7,18,0,0,248,250,7,5,0,0,249,251,
|
||||
7,2,0,0,250,249,1,0,0,0,250,251,1,0,0,0,251,74,1,0,0,0,252,253,7,
|
||||
8,0,0,253,254,7,10,0,0,254,255,7,3,0,0,255,256,7,4,0,0,256,258,7,
|
||||
7,0,0,257,259,7,2,0,0,258,257,1,0,0,0,258,259,1,0,0,0,259,76,1,0,
|
||||
0,0,260,261,7,13,0,0,261,262,7,10,0,0,262,263,7,4,0,0,263,264,7,
|
||||
2,0,0,264,265,7,7,0,0,265,266,7,1,0,0,266,267,7,4,0,0,267,269,7,
|
||||
7,0,0,268,270,7,2,0,0,269,268,1,0,0,0,269,270,1,0,0,0,270,78,1,0,
|
||||
0,0,271,272,7,2,0,0,272,273,7,8,0,0,273,274,7,5,0,0,274,275,7,13,
|
||||
0,0,275,276,7,3,0,0,276,277,7,16,0,0,277,278,7,3,0,0,278,279,7,5,
|
||||
0,0,279,281,7,14,0,0,280,282,7,2,0,0,281,280,1,0,0,0,281,282,1,0,
|
||||
0,0,282,80,1,0,0,0,283,284,7,3,0,0,284,285,7,0,0,0,285,286,7,1,0,
|
||||
0,286,287,7,19,0,0,287,288,7,3,0,0,288,289,7,4,0,0,289,290,7,1,0,
|
||||
0,290,291,7,6,0,0,291,292,7,12,0,0,292,82,1,0,0,0,293,294,7,11,0,
|
||||
0,294,295,7,1,0,0,295,296,7,6,0,0,296,297,7,3,0,0,297,298,7,1,0,
|
||||
0,298,299,7,17,0,0,299,300,7,18,0,0,300,302,7,5,0,0,301,303,7,2,
|
||||
0,0,302,301,1,0,0,0,302,303,1,0,0,0,303,84,1,0,0,0,304,305,7,0,0,
|
||||
0,305,306,7,10,0,0,306,307,7,7,0,0,307,308,7,3,0,0,308,309,7,10,
|
||||
0,0,309,310,7,4,0,0,310,311,7,11,0,0,311,312,7,1,0,0,312,313,7,6,
|
||||
0,0,313,314,7,3,0,0,314,315,7,1,0,0,315,316,7,17,0,0,316,317,7,18,
|
||||
0,0,317,319,7,5,0,0,318,320,7,2,0,0,319,318,1,0,0,0,319,320,1,0,
|
||||
0,0,320,86,1,0,0,0,321,323,5,39,0,0,322,321,1,0,0,0,323,326,1,0,
|
||||
0,0,324,322,1,0,0,0,324,325,1,0,0,0,325,88,1,0,0,0,326,324,1,0,0,
|
||||
0,327,328,7,20,0,0,328,90,1,0,0,0,329,331,7,20,0,0,330,329,1,0,0,
|
||||
0,331,332,1,0,0,0,332,330,1,0,0,0,332,333,1,0,0,0,333,92,1,0,0,0,
|
||||
334,336,3,89,44,0,335,334,1,0,0,0,336,337,1,0,0,0,337,335,1,0,0,
|
||||
0,337,338,1,0,0,0,338,339,1,0,0,0,339,343,5,46,0,0,340,342,3,89,
|
||||
44,0,341,340,1,0,0,0,342,345,1,0,0,0,343,341,1,0,0,0,343,344,1,0,
|
||||
0,0,344,353,1,0,0,0,345,343,1,0,0,0,346,348,5,46,0,0,347,349,3,89,
|
||||
44,0,348,347,1,0,0,0,349,350,1,0,0,0,350,348,1,0,0,0,350,351,1,0,
|
||||
0,0,351,353,1,0,0,0,352,335,1,0,0,0,352,346,1,0,0,0,353,94,1,0,0,
|
||||
0,354,355,3,93,46,0,355,356,5,69,0,0,356,357,3,91,45,0,357,364,1,
|
||||
0,0,0,358,359,3,93,46,0,359,360,5,69,0,0,360,361,5,45,0,0,361,362,
|
||||
3,91,45,0,362,364,1,0,0,0,363,354,1,0,0,0,363,358,1,0,0,0,364,96,
|
||||
1,0,0,0,365,369,5,37,0,0,366,368,9,0,0,0,367,366,1,0,0,0,368,371,
|
||||
1,0,0,0,369,370,1,0,0,0,369,367,1,0,0,0,370,373,1,0,0,0,371,369,
|
||||
1,0,0,0,372,374,5,13,0,0,373,372,1,0,0,0,373,374,1,0,0,0,374,375,
|
||||
1,0,0,0,375,376,5,10,0,0,376,377,1,0,0,0,377,378,6,48,0,0,378,98,
|
||||
1,0,0,0,379,383,7,21,0,0,380,382,7,22,0,0,381,380,1,0,0,0,382,385,
|
||||
1,0,0,0,383,381,1,0,0,0,383,384,1,0,0,0,384,100,1,0,0,0,385,383,
|
||||
1,0,0,0,386,388,7,23,0,0,387,386,1,0,0,0,388,389,1,0,0,0,389,387,
|
||||
1,0,0,0,389,390,1,0,0,0,390,391,1,0,0,0,391,392,6,50,0,0,392,102,
|
||||
1,0,0,0,21,0,183,231,239,250,258,269,281,302,319,324,332,337,343,
|
||||
350,352,363,369,373,383,389,1,6,0,0
|
||||
]
|
||||
|
||||
class AutolevLexer(Lexer):
|
||||
|
||||
atn = ATNDeserializer().deserialize(serializedATN())
|
||||
|
||||
decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
|
||||
|
||||
T__0 = 1
|
||||
T__1 = 2
|
||||
T__2 = 3
|
||||
T__3 = 4
|
||||
T__4 = 5
|
||||
T__5 = 6
|
||||
T__6 = 7
|
||||
T__7 = 8
|
||||
T__8 = 9
|
||||
T__9 = 10
|
||||
T__10 = 11
|
||||
T__11 = 12
|
||||
T__12 = 13
|
||||
T__13 = 14
|
||||
T__14 = 15
|
||||
T__15 = 16
|
||||
T__16 = 17
|
||||
T__17 = 18
|
||||
T__18 = 19
|
||||
T__19 = 20
|
||||
T__20 = 21
|
||||
T__21 = 22
|
||||
T__22 = 23
|
||||
T__23 = 24
|
||||
T__24 = 25
|
||||
T__25 = 26
|
||||
Mass = 27
|
||||
Inertia = 28
|
||||
Input = 29
|
||||
Output = 30
|
||||
Save = 31
|
||||
UnitSystem = 32
|
||||
Encode = 33
|
||||
Newtonian = 34
|
||||
Frames = 35
|
||||
Bodies = 36
|
||||
Particles = 37
|
||||
Points = 38
|
||||
Constants = 39
|
||||
Specifieds = 40
|
||||
Imaginary = 41
|
||||
Variables = 42
|
||||
MotionVariables = 43
|
||||
INT = 44
|
||||
FLOAT = 45
|
||||
EXP = 46
|
||||
LINE_COMMENT = 47
|
||||
ID = 48
|
||||
WS = 49
|
||||
|
||||
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
|
||||
|
||||
modeNames = [ "DEFAULT_MODE" ]
|
||||
|
||||
literalNames = [ "<INVALID>",
|
||||
"'['", "']'", "'='", "'+='", "'-='", "':='", "'*='", "'/='",
|
||||
"'^='", "','", "'''", "'('", "')'", "'{'", "'}'", "':'", "'+'",
|
||||
"'-'", "';'", "'.'", "'>'", "'0>'", "'1>>'", "'^'", "'*'", "'/'" ]
|
||||
|
||||
symbolicNames = [ "<INVALID>",
|
||||
"Mass", "Inertia", "Input", "Output", "Save", "UnitSystem",
|
||||
"Encode", "Newtonian", "Frames", "Bodies", "Particles", "Points",
|
||||
"Constants", "Specifieds", "Imaginary", "Variables", "MotionVariables",
|
||||
"INT", "FLOAT", "EXP", "LINE_COMMENT", "ID", "WS" ]
|
||||
|
||||
ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6",
|
||||
"T__7", "T__8", "T__9", "T__10", "T__11", "T__12", "T__13",
|
||||
"T__14", "T__15", "T__16", "T__17", "T__18", "T__19",
|
||||
"T__20", "T__21", "T__22", "T__23", "T__24", "T__25",
|
||||
"Mass", "Inertia", "Input", "Output", "Save", "UnitSystem",
|
||||
"Encode", "Newtonian", "Frames", "Bodies", "Particles",
|
||||
"Points", "Constants", "Specifieds", "Imaginary", "Variables",
|
||||
"MotionVariables", "DIFF", "DIGIT", "INT", "FLOAT", "EXP",
|
||||
"LINE_COMMENT", "ID", "WS" ]
|
||||
|
||||
grammarFileName = "Autolev.g4"
|
||||
|
||||
def __init__(self, input=None, output:TextIO = sys.stdout):
|
||||
super().__init__(input, output)
|
||||
self.checkVersion("4.11.1")
|
||||
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
|
||||
self._actions = None
|
||||
self._predicates = None
|
||||
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
from antlr4 import *
|
||||
if __name__ is not None and "." in __name__:
|
||||
from .autolevparser import AutolevParser
|
||||
else:
|
||||
from autolevparser import AutolevParser
|
||||
|
||||
# This class defines a complete listener for a parse tree produced by AutolevParser.
|
||||
class AutolevListener(ParseTreeListener):
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#prog.
|
||||
def enterProg(self, ctx:AutolevParser.ProgContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#prog.
|
||||
def exitProg(self, ctx:AutolevParser.ProgContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#stat.
|
||||
def enterStat(self, ctx:AutolevParser.StatContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#stat.
|
||||
def exitStat(self, ctx:AutolevParser.StatContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#vecAssign.
|
||||
def enterVecAssign(self, ctx:AutolevParser.VecAssignContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#vecAssign.
|
||||
def exitVecAssign(self, ctx:AutolevParser.VecAssignContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#indexAssign.
|
||||
def enterIndexAssign(self, ctx:AutolevParser.IndexAssignContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#indexAssign.
|
||||
def exitIndexAssign(self, ctx:AutolevParser.IndexAssignContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#regularAssign.
|
||||
def enterRegularAssign(self, ctx:AutolevParser.RegularAssignContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#regularAssign.
|
||||
def exitRegularAssign(self, ctx:AutolevParser.RegularAssignContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#equals.
|
||||
def enterEquals(self, ctx:AutolevParser.EqualsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#equals.
|
||||
def exitEquals(self, ctx:AutolevParser.EqualsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#index.
|
||||
def enterIndex(self, ctx:AutolevParser.IndexContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#index.
|
||||
def exitIndex(self, ctx:AutolevParser.IndexContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#diff.
|
||||
def enterDiff(self, ctx:AutolevParser.DiffContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#diff.
|
||||
def exitDiff(self, ctx:AutolevParser.DiffContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#functionCall.
|
||||
def enterFunctionCall(self, ctx:AutolevParser.FunctionCallContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#functionCall.
|
||||
def exitFunctionCall(self, ctx:AutolevParser.FunctionCallContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#varDecl.
|
||||
def enterVarDecl(self, ctx:AutolevParser.VarDeclContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#varDecl.
|
||||
def exitVarDecl(self, ctx:AutolevParser.VarDeclContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#varType.
|
||||
def enterVarType(self, ctx:AutolevParser.VarTypeContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#varType.
|
||||
def exitVarType(self, ctx:AutolevParser.VarTypeContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#varDecl2.
|
||||
def enterVarDecl2(self, ctx:AutolevParser.VarDecl2Context):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#varDecl2.
|
||||
def exitVarDecl2(self, ctx:AutolevParser.VarDecl2Context):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#ranges.
|
||||
def enterRanges(self, ctx:AutolevParser.RangesContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#ranges.
|
||||
def exitRanges(self, ctx:AutolevParser.RangesContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#massDecl.
|
||||
def enterMassDecl(self, ctx:AutolevParser.MassDeclContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#massDecl.
|
||||
def exitMassDecl(self, ctx:AutolevParser.MassDeclContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#massDecl2.
|
||||
def enterMassDecl2(self, ctx:AutolevParser.MassDecl2Context):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#massDecl2.
|
||||
def exitMassDecl2(self, ctx:AutolevParser.MassDecl2Context):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#inertiaDecl.
|
||||
def enterInertiaDecl(self, ctx:AutolevParser.InertiaDeclContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#inertiaDecl.
|
||||
def exitInertiaDecl(self, ctx:AutolevParser.InertiaDeclContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#matrix.
|
||||
def enterMatrix(self, ctx:AutolevParser.MatrixContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#matrix.
|
||||
def exitMatrix(self, ctx:AutolevParser.MatrixContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#matrixInOutput.
|
||||
def enterMatrixInOutput(self, ctx:AutolevParser.MatrixInOutputContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#matrixInOutput.
|
||||
def exitMatrixInOutput(self, ctx:AutolevParser.MatrixInOutputContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#codeCommands.
|
||||
def enterCodeCommands(self, ctx:AutolevParser.CodeCommandsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#codeCommands.
|
||||
def exitCodeCommands(self, ctx:AutolevParser.CodeCommandsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#settings.
|
||||
def enterSettings(self, ctx:AutolevParser.SettingsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#settings.
|
||||
def exitSettings(self, ctx:AutolevParser.SettingsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#units.
|
||||
def enterUnits(self, ctx:AutolevParser.UnitsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#units.
|
||||
def exitUnits(self, ctx:AutolevParser.UnitsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#inputs.
|
||||
def enterInputs(self, ctx:AutolevParser.InputsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#inputs.
|
||||
def exitInputs(self, ctx:AutolevParser.InputsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#id_diff.
|
||||
def enterId_diff(self, ctx:AutolevParser.Id_diffContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#id_diff.
|
||||
def exitId_diff(self, ctx:AutolevParser.Id_diffContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#inputs2.
|
||||
def enterInputs2(self, ctx:AutolevParser.Inputs2Context):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#inputs2.
|
||||
def exitInputs2(self, ctx:AutolevParser.Inputs2Context):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#outputs.
|
||||
def enterOutputs(self, ctx:AutolevParser.OutputsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#outputs.
|
||||
def exitOutputs(self, ctx:AutolevParser.OutputsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#outputs2.
|
||||
def enterOutputs2(self, ctx:AutolevParser.Outputs2Context):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#outputs2.
|
||||
def exitOutputs2(self, ctx:AutolevParser.Outputs2Context):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#codegen.
|
||||
def enterCodegen(self, ctx:AutolevParser.CodegenContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#codegen.
|
||||
def exitCodegen(self, ctx:AutolevParser.CodegenContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#commands.
|
||||
def enterCommands(self, ctx:AutolevParser.CommandsContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#commands.
|
||||
def exitCommands(self, ctx:AutolevParser.CommandsContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#vec.
|
||||
def enterVec(self, ctx:AutolevParser.VecContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#vec.
|
||||
def exitVec(self, ctx:AutolevParser.VecContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#parens.
|
||||
def enterParens(self, ctx:AutolevParser.ParensContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#parens.
|
||||
def exitParens(self, ctx:AutolevParser.ParensContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#VectorOrDyadic.
|
||||
def enterVectorOrDyadic(self, ctx:AutolevParser.VectorOrDyadicContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#VectorOrDyadic.
|
||||
def exitVectorOrDyadic(self, ctx:AutolevParser.VectorOrDyadicContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#Exponent.
|
||||
def enterExponent(self, ctx:AutolevParser.ExponentContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#Exponent.
|
||||
def exitExponent(self, ctx:AutolevParser.ExponentContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#MulDiv.
|
||||
def enterMulDiv(self, ctx:AutolevParser.MulDivContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#MulDiv.
|
||||
def exitMulDiv(self, ctx:AutolevParser.MulDivContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#AddSub.
|
||||
def enterAddSub(self, ctx:AutolevParser.AddSubContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#AddSub.
|
||||
def exitAddSub(self, ctx:AutolevParser.AddSubContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#float.
|
||||
def enterFloat(self, ctx:AutolevParser.FloatContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#float.
|
||||
def exitFloat(self, ctx:AutolevParser.FloatContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#int.
|
||||
def enterInt(self, ctx:AutolevParser.IntContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#int.
|
||||
def exitInt(self, ctx:AutolevParser.IntContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#idEqualsExpr.
|
||||
def enterIdEqualsExpr(self, ctx:AutolevParser.IdEqualsExprContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#idEqualsExpr.
|
||||
def exitIdEqualsExpr(self, ctx:AutolevParser.IdEqualsExprContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#negativeOne.
|
||||
def enterNegativeOne(self, ctx:AutolevParser.NegativeOneContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#negativeOne.
|
||||
def exitNegativeOne(self, ctx:AutolevParser.NegativeOneContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#function.
|
||||
def enterFunction(self, ctx:AutolevParser.FunctionContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#function.
|
||||
def exitFunction(self, ctx:AutolevParser.FunctionContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#rangess.
|
||||
def enterRangess(self, ctx:AutolevParser.RangessContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#rangess.
|
||||
def exitRangess(self, ctx:AutolevParser.RangessContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#colon.
|
||||
def enterColon(self, ctx:AutolevParser.ColonContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#colon.
|
||||
def exitColon(self, ctx:AutolevParser.ColonContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#id.
|
||||
def enterId(self, ctx:AutolevParser.IdContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#id.
|
||||
def exitId(self, ctx:AutolevParser.IdContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#exp.
|
||||
def enterExp(self, ctx:AutolevParser.ExpContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#exp.
|
||||
def exitExp(self, ctx:AutolevParser.ExpContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#matrices.
|
||||
def enterMatrices(self, ctx:AutolevParser.MatricesContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#matrices.
|
||||
def exitMatrices(self, ctx:AutolevParser.MatricesContext):
|
||||
pass
|
||||
|
||||
|
||||
# Enter a parse tree produced by AutolevParser#Indexing.
|
||||
def enterIndexing(self, ctx:AutolevParser.IndexingContext):
|
||||
pass
|
||||
|
||||
# Exit a parse tree produced by AutolevParser#Indexing.
|
||||
def exitIndexing(self, ctx:AutolevParser.IndexingContext):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
del AutolevParser
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
import os
|
||||
import subprocess
|
||||
import glob
|
||||
|
||||
from sympy.utilities.misc import debug
|
||||
|
||||
here = os.path.dirname(__file__)
|
||||
grammar_file = os.path.abspath(os.path.join(here, "Autolev.g4"))
|
||||
dir_autolev_antlr = os.path.join(here, "_antlr")
|
||||
|
||||
header = '''\
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
'''
|
||||
|
||||
|
||||
def check_antlr_version():
|
||||
debug("Checking antlr4 version...")
|
||||
|
||||
try:
|
||||
debug(subprocess.check_output(["antlr4"])
|
||||
.decode('utf-8').split("\n")[0])
|
||||
return True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
debug("The 'antlr4' command line tool is not installed, "
|
||||
"or not on your PATH.\n"
|
||||
"> Please refer to the README.md file for more information.")
|
||||
return False
|
||||
|
||||
|
||||
def build_parser(output_dir=dir_autolev_antlr):
|
||||
check_antlr_version()
|
||||
|
||||
debug("Updating ANTLR-generated code in {}".format(output_dir))
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
with open(os.path.join(output_dir, "__init__.py"), "w+") as fp:
|
||||
fp.write(header)
|
||||
|
||||
args = [
|
||||
"antlr4",
|
||||
grammar_file,
|
||||
"-o", output_dir,
|
||||
"-no-visitor",
|
||||
]
|
||||
|
||||
debug("Running code generation...\n\t$ {}".format(" ".join(args)))
|
||||
subprocess.check_output(args, cwd=output_dir)
|
||||
|
||||
debug("Applying headers, removing unnecessary files and renaming...")
|
||||
# Handle case insensitive file systems. If the files are already
|
||||
# generated, they will be written to autolev* but Autolev*.* won't match them.
|
||||
for path in (glob.glob(os.path.join(output_dir, "Autolev*.*")) or
|
||||
glob.glob(os.path.join(output_dir, "autolev*.*"))):
|
||||
|
||||
# Remove files ending in .interp or .tokens as they are not needed.
|
||||
if not path.endswith(".py"):
|
||||
os.unlink(path)
|
||||
continue
|
||||
|
||||
new_path = os.path.join(output_dir, os.path.basename(path).lower())
|
||||
with open(path, 'r') as f:
|
||||
lines = [line.rstrip().replace('AutolevParser import', 'autolevparser import') +'\n'
|
||||
for line in f]
|
||||
|
||||
os.unlink(path)
|
||||
|
||||
with open(new_path, "w") as out_file:
|
||||
offset = 0
|
||||
while lines[offset].startswith('#'):
|
||||
offset += 1
|
||||
out_file.write(header)
|
||||
out_file.writelines(lines[offset:])
|
||||
|
||||
debug("\t{}".format(new_path))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
build_parser()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
from importlib.metadata import version
|
||||
from sympy.external import import_module
|
||||
|
||||
|
||||
autolevparser = import_module('sympy.parsing.autolev._antlr.autolevparser',
|
||||
import_kwargs={'fromlist': ['AutolevParser']})
|
||||
autolevlexer = import_module('sympy.parsing.autolev._antlr.autolevlexer',
|
||||
import_kwargs={'fromlist': ['AutolevLexer']})
|
||||
autolevlistener = import_module('sympy.parsing.autolev._antlr.autolevlistener',
|
||||
import_kwargs={'fromlist': ['AutolevListener']})
|
||||
|
||||
AutolevParser = getattr(autolevparser, 'AutolevParser', None)
|
||||
AutolevLexer = getattr(autolevlexer, 'AutolevLexer', None)
|
||||
AutolevListener = getattr(autolevlistener, 'AutolevListener', None)
|
||||
|
||||
|
||||
def parse_autolev(autolev_code, include_numeric):
|
||||
antlr4 = import_module('antlr4')
|
||||
if not antlr4 or not version('antlr4-python3-runtime').startswith('4.11'):
|
||||
raise ImportError("Autolev parsing requires the antlr4 Python package,"
|
||||
" provided by pip (antlr4-python3-runtime)"
|
||||
" conda (antlr-python-runtime), version 4.11")
|
||||
try:
|
||||
l = autolev_code.readlines()
|
||||
input_stream = antlr4.InputStream("".join(l))
|
||||
except Exception:
|
||||
input_stream = antlr4.InputStream(autolev_code)
|
||||
|
||||
if AutolevListener:
|
||||
from ._listener_autolev_antlr import MyListener
|
||||
lexer = AutolevLexer(input_stream)
|
||||
token_stream = antlr4.CommonTokenStream(lexer)
|
||||
parser = AutolevParser(token_stream)
|
||||
tree = parser.prog()
|
||||
my_listener = MyListener(include_numeric)
|
||||
walker = antlr4.ParseTreeWalker()
|
||||
walker.walk(my_listener, tree)
|
||||
return "".join(my_listener.output_code)
|
||||
@@ -0,0 +1,9 @@
|
||||
# parsing/tests/test_autolev.py uses the .al files in this directory as inputs and checks
|
||||
# the equivalence of the parser generated codes and the respective .py files.
|
||||
|
||||
# By default, this directory contains tests for all rules of the parser.
|
||||
|
||||
# Additional tests consisting of full physics examples shall be made available soon in
|
||||
# the form of another repository. One shall be able to copy the contents of that repo
|
||||
# to this folder and use those tests after uncommenting the respective code in
|
||||
# parsing/tests/test_autolev.py.
|
||||
@@ -0,0 +1,33 @@
|
||||
CONSTANTS G,LB,W,H
|
||||
MOTIONVARIABLES' THETA'',PHI'',OMEGA',ALPHA'
|
||||
NEWTONIAN N
|
||||
BODIES A,B
|
||||
SIMPROT(N,A,2,THETA)
|
||||
SIMPROT(A,B,3,PHI)
|
||||
POINT O
|
||||
LA = (LB-H/2)/2
|
||||
P_O_AO> = LA*A3>
|
||||
P_O_BO> = LB*A3>
|
||||
OMEGA = THETA'
|
||||
ALPHA = PHI'
|
||||
W_A_N> = OMEGA*N2>
|
||||
W_B_A> = ALPHA*A3>
|
||||
V_O_N> = 0>
|
||||
V2PTS(N, A, O, AO)
|
||||
V2PTS(N, A, O, BO)
|
||||
MASS A=MA, B=MB
|
||||
IAXX = 1/12*MA*(2*LA)^2
|
||||
IAYY = IAXX
|
||||
IAZZ = 0
|
||||
IBXX = 1/12*MB*H^2
|
||||
IBYY = 1/12*MB*(W^2+H^2)
|
||||
IBZZ = 1/12*MB*W^2
|
||||
INERTIA A, IAXX, IAYY, IAZZ
|
||||
INERTIA B, IBXX, IBYY, IBZZ
|
||||
GRAVITY(G*N3>)
|
||||
ZERO = FR() + FRSTAR()
|
||||
KANE()
|
||||
INPUT LB=0.2,H=0.1,W=0.2,MA=0.01,MB=0.1,G=9.81
|
||||
INPUT THETA = 90 DEG, PHI = 0.5 DEG, OMEGA=0, ALPHA=0
|
||||
INPUT TFINAL=10, INTEGSTP=0.02
|
||||
CODE DYNAMICS() some_filename.c
|
||||
@@ -0,0 +1,55 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
g, lb, w, h = _sm.symbols('g lb w h', real=True)
|
||||
theta, phi, omega, alpha = _me.dynamicsymbols('theta phi omega alpha')
|
||||
theta_d, phi_d, omega_d, alpha_d = _me.dynamicsymbols('theta_ phi_ omega_ alpha_', 1)
|
||||
theta_dd, phi_dd = _me.dynamicsymbols('theta_ phi_', 2)
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
body_a_cm = _me.Point('a_cm')
|
||||
body_a_cm.set_vel(frame_n, 0)
|
||||
body_a_f = _me.ReferenceFrame('a_f')
|
||||
body_a = _me.RigidBody('a', body_a_cm, body_a_f, _sm.symbols('m'), (_me.outer(body_a_f.x,body_a_f.x),body_a_cm))
|
||||
body_b_cm = _me.Point('b_cm')
|
||||
body_b_cm.set_vel(frame_n, 0)
|
||||
body_b_f = _me.ReferenceFrame('b_f')
|
||||
body_b = _me.RigidBody('b', body_b_cm, body_b_f, _sm.symbols('m'), (_me.outer(body_b_f.x,body_b_f.x),body_b_cm))
|
||||
body_a_f.orient(frame_n, 'Axis', [theta, frame_n.y])
|
||||
body_b_f.orient(body_a_f, 'Axis', [phi, body_a_f.z])
|
||||
point_o = _me.Point('o')
|
||||
la = (lb-h/2)/2
|
||||
body_a_cm.set_pos(point_o, la*body_a_f.z)
|
||||
body_b_cm.set_pos(point_o, lb*body_a_f.z)
|
||||
body_a_f.set_ang_vel(frame_n, omega*frame_n.y)
|
||||
body_b_f.set_ang_vel(body_a_f, alpha*body_a_f.z)
|
||||
point_o.set_vel(frame_n, 0)
|
||||
body_a_cm.v2pt_theory(point_o,frame_n,body_a_f)
|
||||
body_b_cm.v2pt_theory(point_o,frame_n,body_a_f)
|
||||
ma = _sm.symbols('ma')
|
||||
body_a.mass = ma
|
||||
mb = _sm.symbols('mb')
|
||||
body_b.mass = mb
|
||||
iaxx = 1/12*ma*(2*la)**2
|
||||
iayy = iaxx
|
||||
iazz = 0
|
||||
ibxx = 1/12*mb*h**2
|
||||
ibyy = 1/12*mb*(w**2+h**2)
|
||||
ibzz = 1/12*mb*w**2
|
||||
body_a.inertia = (_me.inertia(body_a_f, iaxx, iayy, iazz, 0, 0, 0), body_a_cm)
|
||||
body_b.inertia = (_me.inertia(body_b_f, ibxx, ibyy, ibzz, 0, 0, 0), body_b_cm)
|
||||
force_a = body_a.mass*(g*frame_n.z)
|
||||
force_b = body_b.mass*(g*frame_n.z)
|
||||
kd_eqs = [theta_d - omega, phi_d - alpha]
|
||||
forceList = [(body_a.masscenter,body_a.mass*(g*frame_n.z)), (body_b.masscenter,body_b.mass*(g*frame_n.z))]
|
||||
kane = _me.KanesMethod(frame_n, q_ind=[theta,phi], u_ind=[omega, alpha], kd_eqs = kd_eqs)
|
||||
fr, frstar = kane.kanes_equations([body_a, body_b], forceList)
|
||||
zero = fr+frstar
|
||||
from pydy.system import System
|
||||
sys = System(kane, constants = {g:9.81, lb:0.2, w:0.2, h:0.1, ma:0.01, mb:0.1},
|
||||
specifieds={},
|
||||
initial_conditions={theta:_np.deg2rad(90), phi:_np.deg2rad(0.5), omega:0, alpha:0},
|
||||
times = _np.linspace(0.0, 10, 10/0.02))
|
||||
|
||||
y=sys.integrate()
|
||||
@@ -0,0 +1,25 @@
|
||||
MOTIONVARIABLES' Q{2}', U{2}'
|
||||
CONSTANTS L,M,G
|
||||
NEWTONIAN N
|
||||
FRAMES A,B
|
||||
SIMPROT(N, A, 3, Q1)
|
||||
SIMPROT(N, B, 3, Q2)
|
||||
W_A_N>=U1*N3>
|
||||
W_B_N>=U2*N3>
|
||||
POINT O
|
||||
PARTICLES P,R
|
||||
P_O_P> = L*A1>
|
||||
P_P_R> = L*B1>
|
||||
V_O_N> = 0>
|
||||
V2PTS(N, A, O, P)
|
||||
V2PTS(N, B, P, R)
|
||||
MASS P=M, R=M
|
||||
Q1' = U1
|
||||
Q2' = U2
|
||||
GRAVITY(G*N1>)
|
||||
ZERO = FR() + FRSTAR()
|
||||
KANE()
|
||||
INPUT M=1,G=9.81,L=1
|
||||
INPUT Q1=.1,Q2=.2,U1=0,U2=0
|
||||
INPUT TFINAL=10, INTEGSTP=.01
|
||||
CODE DYNAMICS() some_filename.c
|
||||
@@ -0,0 +1,39 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
q1, q2, u1, u2 = _me.dynamicsymbols('q1 q2 u1 u2')
|
||||
q1_d, q2_d, u1_d, u2_d = _me.dynamicsymbols('q1_ q2_ u1_ u2_', 1)
|
||||
l, m, g = _sm.symbols('l m g', real=True)
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_b = _me.ReferenceFrame('b')
|
||||
frame_a.orient(frame_n, 'Axis', [q1, frame_n.z])
|
||||
frame_b.orient(frame_n, 'Axis', [q2, frame_n.z])
|
||||
frame_a.set_ang_vel(frame_n, u1*frame_n.z)
|
||||
frame_b.set_ang_vel(frame_n, u2*frame_n.z)
|
||||
point_o = _me.Point('o')
|
||||
particle_p = _me.Particle('p', _me.Point('p_pt'), _sm.Symbol('m'))
|
||||
particle_r = _me.Particle('r', _me.Point('r_pt'), _sm.Symbol('m'))
|
||||
particle_p.point.set_pos(point_o, l*frame_a.x)
|
||||
particle_r.point.set_pos(particle_p.point, l*frame_b.x)
|
||||
point_o.set_vel(frame_n, 0)
|
||||
particle_p.point.v2pt_theory(point_o,frame_n,frame_a)
|
||||
particle_r.point.v2pt_theory(particle_p.point,frame_n,frame_b)
|
||||
particle_p.mass = m
|
||||
particle_r.mass = m
|
||||
force_p = particle_p.mass*(g*frame_n.x)
|
||||
force_r = particle_r.mass*(g*frame_n.x)
|
||||
kd_eqs = [q1_d - u1, q2_d - u2]
|
||||
forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x)), (particle_r.point,particle_r.mass*(g*frame_n.x))]
|
||||
kane = _me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs)
|
||||
fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList)
|
||||
zero = fr+frstar
|
||||
from pydy.system import System
|
||||
sys = System(kane, constants = {l:1, m:1, g:9.81},
|
||||
specifieds={},
|
||||
initial_conditions={q1:.1, q2:.2, u1:0, u2:0},
|
||||
times = _np.linspace(0.0, 10, 10/.01))
|
||||
|
||||
y=sys.integrate()
|
||||
@@ -0,0 +1,19 @@
|
||||
CONSTANTS M,K,B,G
|
||||
MOTIONVARIABLES' POSITION',SPEED'
|
||||
VARIABLES O
|
||||
FORCE = O*SIN(T)
|
||||
NEWTONIAN CEILING
|
||||
POINTS ORIGIN
|
||||
V_ORIGIN_CEILING> = 0>
|
||||
PARTICLES BLOCK
|
||||
P_ORIGIN_BLOCK> = POSITION*CEILING1>
|
||||
MASS BLOCK=M
|
||||
V_BLOCK_CEILING>=SPEED*CEILING1>
|
||||
POSITION' = SPEED
|
||||
FORCE_MAGNITUDE = M*G-K*POSITION-B*SPEED+FORCE
|
||||
FORCE_BLOCK>=EXPLICIT(FORCE_MAGNITUDE*CEILING1>)
|
||||
ZERO = FR() + FRSTAR()
|
||||
KANE()
|
||||
INPUT TFINAL=10.0, INTEGSTP=0.01
|
||||
INPUT M=1.0, K=1.0, B=0.2, G=9.8, POSITION=0.1, SPEED=-1.0, O=2
|
||||
CODE DYNAMICS() dummy_file.c
|
||||
@@ -0,0 +1,31 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
m, k, b, g = _sm.symbols('m k b g', real=True)
|
||||
position, speed = _me.dynamicsymbols('position speed')
|
||||
position_d, speed_d = _me.dynamicsymbols('position_ speed_', 1)
|
||||
o = _me.dynamicsymbols('o')
|
||||
force = o*_sm.sin(_me.dynamicsymbols._t)
|
||||
frame_ceiling = _me.ReferenceFrame('ceiling')
|
||||
point_origin = _me.Point('origin')
|
||||
point_origin.set_vel(frame_ceiling, 0)
|
||||
particle_block = _me.Particle('block', _me.Point('block_pt'), _sm.Symbol('m'))
|
||||
particle_block.point.set_pos(point_origin, position*frame_ceiling.x)
|
||||
particle_block.mass = m
|
||||
particle_block.point.set_vel(frame_ceiling, speed*frame_ceiling.x)
|
||||
force_magnitude = m*g-k*position-b*speed+force
|
||||
force_block = (force_magnitude*frame_ceiling.x).subs({position_d:speed})
|
||||
kd_eqs = [position_d - speed]
|
||||
forceList = [(particle_block.point,(force_magnitude*frame_ceiling.x).subs({position_d:speed}))]
|
||||
kane = _me.KanesMethod(frame_ceiling, q_ind=[position], u_ind=[speed], kd_eqs = kd_eqs)
|
||||
fr, frstar = kane.kanes_equations([particle_block], forceList)
|
||||
zero = fr+frstar
|
||||
from pydy.system import System
|
||||
sys = System(kane, constants = {m:1.0, k:1.0, b:0.2, g:9.8},
|
||||
specifieds={_me.dynamicsymbols('t'):lambda x, t: t, o:2},
|
||||
initial_conditions={position:0.1, speed:-1*1.0},
|
||||
times = _np.linspace(0.0, 10.0, 10.0/0.01))
|
||||
|
||||
y=sys.integrate()
|
||||
@@ -0,0 +1,20 @@
|
||||
MOTIONVARIABLES' Q{2}''
|
||||
CONSTANTS L,M,G
|
||||
NEWTONIAN N
|
||||
POINT PN
|
||||
V_PN_N> = 0>
|
||||
THETA1 = ATAN(Q2/Q1)
|
||||
FRAMES A
|
||||
SIMPROT(N, A, 3, THETA1)
|
||||
PARTICLES P
|
||||
P_PN_P> = Q1*N1>+Q2*N2>
|
||||
MASS P=M
|
||||
V_P_N>=DT(P_P_PN>, N)
|
||||
F_V = DOT(EXPRESS(V_P_N>,A), A1>)
|
||||
GRAVITY(G*N1>)
|
||||
DEPENDENT[1] = F_V
|
||||
CONSTRAIN(DEPENDENT[Q1'])
|
||||
ZERO=FR()+FRSTAR()
|
||||
F_C = MAG(P_P_PN>)-L
|
||||
CONFIG[1]=F_C
|
||||
ZERO[2]=CONFIG[1]
|
||||
@@ -0,0 +1,36 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
q1, q2 = _me.dynamicsymbols('q1 q2')
|
||||
q1_d, q2_d = _me.dynamicsymbols('q1_ q2_', 1)
|
||||
q1_dd, q2_dd = _me.dynamicsymbols('q1_ q2_', 2)
|
||||
l, m, g = _sm.symbols('l m g', real=True)
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
point_pn = _me.Point('pn')
|
||||
point_pn.set_vel(frame_n, 0)
|
||||
theta1 = _sm.atan(q2/q1)
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_a.orient(frame_n, 'Axis', [theta1, frame_n.z])
|
||||
particle_p = _me.Particle('p', _me.Point('p_pt'), _sm.Symbol('m'))
|
||||
particle_p.point.set_pos(point_pn, q1*frame_n.x+q2*frame_n.y)
|
||||
particle_p.mass = m
|
||||
particle_p.point.set_vel(frame_n, (point_pn.pos_from(particle_p.point)).dt(frame_n))
|
||||
f_v = _me.dot((particle_p.point.vel(frame_n)).express(frame_a), frame_a.x)
|
||||
force_p = particle_p.mass*(g*frame_n.x)
|
||||
dependent = _sm.Matrix([[0]])
|
||||
dependent[0] = f_v
|
||||
velocity_constraints = [i for i in dependent]
|
||||
u_q1_d = _me.dynamicsymbols('u_q1_d')
|
||||
u_q2_d = _me.dynamicsymbols('u_q2_d')
|
||||
kd_eqs = [q1_d-u_q1_d, q2_d-u_q2_d]
|
||||
forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x))]
|
||||
kane = _me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u_q2_d], u_dependent=[u_q1_d], kd_eqs = kd_eqs, velocity_constraints = velocity_constraints)
|
||||
fr, frstar = kane.kanes_equations([particle_p], forceList)
|
||||
zero = fr+frstar
|
||||
f_c = point_pn.pos_from(particle_p.point).magnitude()-l
|
||||
config = _sm.Matrix([[0]])
|
||||
config[0] = f_c
|
||||
zero = zero.row_insert(zero.shape[0], _sm.Matrix([[0]]))
|
||||
zero[zero.shape[0]-1] = config[0]
|
||||
@@ -0,0 +1,8 @@
|
||||
% ruletest1.al
|
||||
CONSTANTS F = 3, G = 9.81
|
||||
CONSTANTS A, B
|
||||
CONSTANTS S, S1, S2+, S3+, S4-
|
||||
CONSTANTS K{4}, L{1:3}, P{1:2,1:3}
|
||||
CONSTANTS C{2,3}
|
||||
E1 = A*F + S2 - G
|
||||
E2 = F^2 + K3*K2*G
|
||||
@@ -0,0 +1,15 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
f = _sm.S(3)
|
||||
g = _sm.S(9.81)
|
||||
a, b = _sm.symbols('a b', real=True)
|
||||
s, s1 = _sm.symbols('s s1', real=True)
|
||||
s2, s3 = _sm.symbols('s2 s3', real=True, nonnegative=True)
|
||||
s4 = _sm.symbols('s4', real=True, nonpositive=True)
|
||||
k1, k2, k3, k4, l1, l2, l3, p11, p12, p13, p21, p22, p23 = _sm.symbols('k1 k2 k3 k4 l1 l2 l3 p11 p12 p13 p21 p22 p23', real=True)
|
||||
c11, c12, c13, c21, c22, c23 = _sm.symbols('c11 c12 c13 c21 c22 c23', real=True)
|
||||
e1 = a*f+s2-g
|
||||
e2 = f**2+k3*k2*g
|
||||
@@ -0,0 +1,58 @@
|
||||
% ruletest10.al
|
||||
|
||||
VARIABLES X,Y
|
||||
COMPLEX ON
|
||||
CONSTANTS A,B
|
||||
E = A*(B*X+Y)^2
|
||||
M = [E;E]
|
||||
EXPAND(E)
|
||||
EXPAND(M)
|
||||
FACTOR(E,X)
|
||||
FACTOR(M,X)
|
||||
|
||||
EQN[1] = A*X + B*Y
|
||||
EQN[2] = 2*A*X - 3*B*Y
|
||||
SOLVE(EQN, X, Y)
|
||||
RHS_Y = RHS(Y)
|
||||
E = (X+Y)^2 + 2*X^2
|
||||
ARRANGE(E, 2, X)
|
||||
|
||||
CONSTANTS A,B,C
|
||||
M = [A,B;C,0]
|
||||
M2 = EVALUATE(M,A=1,B=2,C=3)
|
||||
EIG(M2, EIGVALUE, EIGVEC)
|
||||
|
||||
NEWTONIAN N
|
||||
FRAMES A
|
||||
SIMPROT(N, A, N1>, X)
|
||||
DEGREES OFF
|
||||
SIMPROT(N, A, N1>, PI/2)
|
||||
|
||||
CONSTANTS C{3}
|
||||
V> = C1*A1> + C2*A2> + C3*A3>
|
||||
POINTS O, P
|
||||
P_P_O> = C1*A1>
|
||||
EXPRESS(V>,N)
|
||||
EXPRESS(P_P_O>,N)
|
||||
W_A_N> = C3*A3>
|
||||
ANGVEL(A,N)
|
||||
|
||||
V2PTS(N,A,O,P)
|
||||
PARTICLES P{2}
|
||||
V2PTS(N,A,P1,P2)
|
||||
A2PTS(N,A,P1,P)
|
||||
|
||||
BODIES B{2}
|
||||
CONSTANT G
|
||||
GRAVITY(G*N1>)
|
||||
|
||||
VARIABLE Z
|
||||
V> = X*A1> + Y*A3>
|
||||
P_P_O> = X*A1> + Y*A2>
|
||||
X = 2*Z
|
||||
Y = Z
|
||||
EXPLICIT(V>)
|
||||
EXPLICIT(P_P_O>)
|
||||
|
||||
FORCE(O/P1, X*Y*A1>)
|
||||
FORCE(P2, X*Y*A1>)
|
||||
@@ -0,0 +1,64 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
a, b = _sm.symbols('a b', real=True)
|
||||
e = a*(b*x+y)**2
|
||||
m = _sm.Matrix([e,e]).reshape(2, 1)
|
||||
e = e.expand()
|
||||
m = _sm.Matrix([i.expand() for i in m]).reshape((m).shape[0], (m).shape[1])
|
||||
e = _sm.factor(e, x)
|
||||
m = _sm.Matrix([_sm.factor(i,x) for i in m]).reshape((m).shape[0], (m).shape[1])
|
||||
eqn = _sm.Matrix([[0]])
|
||||
eqn[0] = a*x+b*y
|
||||
eqn = eqn.row_insert(eqn.shape[0], _sm.Matrix([[0]]))
|
||||
eqn[eqn.shape[0]-1] = 2*a*x-3*b*y
|
||||
print(_sm.solve(eqn,x,y))
|
||||
rhs_y = _sm.solve(eqn,x,y)[y]
|
||||
e = (x+y)**2+2*x**2
|
||||
e.collect(x)
|
||||
a, b, c = _sm.symbols('a b c', real=True)
|
||||
m = _sm.Matrix([a,b,c,0]).reshape(2, 2)
|
||||
m2 = _sm.Matrix([i.subs({a:1,b:2,c:3}) for i in m]).reshape((m).shape[0], (m).shape[1])
|
||||
eigvalue = _sm.Matrix([i.evalf() for i in (m2).eigenvals().keys()])
|
||||
eigvec = _sm.Matrix([i[2][0].evalf() for i in (m2).eigenvects()]).reshape(m2.shape[0], m2.shape[1])
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_a.orient(frame_n, 'Axis', [x, frame_n.x])
|
||||
frame_a.orient(frame_n, 'Axis', [_sm.pi/2, frame_n.x])
|
||||
c1, c2, c3 = _sm.symbols('c1 c2 c3', real=True)
|
||||
v = c1*frame_a.x+c2*frame_a.y+c3*frame_a.z
|
||||
point_o = _me.Point('o')
|
||||
point_p = _me.Point('p')
|
||||
point_o.set_pos(point_p, c1*frame_a.x)
|
||||
v = (v).express(frame_n)
|
||||
point_o.set_pos(point_p, (point_o.pos_from(point_p)).express(frame_n))
|
||||
frame_a.set_ang_vel(frame_n, c3*frame_a.z)
|
||||
print(frame_n.ang_vel_in(frame_a))
|
||||
point_p.v2pt_theory(point_o,frame_n,frame_a)
|
||||
particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m'))
|
||||
particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m'))
|
||||
particle_p2.point.v2pt_theory(particle_p1.point,frame_n,frame_a)
|
||||
point_p.a2pt_theory(particle_p1.point,frame_n,frame_a)
|
||||
body_b1_cm = _me.Point('b1_cm')
|
||||
body_b1_cm.set_vel(frame_n, 0)
|
||||
body_b1_f = _me.ReferenceFrame('b1_f')
|
||||
body_b1 = _me.RigidBody('b1', body_b1_cm, body_b1_f, _sm.symbols('m'), (_me.outer(body_b1_f.x,body_b1_f.x),body_b1_cm))
|
||||
body_b2_cm = _me.Point('b2_cm')
|
||||
body_b2_cm.set_vel(frame_n, 0)
|
||||
body_b2_f = _me.ReferenceFrame('b2_f')
|
||||
body_b2 = _me.RigidBody('b2', body_b2_cm, body_b2_f, _sm.symbols('m'), (_me.outer(body_b2_f.x,body_b2_f.x),body_b2_cm))
|
||||
g = _sm.symbols('g', real=True)
|
||||
force_p1 = particle_p1.mass*(g*frame_n.x)
|
||||
force_p2 = particle_p2.mass*(g*frame_n.x)
|
||||
force_b1 = body_b1.mass*(g*frame_n.x)
|
||||
force_b2 = body_b2.mass*(g*frame_n.x)
|
||||
z = _me.dynamicsymbols('z')
|
||||
v = x*frame_a.x+y*frame_a.z
|
||||
point_o.set_pos(point_p, x*frame_a.x+y*frame_a.y)
|
||||
v = (v).subs({x:2*z, y:z})
|
||||
point_o.set_pos(point_p, (point_o.pos_from(point_p)).subs({x:2*z, y:z}))
|
||||
force_o = -1*(x*y*frame_a.x)
|
||||
force_p1 = particle_p1.mass*(g*frame_n.x)+ x*y*frame_a.x
|
||||
@@ -0,0 +1,6 @@
|
||||
VARIABLES X, Y
|
||||
CONSTANTS A{1:2, 1:2}, B{1:2}
|
||||
EQN[1] = A11*x + A12*y - B1
|
||||
EQN[2] = A21*x + A22*y - B2
|
||||
INPUT A11=2, A12=5, A21=3, A22=4, B1=7, B2=6
|
||||
CODE ALGEBRAIC(EQN, X, Y) some_filename.c
|
||||
@@ -0,0 +1,14 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
a11, a12, a21, a22, b1, b2 = _sm.symbols('a11 a12 a21 a22 b1 b2', real=True)
|
||||
eqn = _sm.Matrix([[0]])
|
||||
eqn[0] = a11*x+a12*y-b1
|
||||
eqn = eqn.row_insert(eqn.shape[0], _sm.Matrix([[0]]))
|
||||
eqn[eqn.shape[0]-1] = a21*x+a22*y-b2
|
||||
eqn_list = []
|
||||
for i in eqn: eqn_list.append(i.subs({a11:2, a12:5, a21:3, a22:4, b1:7, b2:6}))
|
||||
print(_sm.linsolve(eqn_list, x,y))
|
||||
@@ -0,0 +1,7 @@
|
||||
VARIABLES X,Y
|
||||
CONSTANTS A,B,R
|
||||
EQN[1] = A*X^3+B*Y^2-R
|
||||
EQN[2] = A*SIN(X)^2 + B*COS(2*Y) - R^2
|
||||
INPUT A=2.0, B=3.0, R=1.0
|
||||
INPUT X = 30 DEG, Y = 3.14
|
||||
CODE NONLINEAR(EQN,X,Y) some_filename.c
|
||||
@@ -0,0 +1,14 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
a, b, r = _sm.symbols('a b r', real=True)
|
||||
eqn = _sm.Matrix([[0]])
|
||||
eqn[0] = a*x**3+b*y**2-r
|
||||
eqn = eqn.row_insert(eqn.shape[0], _sm.Matrix([[0]]))
|
||||
eqn[eqn.shape[0]-1] = a*_sm.sin(x)**2+b*_sm.cos(2*y)-r**2
|
||||
matrix_list = []
|
||||
for i in eqn:matrix_list.append(i.subs({a:2.0, b:3.0, r:1.0}))
|
||||
print(_sm.nsolve(matrix_list,(x,y),(_np.deg2rad(30),3.14)))
|
||||
@@ -0,0 +1,12 @@
|
||||
% ruletest2.al
|
||||
VARIABLES X1,X2
|
||||
SPECIFIED F1 = X1*X2 + 3*X1^2
|
||||
SPECIFIED F2=X1*T+X2*T^2
|
||||
VARIABLE X', Y''
|
||||
MOTIONVARIABLES Q{3}, U{2}
|
||||
VARIABLES P{2}'
|
||||
VARIABLE W{3}', R{2}''
|
||||
VARIABLES C{1:2, 1:2}
|
||||
VARIABLES D{1,3}
|
||||
VARIABLES J{1:2}
|
||||
IMAGINARY N
|
||||
@@ -0,0 +1,22 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
x1, x2 = _me.dynamicsymbols('x1 x2')
|
||||
f1 = x1*x2+3*x1**2
|
||||
f2 = x1*_me.dynamicsymbols._t+x2*_me.dynamicsymbols._t**2
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
x_d, y_d = _me.dynamicsymbols('x_ y_', 1)
|
||||
y_dd = _me.dynamicsymbols('y_', 2)
|
||||
q1, q2, q3, u1, u2 = _me.dynamicsymbols('q1 q2 q3 u1 u2')
|
||||
p1, p2 = _me.dynamicsymbols('p1 p2')
|
||||
p1_d, p2_d = _me.dynamicsymbols('p1_ p2_', 1)
|
||||
w1, w2, w3, r1, r2 = _me.dynamicsymbols('w1 w2 w3 r1 r2')
|
||||
w1_d, w2_d, w3_d, r1_d, r2_d = _me.dynamicsymbols('w1_ w2_ w3_ r1_ r2_', 1)
|
||||
r1_dd, r2_dd = _me.dynamicsymbols('r1_ r2_', 2)
|
||||
c11, c12, c21, c22 = _me.dynamicsymbols('c11 c12 c21 c22')
|
||||
d11, d12, d13 = _me.dynamicsymbols('d11 d12 d13')
|
||||
j1, j2 = _me.dynamicsymbols('j1 j2')
|
||||
n = _sm.symbols('n')
|
||||
n = _sm.I
|
||||
@@ -0,0 +1,25 @@
|
||||
% ruletest3.al
|
||||
FRAMES A, B
|
||||
NEWTONIAN N
|
||||
|
||||
VARIABLES X{3}
|
||||
CONSTANTS L
|
||||
|
||||
V1> = X1*A1> + X2*A2> + X3*A3>
|
||||
V2> = X1*B1> + X2*B2> + X3*B3>
|
||||
V3> = X1*N1> + X2*N2> + X3*N3>
|
||||
|
||||
V> = V1> + V2> + V3>
|
||||
|
||||
POINTS C, D
|
||||
POINTS PO{3}
|
||||
|
||||
PARTICLES L
|
||||
PARTICLES P{3}
|
||||
|
||||
BODIES S
|
||||
BODIES R{2}
|
||||
|
||||
V4> = X1*S1> + X2*S2> + X3*S3>
|
||||
|
||||
P_C_SO> = L*N1>
|
||||
@@ -0,0 +1,37 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_b = _me.ReferenceFrame('b')
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
x1, x2, x3 = _me.dynamicsymbols('x1 x2 x3')
|
||||
l = _sm.symbols('l', real=True)
|
||||
v1 = x1*frame_a.x+x2*frame_a.y+x3*frame_a.z
|
||||
v2 = x1*frame_b.x+x2*frame_b.y+x3*frame_b.z
|
||||
v3 = x1*frame_n.x+x2*frame_n.y+x3*frame_n.z
|
||||
v = v1+v2+v3
|
||||
point_c = _me.Point('c')
|
||||
point_d = _me.Point('d')
|
||||
point_po1 = _me.Point('po1')
|
||||
point_po2 = _me.Point('po2')
|
||||
point_po3 = _me.Point('po3')
|
||||
particle_l = _me.Particle('l', _me.Point('l_pt'), _sm.Symbol('m'))
|
||||
particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m'))
|
||||
particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m'))
|
||||
particle_p3 = _me.Particle('p3', _me.Point('p3_pt'), _sm.Symbol('m'))
|
||||
body_s_cm = _me.Point('s_cm')
|
||||
body_s_cm.set_vel(frame_n, 0)
|
||||
body_s_f = _me.ReferenceFrame('s_f')
|
||||
body_s = _me.RigidBody('s', body_s_cm, body_s_f, _sm.symbols('m'), (_me.outer(body_s_f.x,body_s_f.x),body_s_cm))
|
||||
body_r1_cm = _me.Point('r1_cm')
|
||||
body_r1_cm.set_vel(frame_n, 0)
|
||||
body_r1_f = _me.ReferenceFrame('r1_f')
|
||||
body_r1 = _me.RigidBody('r1', body_r1_cm, body_r1_f, _sm.symbols('m'), (_me.outer(body_r1_f.x,body_r1_f.x),body_r1_cm))
|
||||
body_r2_cm = _me.Point('r2_cm')
|
||||
body_r2_cm.set_vel(frame_n, 0)
|
||||
body_r2_f = _me.ReferenceFrame('r2_f')
|
||||
body_r2 = _me.RigidBody('r2', body_r2_cm, body_r2_f, _sm.symbols('m'), (_me.outer(body_r2_f.x,body_r2_f.x),body_r2_cm))
|
||||
v4 = x1*body_s_f.x+x2*body_s_f.y+x3*body_s_f.z
|
||||
body_s_cm.set_pos(point_c, l*frame_n.x)
|
||||
@@ -0,0 +1,20 @@
|
||||
% ruletest4.al
|
||||
|
||||
FRAMES A, B
|
||||
MOTIONVARIABLES Q{3}
|
||||
SIMPROT(A, B, 1, Q3)
|
||||
DCM = A_B
|
||||
M = DCM*3 - A_B
|
||||
|
||||
VARIABLES R
|
||||
CIRCLE_AREA = PI*R^2
|
||||
|
||||
VARIABLES U, A
|
||||
VARIABLES X, Y
|
||||
S = U*T - 1/2*A*T^2
|
||||
|
||||
EXPR1 = 2*A*0.5 - 1.25 + 0.25
|
||||
EXPR2 = -X^2 + Y^2 + 0.25*(X+Y)^2
|
||||
EXPR3 = 0.5E-10
|
||||
|
||||
DYADIC>> = A1>*A1> + A2>*A2> + A3>*A3>
|
||||
@@ -0,0 +1,20 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_b = _me.ReferenceFrame('b')
|
||||
q1, q2, q3 = _me.dynamicsymbols('q1 q2 q3')
|
||||
frame_b.orient(frame_a, 'Axis', [q3, frame_a.x])
|
||||
dcm = frame_a.dcm(frame_b)
|
||||
m = dcm*3-frame_a.dcm(frame_b)
|
||||
r = _me.dynamicsymbols('r')
|
||||
circle_area = _sm.pi*r**2
|
||||
u, a = _me.dynamicsymbols('u a')
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
s = u*_me.dynamicsymbols._t-1/2*a*_me.dynamicsymbols._t**2
|
||||
expr1 = 2*a*0.5-1.25+0.25
|
||||
expr2 = -1*x**2+y**2+0.25*(x+y)**2
|
||||
expr3 = 0.5*10**(-10)
|
||||
dyadic = _me.outer(frame_a.x, frame_a.x)+_me.outer(frame_a.y, frame_a.y)+_me.outer(frame_a.z, frame_a.z)
|
||||
@@ -0,0 +1,32 @@
|
||||
% ruletest5.al
|
||||
VARIABLES X', Y'
|
||||
|
||||
E1 = (X+Y)^2 + (X-Y)^3
|
||||
E2 = (X-Y)^2
|
||||
E3 = X^2 + Y^2 + 2*X*Y
|
||||
|
||||
M1 = [E1;E2]
|
||||
M2 = [(X+Y)^2,(X-Y)^2]
|
||||
M3 = M1 + [X;Y]
|
||||
|
||||
AM = EXPAND(M1)
|
||||
CM = EXPAND([(X+Y)^2,(X-Y)^2])
|
||||
EM = EXPAND(M1 + [X;Y])
|
||||
F = EXPAND(E1)
|
||||
G = EXPAND(E2)
|
||||
|
||||
A = FACTOR(E3, X)
|
||||
BM = FACTOR(M1, X)
|
||||
CM = FACTOR(M1 + [X;Y], X)
|
||||
|
||||
A = D(E3, X)
|
||||
B = D(E3, Y)
|
||||
CM = D(M2, X)
|
||||
DM = D(M1 + [X;Y], X)
|
||||
FRAMES A, B
|
||||
A_B = [1,0,0;1,0,0;1,0,0]
|
||||
V1> = X*A1> + Y*A2> + X*Y*A3>
|
||||
E> = D(V1>, X, B)
|
||||
FM = DT(M1)
|
||||
GM = DT([(X+Y)^2,(X-Y)^2])
|
||||
H> = DT(V1>, B)
|
||||
@@ -0,0 +1,33 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
x_d, y_d = _me.dynamicsymbols('x_ y_', 1)
|
||||
e1 = (x+y)**2+(x-y)**3
|
||||
e2 = (x-y)**2
|
||||
e3 = x**2+y**2+2*x*y
|
||||
m1 = _sm.Matrix([e1,e2]).reshape(2, 1)
|
||||
m2 = _sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)
|
||||
m3 = m1+_sm.Matrix([x,y]).reshape(2, 1)
|
||||
am = _sm.Matrix([i.expand() for i in m1]).reshape((m1).shape[0], (m1).shape[1])
|
||||
cm = _sm.Matrix([i.expand() for i in _sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)]).reshape((_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[0], (_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[1])
|
||||
em = _sm.Matrix([i.expand() for i in m1+_sm.Matrix([x,y]).reshape(2, 1)]).reshape((m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[0], (m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[1])
|
||||
f = (e1).expand()
|
||||
g = (e2).expand()
|
||||
a = _sm.factor((e3), x)
|
||||
bm = _sm.Matrix([_sm.factor(i, x) for i in m1]).reshape((m1).shape[0], (m1).shape[1])
|
||||
cm = _sm.Matrix([_sm.factor(i, x) for i in m1+_sm.Matrix([x,y]).reshape(2, 1)]).reshape((m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[0], (m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[1])
|
||||
a = (e3).diff(x)
|
||||
b = (e3).diff(y)
|
||||
cm = _sm.Matrix([i.diff(x) for i in m2]).reshape((m2).shape[0], (m2).shape[1])
|
||||
dm = _sm.Matrix([i.diff(x) for i in m1+_sm.Matrix([x,y]).reshape(2, 1)]).reshape((m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[0], (m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[1])
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_b = _me.ReferenceFrame('b')
|
||||
frame_b.orient(frame_a, 'DCM', _sm.Matrix([1,0,0,1,0,0,1,0,0]).reshape(3, 3))
|
||||
v1 = x*frame_a.x+y*frame_a.y+x*y*frame_a.z
|
||||
e = (v1).diff(x, frame_b)
|
||||
fm = _sm.Matrix([i.diff(_sm.Symbol('t')) for i in m1]).reshape((m1).shape[0], (m1).shape[1])
|
||||
gm = _sm.Matrix([i.diff(_sm.Symbol('t')) for i in _sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)]).reshape((_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[0], (_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[1])
|
||||
h = (v1).dt(frame_b)
|
||||
@@ -0,0 +1,41 @@
|
||||
% ruletest6.al
|
||||
VARIABLES Q{2}
|
||||
VARIABLES X,Y,Z
|
||||
Q1 = X^2 + Y^2
|
||||
Q2 = X-Y
|
||||
E = Q1 + Q2
|
||||
A = EXPLICIT(E)
|
||||
E2 = COS(X)
|
||||
E3 = COS(X*Y)
|
||||
A = TAYLOR(E2, 0:2, X=0)
|
||||
B = TAYLOR(E3, 0:2, X=0, Y=0)
|
||||
|
||||
E = EXPAND((X+Y)^2)
|
||||
A = EVALUATE(E, X=1, Y=Z)
|
||||
BM = EVALUATE([E;2*E], X=1, Y=Z)
|
||||
|
||||
E = Q1 + Q2
|
||||
A = EVALUATE(E, X=2, Y=Z^2)
|
||||
|
||||
CONSTANTS J,K,L
|
||||
P1 = POLYNOMIAL([J,K,L],X)
|
||||
P2 = POLYNOMIAL(J*X+K,X,1)
|
||||
|
||||
ROOT1 = ROOTS(P1, X, 2)
|
||||
ROOT2 = ROOTS([1;2;3])
|
||||
|
||||
M = [1,2,3,4;5,6,7,8;9,10,11,12;13,14,15,16]
|
||||
|
||||
AM = TRANSPOSE(M) + M
|
||||
BM = EIG(M)
|
||||
C1 = DIAGMAT(4, 1)
|
||||
C2 = DIAGMAT(3, 4, 2)
|
||||
DM = INV(M+C1)
|
||||
E = DET(M+C1) + TRACE([1,0;0,1])
|
||||
F = ELEMENT(M, 2, 3)
|
||||
|
||||
A = COLS(M)
|
||||
BM = COLS(M, 1)
|
||||
CM = COLS(M, 1, 2:4, 3)
|
||||
DM = ROWS(M, 1)
|
||||
EM = ROWS(M, 1, 2:4, 3)
|
||||
@@ -0,0 +1,36 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
q1, q2 = _me.dynamicsymbols('q1 q2')
|
||||
x, y, z = _me.dynamicsymbols('x y z')
|
||||
e = q1+q2
|
||||
a = (e).subs({q1:x**2+y**2, q2:x-y})
|
||||
e2 = _sm.cos(x)
|
||||
e3 = _sm.cos(x*y)
|
||||
a = (e2).series(x, 0, 2).removeO()
|
||||
b = (e3).series(x, 0, 2).removeO().series(y, 0, 2).removeO()
|
||||
e = ((x+y)**2).expand()
|
||||
a = (e).subs({q1:x**2+y**2,q2:x-y}).subs({x:1,y:z})
|
||||
bm = _sm.Matrix([i.subs({x:1,y:z}) for i in _sm.Matrix([e,2*e]).reshape(2, 1)]).reshape((_sm.Matrix([e,2*e]).reshape(2, 1)).shape[0], (_sm.Matrix([e,2*e]).reshape(2, 1)).shape[1])
|
||||
e = q1+q2
|
||||
a = (e).subs({q1:x**2+y**2,q2:x-y}).subs({x:2,y:z**2})
|
||||
j, k, l = _sm.symbols('j k l', real=True)
|
||||
p1 = _sm.Poly(_sm.Matrix([j,k,l]).reshape(1, 3), x)
|
||||
p2 = _sm.Poly(j*x+k, x)
|
||||
root1 = [i.evalf() for i in _sm.solve(p1, x)]
|
||||
root2 = [i.evalf() for i in _sm.solve(_sm.Poly(_sm.Matrix([1,2,3]).reshape(3, 1), x),x)]
|
||||
m = _sm.Matrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]).reshape(4, 4)
|
||||
am = (m).T+m
|
||||
bm = _sm.Matrix([i.evalf() for i in (m).eigenvals().keys()])
|
||||
c1 = _sm.diag(1,1,1,1)
|
||||
c2 = _sm.Matrix([2 if i==j else 0 for i in range(3) for j in range(4)]).reshape(3, 4)
|
||||
dm = (m+c1)**(-1)
|
||||
e = (m+c1).det()+(_sm.Matrix([1,0,0,1]).reshape(2, 2)).trace()
|
||||
f = (m)[1,2]
|
||||
a = (m).cols
|
||||
bm = (m).col(0)
|
||||
cm = _sm.Matrix([(m).T.row(0),(m).T.row(1),(m).T.row(2),(m).T.row(3),(m).T.row(2)])
|
||||
dm = (m).row(0)
|
||||
em = _sm.Matrix([(m).row(0),(m).row(1),(m).row(2),(m).row(3),(m).row(2)])
|
||||
@@ -0,0 +1,39 @@
|
||||
% ruletest7.al
|
||||
VARIABLES X', Y'
|
||||
E = COS(X) + SIN(X) + TAN(X)&
|
||||
+ COSH(X) + SINH(X) + TANH(X)&
|
||||
+ ACOS(X) + ASIN(X) + ATAN(X)&
|
||||
+ LOG(X) + EXP(X) + SQRT(X)&
|
||||
+ FACTORIAL(X) + CEIL(X) +&
|
||||
FLOOR(X) + SIGN(X)
|
||||
|
||||
E = SQR(X) + LOG10(X)
|
||||
|
||||
A = ABS(-1) + INT(1.5) + ROUND(1.9)
|
||||
|
||||
E1 = 2*X + 3*Y
|
||||
E2 = X + Y
|
||||
|
||||
AM = COEF([E1;E2], [X,Y])
|
||||
B = COEF(E1, X)
|
||||
C = COEF(E2, Y)
|
||||
D1 = EXCLUDE(E1, X)
|
||||
D2 = INCLUDE(E1, X)
|
||||
FM = ARRANGE([E1,E2],2,X)
|
||||
F = ARRANGE(E1, 2, Y)
|
||||
G = REPLACE(E1, X=2*X)
|
||||
GM = REPLACE([E1;E2], X=3)
|
||||
|
||||
FRAMES A, B
|
||||
VARIABLES THETA
|
||||
SIMPROT(A,B,3,THETA)
|
||||
V1> = 2*A1> - 3*A2> + A3>
|
||||
V2> = B1> + B2> + B3>
|
||||
A = DOT(V1>, V2>)
|
||||
BM = DOT(V1>, [V2>;2*V2>])
|
||||
C> = CROSS(V1>,V2>)
|
||||
D = MAG(2*V1>) + MAG(3*V1>)
|
||||
DYADIC>> = 3*A1>*A1> + A2>*A2> + 2*A3>*A3>
|
||||
AM = MATRIX(B, DYADIC>>)
|
||||
M = [1;2;3]
|
||||
V> = VECTOR(A, M)
|
||||
@@ -0,0 +1,35 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
x_d, y_d = _me.dynamicsymbols('x_ y_', 1)
|
||||
e = _sm.cos(x)+_sm.sin(x)+_sm.tan(x)+_sm.cosh(x)+_sm.sinh(x)+_sm.tanh(x)+_sm.acos(x)+_sm.asin(x)+_sm.atan(x)+_sm.log(x)+_sm.exp(x)+_sm.sqrt(x)+_sm.factorial(x)+_sm.ceiling(x)+_sm.floor(x)+_sm.sign(x)
|
||||
e = (x)**2+_sm.log(x, 10)
|
||||
a = _sm.Abs(-1*1)+int(1.5)+round(1.9)
|
||||
e1 = 2*x+3*y
|
||||
e2 = x+y
|
||||
am = _sm.Matrix([e1.expand().coeff(x), e1.expand().coeff(y), e2.expand().coeff(x), e2.expand().coeff(y)]).reshape(2, 2)
|
||||
b = (e1).expand().coeff(x)
|
||||
c = (e2).expand().coeff(y)
|
||||
d1 = (e1).collect(x).coeff(x,0)
|
||||
d2 = (e1).collect(x).coeff(x,1)
|
||||
fm = _sm.Matrix([i.collect(x)for i in _sm.Matrix([e1,e2]).reshape(1, 2)]).reshape((_sm.Matrix([e1,e2]).reshape(1, 2)).shape[0], (_sm.Matrix([e1,e2]).reshape(1, 2)).shape[1])
|
||||
f = (e1).collect(y)
|
||||
g = (e1).subs({x:2*x})
|
||||
gm = _sm.Matrix([i.subs({x:3}) for i in _sm.Matrix([e1,e2]).reshape(2, 1)]).reshape((_sm.Matrix([e1,e2]).reshape(2, 1)).shape[0], (_sm.Matrix([e1,e2]).reshape(2, 1)).shape[1])
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
frame_b = _me.ReferenceFrame('b')
|
||||
theta = _me.dynamicsymbols('theta')
|
||||
frame_b.orient(frame_a, 'Axis', [theta, frame_a.z])
|
||||
v1 = 2*frame_a.x-3*frame_a.y+frame_a.z
|
||||
v2 = frame_b.x+frame_b.y+frame_b.z
|
||||
a = _me.dot(v1, v2)
|
||||
bm = _sm.Matrix([_me.dot(v1, v2),_me.dot(v1, 2*v2)]).reshape(2, 1)
|
||||
c = _me.cross(v1, v2)
|
||||
d = 2*v1.magnitude()+3*v1.magnitude()
|
||||
dyadic = _me.outer(3*frame_a.x, frame_a.x)+_me.outer(frame_a.y, frame_a.y)+_me.outer(2*frame_a.z, frame_a.z)
|
||||
am = (dyadic).to_matrix(frame_b)
|
||||
m = _sm.Matrix([1,2,3]).reshape(3, 1)
|
||||
v = m[0]*frame_a.x +m[1]*frame_a.y +m[2]*frame_a.z
|
||||
@@ -0,0 +1,38 @@
|
||||
% ruletest8.al
|
||||
FRAMES A
|
||||
CONSTANTS C{3}
|
||||
A>> = EXPRESS(1>>,A)
|
||||
PARTICLES P1, P2
|
||||
BODIES R
|
||||
R_A = [1,1,1;1,1,0;0,0,1]
|
||||
POINT O
|
||||
MASS P1=M1, P2=M2, R=MR
|
||||
INERTIA R, I1, I2, I3
|
||||
P_P1_O> = C1*A1>
|
||||
P_P2_O> = C2*A2>
|
||||
P_RO_O> = C3*A3>
|
||||
A>> = EXPRESS(I_P1_O>>, A)
|
||||
A>> = EXPRESS(I_P2_O>>, A)
|
||||
A>> = EXPRESS(I_R_O>>, A)
|
||||
A>> = EXPRESS(INERTIA(O), A)
|
||||
A>> = EXPRESS(INERTIA(O, P1, R), A)
|
||||
A>> = EXPRESS(I_R_O>>, A)
|
||||
A>> = EXPRESS(I_R_RO>>, A)
|
||||
|
||||
P_P1_P2> = C1*A1> + C2*A2>
|
||||
P_P1_RO> = C3*A1>
|
||||
P_P2_RO> = C3*A2>
|
||||
|
||||
B> = CM(O)
|
||||
B> = CM(O, P1, R)
|
||||
B> = CM(P1)
|
||||
|
||||
MOTIONVARIABLES U{3}
|
||||
V> = U1*A1> + U2*A2> + U3*A3>
|
||||
U> = UNITVEC(V> + C1*A1>)
|
||||
V_P1_A> = U1*A1>
|
||||
A> = PARTIALS(V_P1_A>, U1)
|
||||
|
||||
M = MASS(P1,R)
|
||||
M = MASS(P2)
|
||||
M = MASS()
|
||||
@@ -0,0 +1,49 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
c1, c2, c3 = _sm.symbols('c1 c2 c3', real=True)
|
||||
a = _me.inertia(frame_a, 1, 1, 1)
|
||||
particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m'))
|
||||
particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m'))
|
||||
body_r_cm = _me.Point('r_cm')
|
||||
body_r_f = _me.ReferenceFrame('r_f')
|
||||
body_r = _me.RigidBody('r', body_r_cm, body_r_f, _sm.symbols('m'), (_me.outer(body_r_f.x,body_r_f.x),body_r_cm))
|
||||
frame_a.orient(body_r_f, 'DCM', _sm.Matrix([1,1,1,1,1,0,0,0,1]).reshape(3, 3))
|
||||
point_o = _me.Point('o')
|
||||
m1 = _sm.symbols('m1')
|
||||
particle_p1.mass = m1
|
||||
m2 = _sm.symbols('m2')
|
||||
particle_p2.mass = m2
|
||||
mr = _sm.symbols('mr')
|
||||
body_r.mass = mr
|
||||
i1 = _sm.symbols('i1')
|
||||
i2 = _sm.symbols('i2')
|
||||
i3 = _sm.symbols('i3')
|
||||
body_r.inertia = (_me.inertia(body_r_f, i1, i2, i3, 0, 0, 0), body_r_cm)
|
||||
point_o.set_pos(particle_p1.point, c1*frame_a.x)
|
||||
point_o.set_pos(particle_p2.point, c2*frame_a.y)
|
||||
point_o.set_pos(body_r_cm, c3*frame_a.z)
|
||||
a = _me.inertia_of_point_mass(particle_p1.mass, particle_p1.point.pos_from(point_o), frame_a)
|
||||
a = _me.inertia_of_point_mass(particle_p2.mass, particle_p2.point.pos_from(point_o), frame_a)
|
||||
a = body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a)
|
||||
a = _me.inertia_of_point_mass(particle_p1.mass, particle_p1.point.pos_from(point_o), frame_a) + _me.inertia_of_point_mass(particle_p2.mass, particle_p2.point.pos_from(point_o), frame_a) + body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a)
|
||||
a = _me.inertia_of_point_mass(particle_p1.mass, particle_p1.point.pos_from(point_o), frame_a) + body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a)
|
||||
a = body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a)
|
||||
a = body_r.inertia[0]
|
||||
particle_p2.point.set_pos(particle_p1.point, c1*frame_a.x+c2*frame_a.y)
|
||||
body_r_cm.set_pos(particle_p1.point, c3*frame_a.x)
|
||||
body_r_cm.set_pos(particle_p2.point, c3*frame_a.y)
|
||||
b = _me.functions.center_of_mass(point_o,particle_p1, particle_p2, body_r)
|
||||
b = _me.functions.center_of_mass(point_o,particle_p1, body_r)
|
||||
b = _me.functions.center_of_mass(particle_p1.point,particle_p1, particle_p2, body_r)
|
||||
u1, u2, u3 = _me.dynamicsymbols('u1 u2 u3')
|
||||
v = u1*frame_a.x+u2*frame_a.y+u3*frame_a.z
|
||||
u = (v+c1*frame_a.x).normalize()
|
||||
particle_p1.point.set_vel(frame_a, u1*frame_a.x)
|
||||
a = particle_p1.point.partial_velocity(frame_a, u1)
|
||||
m = particle_p1.mass+body_r.mass
|
||||
m = particle_p2.mass
|
||||
m = particle_p1.mass+particle_p2.mass+body_r.mass
|
||||
@@ -0,0 +1,54 @@
|
||||
% ruletest9.al
|
||||
NEWTONIAN N
|
||||
FRAMES A
|
||||
A> = 0>
|
||||
D>> = EXPRESS(1>>, A)
|
||||
|
||||
POINTS PO{2}
|
||||
PARTICLES P{2}
|
||||
MOTIONVARIABLES' C{3}'
|
||||
BODIES R
|
||||
P_P1_PO2> = C1*A1>
|
||||
V> = 2*P_P1_PO2> + C2*A2>
|
||||
|
||||
W_A_N> = C3*A3>
|
||||
V> = 2*W_A_N> + C2*A2>
|
||||
W_R_N> = C3*A3>
|
||||
V> = 2*W_R_N> + C2*A2>
|
||||
|
||||
ALF_A_N> = DT(W_A_N>, A)
|
||||
V> = 2*ALF_A_N> + C2*A2>
|
||||
|
||||
V_P1_A> = C1*A1> + C3*A2>
|
||||
A_RO_N> = C2*A2>
|
||||
V_A> = CROSS(A_RO_N>, V_P1_A>)
|
||||
|
||||
X_B_C> = V_A>
|
||||
X_B_D> = 2*X_B_C>
|
||||
A_B_C_D_E> = X_B_D>*2
|
||||
|
||||
A_B_C = 2*C1*C2*C3
|
||||
A_B_C += 2*C1
|
||||
A_B_C := 3*C1
|
||||
|
||||
MOTIONVARIABLES' Q{2}', U{2}'
|
||||
Q1' = U1
|
||||
Q2' = U2
|
||||
|
||||
VARIABLES X'', Y''
|
||||
SPECIFIED YY
|
||||
Y'' = X*X'^2 + 1
|
||||
YY = X*X'^2 + 1
|
||||
|
||||
M[1] = 2*X
|
||||
M[2] = 2*Y
|
||||
A = 2*M[1]
|
||||
|
||||
M = [1,2,3;4,5,6;7,8,9]
|
||||
M[1, 2] = 5
|
||||
A = M[1, 2]*2
|
||||
|
||||
FORCE_RO> = Q1*N1>
|
||||
TORQUE_A> = Q2*N3>
|
||||
FORCE_RO> = Q2*N2>
|
||||
F> = FORCE_RO>*2
|
||||
@@ -0,0 +1,55 @@
|
||||
import sympy.physics.mechanics as _me
|
||||
import sympy as _sm
|
||||
import math as m
|
||||
import numpy as _np
|
||||
|
||||
frame_n = _me.ReferenceFrame('n')
|
||||
frame_a = _me.ReferenceFrame('a')
|
||||
a = 0
|
||||
d = _me.inertia(frame_a, 1, 1, 1)
|
||||
point_po1 = _me.Point('po1')
|
||||
point_po2 = _me.Point('po2')
|
||||
particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m'))
|
||||
particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m'))
|
||||
c1, c2, c3 = _me.dynamicsymbols('c1 c2 c3')
|
||||
c1_d, c2_d, c3_d = _me.dynamicsymbols('c1_ c2_ c3_', 1)
|
||||
body_r_cm = _me.Point('r_cm')
|
||||
body_r_cm.set_vel(frame_n, 0)
|
||||
body_r_f = _me.ReferenceFrame('r_f')
|
||||
body_r = _me.RigidBody('r', body_r_cm, body_r_f, _sm.symbols('m'), (_me.outer(body_r_f.x,body_r_f.x),body_r_cm))
|
||||
point_po2.set_pos(particle_p1.point, c1*frame_a.x)
|
||||
v = 2*point_po2.pos_from(particle_p1.point)+c2*frame_a.y
|
||||
frame_a.set_ang_vel(frame_n, c3*frame_a.z)
|
||||
v = 2*frame_a.ang_vel_in(frame_n)+c2*frame_a.y
|
||||
body_r_f.set_ang_vel(frame_n, c3*frame_a.z)
|
||||
v = 2*body_r_f.ang_vel_in(frame_n)+c2*frame_a.y
|
||||
frame_a.set_ang_acc(frame_n, (frame_a.ang_vel_in(frame_n)).dt(frame_a))
|
||||
v = 2*frame_a.ang_acc_in(frame_n)+c2*frame_a.y
|
||||
particle_p1.point.set_vel(frame_a, c1*frame_a.x+c3*frame_a.y)
|
||||
body_r_cm.set_acc(frame_n, c2*frame_a.y)
|
||||
v_a = _me.cross(body_r_cm.acc(frame_n), particle_p1.point.vel(frame_a))
|
||||
x_b_c = v_a
|
||||
x_b_d = 2*x_b_c
|
||||
a_b_c_d_e = x_b_d*2
|
||||
a_b_c = 2*c1*c2*c3
|
||||
a_b_c += 2*c1
|
||||
a_b_c = 3*c1
|
||||
q1, q2, u1, u2 = _me.dynamicsymbols('q1 q2 u1 u2')
|
||||
q1_d, q2_d, u1_d, u2_d = _me.dynamicsymbols('q1_ q2_ u1_ u2_', 1)
|
||||
x, y = _me.dynamicsymbols('x y')
|
||||
x_d, y_d = _me.dynamicsymbols('x_ y_', 1)
|
||||
x_dd, y_dd = _me.dynamicsymbols('x_ y_', 2)
|
||||
yy = _me.dynamicsymbols('yy')
|
||||
yy = x*x_d**2+1
|
||||
m = _sm.Matrix([[0]])
|
||||
m[0] = 2*x
|
||||
m = m.row_insert(m.shape[0], _sm.Matrix([[0]]))
|
||||
m[m.shape[0]-1] = 2*y
|
||||
a = 2*m[0]
|
||||
m = _sm.Matrix([1,2,3,4,5,6,7,8,9]).reshape(3, 3)
|
||||
m[0,1] = 5
|
||||
a = m[0, 1]*2
|
||||
force_ro = q1*frame_n.x
|
||||
torque_a = q2*frame_n.z
|
||||
force_ro = q1*frame_n.x + q2*frame_n.y
|
||||
f = force_ro*2
|
||||
@@ -0,0 +1 @@
|
||||
"""Used for translating C source code into a SymPy expression"""
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
"""Used for translating Fortran source code into a SymPy expression. """
|
||||
@@ -0,0 +1,347 @@
|
||||
from sympy.external import import_module
|
||||
|
||||
lfortran = import_module('lfortran')
|
||||
|
||||
if lfortran:
|
||||
from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String,
|
||||
Return, FunctionDefinition, Assignment)
|
||||
from sympy.core import Add, Mul, Integer, Float
|
||||
from sympy.core.symbol import Symbol
|
||||
|
||||
asr_mod = lfortran.asr
|
||||
asr = lfortran.asr.asr
|
||||
src_to_ast = lfortran.ast.src_to_ast
|
||||
ast_to_asr = lfortran.semantic.ast_to_asr.ast_to_asr
|
||||
|
||||
"""
|
||||
This module contains all the necessary Classes and Function used to Parse
|
||||
Fortran code into SymPy expression
|
||||
|
||||
The module and its API are currently under development and experimental.
|
||||
It is also dependent on LFortran for the ASR that is converted to SymPy syntax
|
||||
which is also under development.
|
||||
The module only supports the features currently supported by the LFortran ASR
|
||||
which will be updated as the development of LFortran and this module progresses
|
||||
|
||||
You might find unexpected bugs and exceptions while using the module, feel free
|
||||
to report them to the SymPy Issue Tracker
|
||||
|
||||
The API for the module might also change while in development if better and
|
||||
more effective ways are discovered for the process
|
||||
|
||||
Features Supported
|
||||
==================
|
||||
|
||||
- Variable Declarations (integers and reals)
|
||||
- Function Definitions
|
||||
- Assignments and Basic Binary Operations
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
The module depends on an external dependency
|
||||
|
||||
LFortran : Required to parse Fortran source code into ASR
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://github.com/sympy/sympy/issues
|
||||
.. [2] https://gitlab.com/lfortran/lfortran
|
||||
.. [3] https://docs.lfortran.org/
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class ASR2PyVisitor(asr.ASTVisitor): # type: ignore
|
||||
"""
|
||||
Visitor Class for LFortran ASR
|
||||
|
||||
It is a Visitor class derived from asr.ASRVisitor which visits all the
|
||||
nodes of the LFortran ASR and creates corresponding AST node for each
|
||||
ASR node
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the Parser"""
|
||||
self._py_ast = []
|
||||
|
||||
def visit_TranslationUnit(self, node):
|
||||
"""
|
||||
Function to visit all the elements of the Translation Unit
|
||||
created by LFortran ASR
|
||||
"""
|
||||
for s in node.global_scope.symbols:
|
||||
sym = node.global_scope.symbols[s]
|
||||
self.visit(sym)
|
||||
for item in node.items:
|
||||
self.visit(item)
|
||||
|
||||
def visit_Assignment(self, node):
|
||||
"""Visitor Function for Assignment
|
||||
|
||||
Visits each Assignment is the LFortran ASR and creates corresponding
|
||||
assignment for SymPy.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
The function currently only supports variable assignment and binary
|
||||
operation assignments of varying multitudes. Any type of numberS or
|
||||
array is not supported.
|
||||
|
||||
Raises
|
||||
======
|
||||
|
||||
NotImplementedError() when called for Numeric assignments or Arrays
|
||||
|
||||
"""
|
||||
# TODO: Arithmetic Assignment
|
||||
if isinstance(node.target, asr.Variable):
|
||||
target = node.target
|
||||
value = node.value
|
||||
if isinstance(value, asr.Variable):
|
||||
new_node = Assignment(
|
||||
Variable(
|
||||
target.name
|
||||
),
|
||||
Variable(
|
||||
value.name
|
||||
)
|
||||
)
|
||||
elif (type(value) == asr.BinOp):
|
||||
exp_ast = call_visitor(value)
|
||||
for expr in exp_ast:
|
||||
new_node = Assignment(
|
||||
Variable(target.name),
|
||||
expr
|
||||
)
|
||||
else:
|
||||
raise NotImplementedError("Numeric assignments not supported")
|
||||
else:
|
||||
raise NotImplementedError("Arrays not supported")
|
||||
self._py_ast.append(new_node)
|
||||
|
||||
def visit_BinOp(self, node):
|
||||
"""Visitor Function for Binary Operations
|
||||
|
||||
Visits each binary operation present in the LFortran ASR like addition,
|
||||
subtraction, multiplication, division and creates the corresponding
|
||||
operation node in SymPy's AST
|
||||
|
||||
In case of more than one binary operations, the function calls the
|
||||
call_visitor() function on the child nodes of the binary operations
|
||||
recursively until all the operations have been processed.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
The function currently only supports binary operations with Variables
|
||||
or other binary operations. Numerics are not supported as of yet.
|
||||
|
||||
Raises
|
||||
======
|
||||
|
||||
NotImplementedError() when called for Numeric assignments
|
||||
|
||||
"""
|
||||
# TODO: Integer Binary Operations
|
||||
op = node.op
|
||||
lhs = node.left
|
||||
rhs = node.right
|
||||
|
||||
if (type(lhs) == asr.Variable):
|
||||
left_value = Symbol(lhs.name)
|
||||
elif(type(lhs) == asr.BinOp):
|
||||
l_exp_ast = call_visitor(lhs)
|
||||
for exp in l_exp_ast:
|
||||
left_value = exp
|
||||
else:
|
||||
raise NotImplementedError("Numbers Currently not supported")
|
||||
|
||||
if (type(rhs) == asr.Variable):
|
||||
right_value = Symbol(rhs.name)
|
||||
elif(type(rhs) == asr.BinOp):
|
||||
r_exp_ast = call_visitor(rhs)
|
||||
for exp in r_exp_ast:
|
||||
right_value = exp
|
||||
else:
|
||||
raise NotImplementedError("Numbers Currently not supported")
|
||||
|
||||
if isinstance(op, asr.Add):
|
||||
new_node = Add(left_value, right_value)
|
||||
elif isinstance(op, asr.Sub):
|
||||
new_node = Add(left_value, -right_value)
|
||||
elif isinstance(op, asr.Div):
|
||||
new_node = Mul(left_value, 1/right_value)
|
||||
elif isinstance(op, asr.Mul):
|
||||
new_node = Mul(left_value, right_value)
|
||||
|
||||
self._py_ast.append(new_node)
|
||||
|
||||
def visit_Variable(self, node):
|
||||
"""Visitor Function for Variable Declaration
|
||||
|
||||
Visits each variable declaration present in the ASR and creates a
|
||||
Symbol declaration for each variable
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
The functions currently only support declaration of integer and
|
||||
real variables. Other data types are still under development.
|
||||
|
||||
Raises
|
||||
======
|
||||
|
||||
NotImplementedError() when called for unsupported data types
|
||||
|
||||
"""
|
||||
if isinstance(node.type, asr.Integer):
|
||||
var_type = IntBaseType(String('integer'))
|
||||
value = Integer(0)
|
||||
elif isinstance(node.type, asr.Real):
|
||||
var_type = FloatBaseType(String('real'))
|
||||
value = Float(0.0)
|
||||
else:
|
||||
raise NotImplementedError("Data type not supported")
|
||||
|
||||
if not (node.intent == 'in'):
|
||||
new_node = Variable(
|
||||
node.name
|
||||
).as_Declaration(
|
||||
type = var_type,
|
||||
value = value
|
||||
)
|
||||
self._py_ast.append(new_node)
|
||||
|
||||
def visit_Sequence(self, seq):
|
||||
"""Visitor Function for code sequence
|
||||
|
||||
Visits a code sequence/ block and calls the visitor function on all the
|
||||
children of the code block to create corresponding code in python
|
||||
|
||||
"""
|
||||
if seq is not None:
|
||||
for node in seq:
|
||||
self._py_ast.append(call_visitor(node))
|
||||
|
||||
def visit_Num(self, node):
|
||||
"""Visitor Function for Numbers in ASR
|
||||
|
||||
This function is currently under development and will be updated
|
||||
with improvements in the LFortran ASR
|
||||
|
||||
"""
|
||||
# TODO:Numbers when the LFortran ASR is updated
|
||||
# self._py_ast.append(Integer(node.n))
|
||||
pass
|
||||
|
||||
def visit_Function(self, node):
|
||||
"""Visitor Function for function Definitions
|
||||
|
||||
Visits each function definition present in the ASR and creates a
|
||||
function definition node in the Python AST with all the elements of the
|
||||
given function
|
||||
|
||||
The functions declare all the variables required as SymPy symbols in
|
||||
the function before the function definition
|
||||
|
||||
This function also the call_visior_function to parse the contents of
|
||||
the function body
|
||||
|
||||
"""
|
||||
# TODO: Return statement, variable declaration
|
||||
fn_args = [Variable(arg_iter.name) for arg_iter in node.args]
|
||||
fn_body = []
|
||||
fn_name = node.name
|
||||
for i in node.body:
|
||||
fn_ast = call_visitor(i)
|
||||
try:
|
||||
fn_body_expr = fn_ast
|
||||
except UnboundLocalError:
|
||||
fn_body_expr = []
|
||||
for sym in node.symtab.symbols:
|
||||
decl = call_visitor(node.symtab.symbols[sym])
|
||||
for symbols in decl:
|
||||
fn_body.append(symbols)
|
||||
for elem in fn_body_expr:
|
||||
fn_body.append(elem)
|
||||
fn_body.append(
|
||||
Return(
|
||||
Variable(
|
||||
node.return_var.name
|
||||
)
|
||||
)
|
||||
)
|
||||
if isinstance(node.return_var.type, asr.Integer):
|
||||
ret_type = IntBaseType(String('integer'))
|
||||
elif isinstance(node.return_var.type, asr.Real):
|
||||
ret_type = FloatBaseType(String('real'))
|
||||
else:
|
||||
raise NotImplementedError("Data type not supported")
|
||||
new_node = FunctionDefinition(
|
||||
return_type = ret_type,
|
||||
name = fn_name,
|
||||
parameters = fn_args,
|
||||
body = fn_body
|
||||
)
|
||||
self._py_ast.append(new_node)
|
||||
|
||||
def ret_ast(self):
|
||||
"""Returns the AST nodes"""
|
||||
return self._py_ast
|
||||
else:
|
||||
class ASR2PyVisitor(): # type: ignore
|
||||
def __init__(self, *args, **kwargs):
|
||||
raise ImportError('lfortran not available')
|
||||
|
||||
def call_visitor(fort_node):
|
||||
"""Calls the AST Visitor on the Module
|
||||
|
||||
This function is used to call the AST visitor for a program or module
|
||||
It imports all the required modules and calls the visit() function
|
||||
on the given node
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
fort_node : LFortran ASR object
|
||||
Node for the operation for which the NodeVisitor is called
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
res_ast : list
|
||||
list of SymPy AST Nodes
|
||||
|
||||
"""
|
||||
v = ASR2PyVisitor()
|
||||
v.visit(fort_node)
|
||||
res_ast = v.ret_ast()
|
||||
return res_ast
|
||||
|
||||
|
||||
def src_to_sympy(src):
|
||||
"""Wrapper function to convert the given Fortran source code to SymPy Expressions
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
src : string
|
||||
A string with the Fortran source code
|
||||
|
||||
Returns
|
||||
=======
|
||||
|
||||
py_src : string
|
||||
A string with the Python source code compatible with SymPy
|
||||
|
||||
"""
|
||||
a_ast = src_to_ast(src, translation_unit=False)
|
||||
a = ast_to_asr(a_ast)
|
||||
py_src = call_visitor(a)
|
||||
return py_src
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2016, latex2sympy
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
ANTLR4 LaTeX Math Grammar
|
||||
|
||||
Ported from latex2sympy by @augustt198 https://github.com/augustt198/latex2sympy See license in
|
||||
LICENSE.txt
|
||||
*/
|
||||
|
||||
/*
|
||||
After changing this file, it is necessary to run `python setup.py antlr` in the root directory of
|
||||
the repository. This will regenerate the code in `sympy/parsing/latex/_antlr/*.py`.
|
||||
*/
|
||||
|
||||
grammar LaTeX;
|
||||
|
||||
options {
|
||||
language = Python3;
|
||||
}
|
||||
|
||||
WS: [ \t\r\n]+ -> skip;
|
||||
THINSPACE: ('\\,' | '\\thinspace') -> skip;
|
||||
MEDSPACE: ('\\:' | '\\medspace') -> skip;
|
||||
THICKSPACE: ('\\;' | '\\thickspace') -> skip;
|
||||
QUAD: '\\quad' -> skip;
|
||||
QQUAD: '\\qquad' -> skip;
|
||||
NEGTHINSPACE: ('\\!' | '\\negthinspace') -> skip;
|
||||
NEGMEDSPACE: '\\negmedspace' -> skip;
|
||||
NEGTHICKSPACE: '\\negthickspace' -> skip;
|
||||
CMD_LEFT: '\\left' -> skip;
|
||||
CMD_RIGHT: '\\right' -> skip;
|
||||
|
||||
IGNORE:
|
||||
(
|
||||
'\\vrule'
|
||||
| '\\vcenter'
|
||||
| '\\vbox'
|
||||
| '\\vskip'
|
||||
| '\\vspace'
|
||||
| '\\hfil'
|
||||
| '\\*'
|
||||
| '\\-'
|
||||
| '\\.'
|
||||
| '\\/'
|
||||
| '\\"'
|
||||
| '\\('
|
||||
| '\\='
|
||||
) -> skip;
|
||||
|
||||
ADD: '+';
|
||||
SUB: '-';
|
||||
MUL: '*';
|
||||
DIV: '/';
|
||||
|
||||
L_PAREN: '(';
|
||||
R_PAREN: ')';
|
||||
L_BRACE: '{';
|
||||
R_BRACE: '}';
|
||||
L_BRACE_LITERAL: '\\{';
|
||||
R_BRACE_LITERAL: '\\}';
|
||||
L_BRACKET: '[';
|
||||
R_BRACKET: ']';
|
||||
|
||||
BAR: '|';
|
||||
|
||||
R_BAR: '\\right|';
|
||||
L_BAR: '\\left|';
|
||||
|
||||
L_ANGLE: '\\langle';
|
||||
R_ANGLE: '\\rangle';
|
||||
FUNC_LIM: '\\lim';
|
||||
LIM_APPROACH_SYM:
|
||||
'\\to'
|
||||
| '\\rightarrow'
|
||||
| '\\Rightarrow'
|
||||
| '\\longrightarrow'
|
||||
| '\\Longrightarrow';
|
||||
FUNC_INT:
|
||||
'\\int'
|
||||
| '\\int\\limits';
|
||||
FUNC_SUM: '\\sum';
|
||||
FUNC_PROD: '\\prod';
|
||||
|
||||
FUNC_EXP: '\\exp';
|
||||
FUNC_LOG: '\\log';
|
||||
FUNC_LG: '\\lg';
|
||||
FUNC_LN: '\\ln';
|
||||
FUNC_SIN: '\\sin';
|
||||
FUNC_COS: '\\cos';
|
||||
FUNC_TAN: '\\tan';
|
||||
FUNC_CSC: '\\csc';
|
||||
FUNC_SEC: '\\sec';
|
||||
FUNC_COT: '\\cot';
|
||||
|
||||
FUNC_ARCSIN: '\\arcsin';
|
||||
FUNC_ARCCOS: '\\arccos';
|
||||
FUNC_ARCTAN: '\\arctan';
|
||||
FUNC_ARCCSC: '\\arccsc';
|
||||
FUNC_ARCSEC: '\\arcsec';
|
||||
FUNC_ARCCOT: '\\arccot';
|
||||
|
||||
FUNC_SINH: '\\sinh';
|
||||
FUNC_COSH: '\\cosh';
|
||||
FUNC_TANH: '\\tanh';
|
||||
FUNC_ARSINH: '\\arsinh';
|
||||
FUNC_ARCOSH: '\\arcosh';
|
||||
FUNC_ARTANH: '\\artanh';
|
||||
|
||||
L_FLOOR: '\\lfloor';
|
||||
R_FLOOR: '\\rfloor';
|
||||
L_CEIL: '\\lceil';
|
||||
R_CEIL: '\\rceil';
|
||||
|
||||
FUNC_SQRT: '\\sqrt';
|
||||
FUNC_OVERLINE: '\\overline';
|
||||
|
||||
CMD_TIMES: '\\times';
|
||||
CMD_CDOT: '\\cdot';
|
||||
CMD_DIV: '\\div';
|
||||
CMD_FRAC:
|
||||
'\\frac'
|
||||
| '\\dfrac'
|
||||
| '\\tfrac';
|
||||
CMD_BINOM: '\\binom';
|
||||
CMD_DBINOM: '\\dbinom';
|
||||
CMD_TBINOM: '\\tbinom';
|
||||
|
||||
CMD_MATHIT: '\\mathit';
|
||||
|
||||
UNDERSCORE: '_';
|
||||
CARET: '^';
|
||||
COLON: ':';
|
||||
|
||||
fragment WS_CHAR: [ \t\r\n];
|
||||
DIFFERENTIAL: 'd' WS_CHAR*? ([a-zA-Z] | '\\' [a-zA-Z]+);
|
||||
|
||||
LETTER: [a-zA-Z];
|
||||
DIGIT: [0-9];
|
||||
|
||||
EQUAL: (('&' WS_CHAR*?)? '=') | ('=' (WS_CHAR*? '&')?);
|
||||
NEQ: '\\neq';
|
||||
|
||||
LT: '<';
|
||||
LTE: ('\\leq' | '\\le' | LTE_Q | LTE_S);
|
||||
LTE_Q: '\\leqq';
|
||||
LTE_S: '\\leqslant';
|
||||
|
||||
GT: '>';
|
||||
GTE: ('\\geq' | '\\ge' | GTE_Q | GTE_S);
|
||||
GTE_Q: '\\geqq';
|
||||
GTE_S: '\\geqslant';
|
||||
|
||||
BANG: '!';
|
||||
|
||||
SINGLE_QUOTES: '\''+;
|
||||
|
||||
SYMBOL: '\\' [a-zA-Z]+;
|
||||
|
||||
math: relation;
|
||||
|
||||
relation:
|
||||
relation (EQUAL | LT | LTE | GT | GTE | NEQ) relation
|
||||
| expr;
|
||||
|
||||
equality: expr EQUAL expr;
|
||||
|
||||
expr: additive;
|
||||
|
||||
additive: additive (ADD | SUB) additive | mp;
|
||||
|
||||
// mult part
|
||||
mp:
|
||||
mp (MUL | CMD_TIMES | CMD_CDOT | DIV | CMD_DIV | COLON) mp
|
||||
| unary;
|
||||
|
||||
mp_nofunc:
|
||||
mp_nofunc (
|
||||
MUL
|
||||
| CMD_TIMES
|
||||
| CMD_CDOT
|
||||
| DIV
|
||||
| CMD_DIV
|
||||
| COLON
|
||||
) mp_nofunc
|
||||
| unary_nofunc;
|
||||
|
||||
unary: (ADD | SUB) unary | postfix+;
|
||||
|
||||
unary_nofunc:
|
||||
(ADD | SUB) unary_nofunc
|
||||
| postfix postfix_nofunc*;
|
||||
|
||||
postfix: exp postfix_op*;
|
||||
postfix_nofunc: exp_nofunc postfix_op*;
|
||||
postfix_op: BANG | eval_at;
|
||||
|
||||
eval_at:
|
||||
BAR (eval_at_sup | eval_at_sub | eval_at_sup eval_at_sub);
|
||||
|
||||
eval_at_sub: UNDERSCORE L_BRACE (expr | equality) R_BRACE;
|
||||
|
||||
eval_at_sup: CARET L_BRACE (expr | equality) R_BRACE;
|
||||
|
||||
exp: exp CARET (atom | L_BRACE expr R_BRACE) subexpr? | comp;
|
||||
|
||||
exp_nofunc:
|
||||
exp_nofunc CARET (atom | L_BRACE expr R_BRACE) subexpr?
|
||||
| comp_nofunc;
|
||||
|
||||
comp:
|
||||
group
|
||||
| abs_group
|
||||
| func
|
||||
| atom
|
||||
| floor
|
||||
| ceil;
|
||||
|
||||
comp_nofunc:
|
||||
group
|
||||
| abs_group
|
||||
| atom
|
||||
| floor
|
||||
| ceil;
|
||||
|
||||
group:
|
||||
L_PAREN expr R_PAREN
|
||||
| L_BRACKET expr R_BRACKET
|
||||
| L_BRACE expr R_BRACE
|
||||
| L_BRACE_LITERAL expr R_BRACE_LITERAL;
|
||||
|
||||
abs_group: BAR expr BAR;
|
||||
|
||||
number: DIGIT+ (',' DIGIT DIGIT DIGIT)* ('.' DIGIT+)?;
|
||||
|
||||
atom: (LETTER | SYMBOL) (subexpr? SINGLE_QUOTES? | SINGLE_QUOTES? subexpr?)
|
||||
| number
|
||||
| DIFFERENTIAL
|
||||
| mathit
|
||||
| frac
|
||||
| binom
|
||||
| bra
|
||||
| ket;
|
||||
|
||||
bra: L_ANGLE expr (R_BAR | BAR);
|
||||
ket: (L_BAR | BAR) expr R_ANGLE;
|
||||
|
||||
mathit: CMD_MATHIT L_BRACE mathit_text R_BRACE;
|
||||
mathit_text: LETTER*;
|
||||
|
||||
frac: CMD_FRAC (upperd = DIGIT | L_BRACE upper = expr R_BRACE)
|
||||
(lowerd = DIGIT | L_BRACE lower = expr R_BRACE);
|
||||
|
||||
binom:
|
||||
(CMD_BINOM | CMD_DBINOM | CMD_TBINOM) L_BRACE n = expr R_BRACE L_BRACE k = expr R_BRACE;
|
||||
|
||||
floor: L_FLOOR val = expr R_FLOOR;
|
||||
ceil: L_CEIL val = expr R_CEIL;
|
||||
|
||||
func_normal:
|
||||
FUNC_EXP
|
||||
| FUNC_LOG
|
||||
| FUNC_LG
|
||||
| FUNC_LN
|
||||
| FUNC_SIN
|
||||
| FUNC_COS
|
||||
| FUNC_TAN
|
||||
| FUNC_CSC
|
||||
| FUNC_SEC
|
||||
| FUNC_COT
|
||||
| FUNC_ARCSIN
|
||||
| FUNC_ARCCOS
|
||||
| FUNC_ARCTAN
|
||||
| FUNC_ARCCSC
|
||||
| FUNC_ARCSEC
|
||||
| FUNC_ARCCOT
|
||||
| FUNC_SINH
|
||||
| FUNC_COSH
|
||||
| FUNC_TANH
|
||||
| FUNC_ARSINH
|
||||
| FUNC_ARCOSH
|
||||
| FUNC_ARTANH;
|
||||
|
||||
func:
|
||||
func_normal (subexpr? supexpr? | supexpr? subexpr?) (
|
||||
L_PAREN func_arg R_PAREN
|
||||
| func_arg_noparens
|
||||
)
|
||||
| (LETTER | SYMBOL) (subexpr? SINGLE_QUOTES? | SINGLE_QUOTES? subexpr?) // e.g. f(x), f_1'(x)
|
||||
L_PAREN args R_PAREN
|
||||
| FUNC_INT (subexpr supexpr | supexpr subexpr)? (
|
||||
additive? DIFFERENTIAL
|
||||
| frac
|
||||
| additive
|
||||
)
|
||||
| FUNC_SQRT (L_BRACKET root = expr R_BRACKET)? L_BRACE base = expr R_BRACE
|
||||
| FUNC_OVERLINE L_BRACE base = expr R_BRACE
|
||||
| (FUNC_SUM | FUNC_PROD) (subeq supexpr | supexpr subeq) mp
|
||||
| FUNC_LIM limit_sub mp;
|
||||
|
||||
args: (expr ',' args) | expr;
|
||||
|
||||
limit_sub:
|
||||
UNDERSCORE L_BRACE (LETTER | SYMBOL) LIM_APPROACH_SYM expr (
|
||||
CARET ((L_BRACE (ADD | SUB) R_BRACE) | ADD | SUB)
|
||||
)? R_BRACE;
|
||||
|
||||
func_arg: expr | (expr ',' func_arg);
|
||||
func_arg_noparens: mp_nofunc;
|
||||
|
||||
subexpr: UNDERSCORE (atom | L_BRACE expr R_BRACE);
|
||||
supexpr: CARET (atom | L_BRACE expr R_BRACE);
|
||||
|
||||
subeq: UNDERSCORE L_BRACE equality R_BRACE;
|
||||
supeq: UNDERSCORE L_BRACE equality R_BRACE;
|
||||
@@ -0,0 +1,204 @@
|
||||
from sympy.external import import_module
|
||||
from sympy.utilities.decorator import doctest_depends_on
|
||||
from re import compile as rcompile
|
||||
|
||||
from sympy.parsing.latex.lark import LarkLaTeXParser, TransformToSymPyExpr, parse_latex_lark # noqa
|
||||
|
||||
from .errors import LaTeXParsingError # noqa
|
||||
|
||||
|
||||
IGNORE_L = r"\s*[{]*\s*"
|
||||
IGNORE_R = r"\s*[}]*\s*"
|
||||
NO_LEFT = r"(?<!\\left)"
|
||||
BEGIN_AMS_MAT = r"\\begin{matrix}"
|
||||
END_AMS_MAT = r"\\end{matrix}"
|
||||
BEGIN_ARR = r"\\begin{array}{.*?}"
|
||||
END_ARR = r"\\end{array}"
|
||||
|
||||
# begin_delim_regex: end_delim_regex
|
||||
MATRIX_DELIMS = {fr"\\left\({IGNORE_L}{BEGIN_AMS_MAT}": fr"{END_AMS_MAT}{IGNORE_R}\\right\)",
|
||||
fr"{NO_LEFT}\({IGNORE_L}{BEGIN_AMS_MAT}": fr"{END_AMS_MAT}{IGNORE_R}\)",
|
||||
fr"\\left\[{IGNORE_L}{BEGIN_AMS_MAT}": fr"{END_AMS_MAT}{IGNORE_R}\\right\]",
|
||||
fr"{NO_LEFT}\[{IGNORE_L}{BEGIN_AMS_MAT}": fr"{END_AMS_MAT}{IGNORE_R}\]",
|
||||
fr"\\left\|{IGNORE_L}{BEGIN_AMS_MAT}": fr"{END_AMS_MAT}{IGNORE_R}\\right\|",
|
||||
fr"{NO_LEFT}\|{IGNORE_L}{BEGIN_AMS_MAT}": fr"{END_AMS_MAT}{IGNORE_R}\|",
|
||||
r"\\begin{pmatrix}": r"\\end{pmatrix}",
|
||||
r"\\begin{bmatrix}": r"\\end{bmatrix}",
|
||||
r"\\begin{vmatrix}": r"\\end{vmatrix}",
|
||||
fr"\\left\({IGNORE_L}{BEGIN_ARR}": fr"{END_ARR}{IGNORE_R}\\right\)",
|
||||
fr"{NO_LEFT}\({IGNORE_L}{BEGIN_ARR}": fr"{END_ARR}{IGNORE_R}\)",
|
||||
fr"\\left\[{IGNORE_L}{BEGIN_ARR}": fr"{END_ARR}{IGNORE_R}\\right\]",
|
||||
fr"{NO_LEFT}\[{IGNORE_L}{BEGIN_ARR}": fr"{END_ARR}{IGNORE_R}\]",
|
||||
fr"\\left\|{IGNORE_L}{BEGIN_ARR}": fr"{END_ARR}{IGNORE_R}\\right\|",
|
||||
fr"{NO_LEFT}\|{IGNORE_L}{BEGIN_ARR}": fr"{END_ARR}{IGNORE_R}\|"
|
||||
}
|
||||
|
||||
MATRIX_DELIMS_INV = {v: k for k, v in MATRIX_DELIMS.items()}
|
||||
|
||||
# begin_delim_regex: ideal_begin_delim_representative
|
||||
BEGIN_DELIM_REPR = {fr"\\left\({IGNORE_L}{BEGIN_AMS_MAT}": "\\left(\\begin{matrix}",
|
||||
fr"{NO_LEFT}\({IGNORE_L}{BEGIN_AMS_MAT}": "(\\begin{matrix}",
|
||||
fr"\\left\[{IGNORE_L}{BEGIN_AMS_MAT}": "\\left[\\begin{matrix}",
|
||||
fr"{NO_LEFT}\[{IGNORE_L}{BEGIN_AMS_MAT}": "[\\begin{matrix}",
|
||||
fr"\\left\|{IGNORE_L}{BEGIN_AMS_MAT}": "\\left|\\begin{matrix}",
|
||||
fr"{NO_LEFT}\|{IGNORE_L}{BEGIN_AMS_MAT}": "|\\begin{matrix}",
|
||||
r"\\begin{pmatrix}": "\\begin{pmatrix}",
|
||||
r"\\begin{bmatrix}": "\\begin{bmatrix}",
|
||||
r"\\begin{vmatrix}": "\\begin{vmatrix}",
|
||||
fr"\\left\({IGNORE_L}{BEGIN_ARR}": "\\left(\\begin{array}{COLUMN_SPECIFIERS}",
|
||||
fr"{NO_LEFT}\({IGNORE_L}{BEGIN_ARR}": "(\\begin{array}{COLUMN_SPECIFIERS}",
|
||||
fr"\\left\[{IGNORE_L}{BEGIN_ARR}": "\\left[\\begin{array}{COLUMN_SPECIFIERS}",
|
||||
fr"{NO_LEFT}\[{IGNORE_L}{BEGIN_ARR}": "[\\begin{array}{COLUMN_SPECIFIERS}",
|
||||
fr"\\left\|{IGNORE_L}{BEGIN_ARR}": "\\left|\\begin{array}{COLUMN_SPECIFIERS}",
|
||||
fr"{NO_LEFT}\|{IGNORE_L}{BEGIN_ARR}": "|\\begin{array}{COLUMN_SPECIFIERS}"
|
||||
}
|
||||
|
||||
# end_delim_regex: ideal_end_delim_representative
|
||||
END_DELIM_REPR = {fr"{END_AMS_MAT}{IGNORE_R}\\right\)": "\\end{matrix}\\right)",
|
||||
fr"{END_AMS_MAT}{IGNORE_R}\)": "\\end{matrix})",
|
||||
fr"{END_AMS_MAT}{IGNORE_R}\\right\]": "\\end{matrix}\\right]",
|
||||
fr"{END_AMS_MAT}{IGNORE_R}\]": "\\end{matrix}]",
|
||||
fr"{END_AMS_MAT}{IGNORE_R}\\right\|": "\\end{matrix}\\right|",
|
||||
fr"{END_AMS_MAT}{IGNORE_R}\|": "\\end{matrix}|",
|
||||
r"\\end{pmatrix}": "\\end{pmatrix}",
|
||||
r"\\end{bmatrix}": "\\end{bmatrix}",
|
||||
r"\\end{vmatrix}": "\\end{vmatrix}",
|
||||
fr"{END_ARR}{IGNORE_R}\\right\)": "\\end{array}\\right)",
|
||||
fr"{END_ARR}{IGNORE_R}\)": "\\end{array})",
|
||||
fr"{END_ARR}{IGNORE_R}\\right\]": "\\end{array}\\right]",
|
||||
fr"{END_ARR}{IGNORE_R}\]": "\\end{array}]",
|
||||
fr"{END_ARR}{IGNORE_R}\\right\|": "\\end{array}\\right|",
|
||||
fr"{END_ARR}{IGNORE_R}\|": "\\end{array}|"
|
||||
}
|
||||
|
||||
|
||||
def check_matrix_delimiters(latex_str):
|
||||
"""Report mismatched, excess, or missing matrix delimiters."""
|
||||
spans = []
|
||||
for begin_delim in MATRIX_DELIMS:
|
||||
end_delim = MATRIX_DELIMS[begin_delim]
|
||||
|
||||
p = rcompile(begin_delim)
|
||||
q = rcompile(end_delim)
|
||||
|
||||
spans.extend([(*m.span(), m.group(),
|
||||
begin_delim) for m in p.finditer(latex_str)])
|
||||
spans.extend([(*m.span(), m.group(),
|
||||
end_delim) for m in q.finditer(latex_str)])
|
||||
|
||||
spans.sort(key=(lambda x: x[0]))
|
||||
if len(spans) % 2 == 1:
|
||||
# Odd number of delimiters; therefore something
|
||||
# is wrong. We do not complain yet; let's see if
|
||||
# we can pinpoint the actual error.
|
||||
spans.append((None, None, None, None))
|
||||
|
||||
spans = [(*x, *y) for (x, y) in zip(spans[::2], spans[1::2])]
|
||||
for x in spans:
|
||||
# x is supposed to be an 8-tuple of the following form:
|
||||
#
|
||||
# (begin_delim_span_start, begin_delim_span_end,
|
||||
# begin_delim_match, begin_delim_regex,
|
||||
# end_delim_span_start, end_delim_span_end,
|
||||
# end_delim_match, end_delim_regex)
|
||||
|
||||
sellipsis = "..."
|
||||
s = x[0] - 10
|
||||
if s < 0:
|
||||
s = 0
|
||||
sellipsis = ""
|
||||
|
||||
eellipsis = "..."
|
||||
e = x[1] + 10
|
||||
if e > len(latex_str):
|
||||
e = len(latex_str)
|
||||
eellipsis = ""
|
||||
|
||||
if x[3] in END_DELIM_REPR:
|
||||
err = (f"Extra '{x[2]}' at index {x[0]} or "
|
||||
"missing corresponding "
|
||||
f"'{BEGIN_DELIM_REPR[MATRIX_DELIMS_INV[x[3]]]}' "
|
||||
f"in LaTeX string: {sellipsis}{latex_str[s:e]}"
|
||||
f"{eellipsis}")
|
||||
raise LaTeXParsingError(err)
|
||||
|
||||
if x[7] is None:
|
||||
err = (f"Extra '{x[2]}' at index {x[0]} or "
|
||||
"missing corresponding "
|
||||
f"'{END_DELIM_REPR[MATRIX_DELIMS[x[3]]]}' "
|
||||
f"in LaTeX string: {sellipsis}{latex_str[s:e]}"
|
||||
f"{eellipsis}")
|
||||
raise LaTeXParsingError(err)
|
||||
|
||||
correct_end_regex = MATRIX_DELIMS[x[3]]
|
||||
sellipsis = "..." if x[0] > 0 else ""
|
||||
eellipsis = "..." if x[5] < len(latex_str) else ""
|
||||
if x[7] != correct_end_regex:
|
||||
err = ("Expected "
|
||||
f"'{END_DELIM_REPR[correct_end_regex]}' "
|
||||
f"to close the '{x[2]}' at index {x[0]} but "
|
||||
f"found '{x[6]}' at index {x[4]} of LaTeX "
|
||||
f"string instead: {sellipsis}{latex_str[x[0]:x[5]]}"
|
||||
f"{eellipsis}")
|
||||
raise LaTeXParsingError(err)
|
||||
|
||||
__doctest_requires__ = {('parse_latex',): ['antlr4', 'lark']}
|
||||
|
||||
|
||||
@doctest_depends_on(modules=('antlr4', 'lark'))
|
||||
def parse_latex(s, strict=False, backend="antlr"):
|
||||
r"""Converts the input LaTeX string ``s`` to a SymPy ``Expr``.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
s : str
|
||||
The LaTeX string to parse. In Python source containing LaTeX,
|
||||
*raw strings* (denoted with ``r"``, like this one) are preferred,
|
||||
as LaTeX makes liberal use of the ``\`` character, which would
|
||||
trigger escaping in normal Python strings.
|
||||
backend : str, optional
|
||||
Currently, there are two backends supported: ANTLR, and Lark.
|
||||
The default setting is to use the ANTLR backend, which can be
|
||||
changed to Lark if preferred.
|
||||
|
||||
Use ``backend="antlr"`` for the ANTLR-based parser, and
|
||||
``backend="lark"`` for the Lark-based parser.
|
||||
|
||||
The ``backend`` option is case-sensitive, and must be in
|
||||
all lowercase.
|
||||
strict : bool, optional
|
||||
This option is only available with the ANTLR backend.
|
||||
|
||||
If True, raise an exception if the string cannot be parsed as
|
||||
valid LaTeX. If False, try to recover gracefully from common
|
||||
mistakes.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.parsing.latex import parse_latex
|
||||
>>> expr = parse_latex(r"\frac {1 + \sqrt {\a}} {\b}")
|
||||
>>> expr
|
||||
(sqrt(a) + 1)/b
|
||||
>>> expr.evalf(4, subs=dict(a=5, b=2))
|
||||
1.618
|
||||
>>> func = parse_latex(r"\int_1^\alpha \dfrac{\mathrm{d}t}{t}", backend="lark")
|
||||
>>> func.evalf(subs={"alpha": 2})
|
||||
0.693147180559945
|
||||
"""
|
||||
|
||||
check_matrix_delimiters(s)
|
||||
|
||||
if backend == "antlr":
|
||||
_latex = import_module(
|
||||
'sympy.parsing.latex._parse_latex_antlr',
|
||||
import_kwargs={'fromlist': ['X']})
|
||||
|
||||
if _latex is not None:
|
||||
return _latex.parse_latex(s, strict)
|
||||
elif backend == "lark":
|
||||
return parse_latex_lark(s)
|
||||
else:
|
||||
raise NotImplementedError(f"Using the '{backend}' backend in the LaTeX" \
|
||||
" parser is not supported.")
|
||||
@@ -0,0 +1,9 @@
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated from ../LaTeX.g4, derived from latex2sympy
|
||||
# latex2sympy is licensed under the MIT license
|
||||
# https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
@@ -0,0 +1,512 @@
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated from ../LaTeX.g4, derived from latex2sympy
|
||||
# latex2sympy is licensed under the MIT license
|
||||
# https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
from antlr4 import *
|
||||
from io import StringIO
|
||||
import sys
|
||||
if sys.version_info[1] > 5:
|
||||
from typing import TextIO
|
||||
else:
|
||||
from typing.io import TextIO
|
||||
|
||||
|
||||
def serializedATN():
|
||||
return [
|
||||
4,0,91,911,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
|
||||
2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,
|
||||
13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,
|
||||
19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,
|
||||
26,7,26,2,27,7,27,2,28,7,28,2,29,7,29,2,30,7,30,2,31,7,31,2,32,7,
|
||||
32,2,33,7,33,2,34,7,34,2,35,7,35,2,36,7,36,2,37,7,37,2,38,7,38,2,
|
||||
39,7,39,2,40,7,40,2,41,7,41,2,42,7,42,2,43,7,43,2,44,7,44,2,45,7,
|
||||
45,2,46,7,46,2,47,7,47,2,48,7,48,2,49,7,49,2,50,7,50,2,51,7,51,2,
|
||||
52,7,52,2,53,7,53,2,54,7,54,2,55,7,55,2,56,7,56,2,57,7,57,2,58,7,
|
||||
58,2,59,7,59,2,60,7,60,2,61,7,61,2,62,7,62,2,63,7,63,2,64,7,64,2,
|
||||
65,7,65,2,66,7,66,2,67,7,67,2,68,7,68,2,69,7,69,2,70,7,70,2,71,7,
|
||||
71,2,72,7,72,2,73,7,73,2,74,7,74,2,75,7,75,2,76,7,76,2,77,7,77,2,
|
||||
78,7,78,2,79,7,79,2,80,7,80,2,81,7,81,2,82,7,82,2,83,7,83,2,84,7,
|
||||
84,2,85,7,85,2,86,7,86,2,87,7,87,2,88,7,88,2,89,7,89,2,90,7,90,2,
|
||||
91,7,91,1,0,1,0,1,1,1,1,1,2,4,2,191,8,2,11,2,12,2,192,1,2,1,2,1,
|
||||
3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,3,3,209,8,3,1,3,1,
|
||||
3,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,1,4,3,4,224,8,4,1,4,1,
|
||||
4,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,1,5,3,5,241,8,
|
||||
5,1,5,1,5,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,7,1,7,1,7,1,
|
||||
7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,8,1,
|
||||
8,1,8,1,8,3,8,277,8,8,1,8,1,8,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,9,1,
|
||||
9,1,9,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,10,
|
||||
1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,
|
||||
1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,
|
||||
1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,
|
||||
1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,
|
||||
1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,
|
||||
1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1,13,3,13,
|
||||
381,8,13,1,13,1,13,1,14,1,14,1,15,1,15,1,16,1,16,1,17,1,17,1,18,
|
||||
1,18,1,19,1,19,1,20,1,20,1,21,1,21,1,22,1,22,1,22,1,23,1,23,1,23,
|
||||
1,24,1,24,1,25,1,25,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,27,
|
||||
1,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,29,1,29,1,29,1,29,1,29,
|
||||
1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,31,1,31,
|
||||
1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,
|
||||
1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,
|
||||
1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,
|
||||
1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,1,32,
|
||||
1,32,1,32,1,32,1,32,1,32,1,32,3,32,504,8,32,1,33,1,33,1,33,1,33,
|
||||
1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,3,33,521,
|
||||
8,33,1,34,1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,35,1,35,1,35,1,36,
|
||||
1,36,1,36,1,36,1,36,1,37,1,37,1,37,1,37,1,37,1,38,1,38,1,38,1,38,
|
||||
1,39,1,39,1,39,1,39,1,40,1,40,1,40,1,40,1,40,1,41,1,41,1,41,1,41,
|
||||
1,41,1,42,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,44,1,44,
|
||||
1,44,1,44,1,44,1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,46,1,46,
|
||||
1,46,1,46,1,46,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,47,1,48,1,48,
|
||||
1,48,1,48,1,48,1,48,1,48,1,48,1,49,1,49,1,49,1,49,1,49,1,49,1,49,
|
||||
1,49,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,50,1,51,1,51,1,51,1,51,
|
||||
1,51,1,51,1,51,1,51,1,52,1,52,1,52,1,52,1,52,1,52,1,53,1,53,1,53,
|
||||
1,53,1,53,1,53,1,54,1,54,1,54,1,54,1,54,1,54,1,55,1,55,1,55,1,55,
|
||||
1,55,1,55,1,55,1,55,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,56,1,57,
|
||||
1,57,1,57,1,57,1,57,1,57,1,57,1,57,1,58,1,58,1,58,1,58,1,58,1,58,
|
||||
1,58,1,58,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,59,1,60,1,60,1,60,
|
||||
1,60,1,60,1,60,1,60,1,61,1,61,1,61,1,61,1,61,1,61,1,61,1,62,1,62,
|
||||
1,62,1,62,1,62,1,62,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,1,63,
|
||||
1,63,1,64,1,64,1,64,1,64,1,64,1,64,1,64,1,65,1,65,1,65,1,65,1,65,
|
||||
1,65,1,66,1,66,1,66,1,66,1,66,1,67,1,67,1,67,1,67,1,67,1,67,1,67,
|
||||
1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,1,67,3,67,753,8,67,
|
||||
1,68,1,68,1,68,1,68,1,68,1,68,1,68,1,69,1,69,1,69,1,69,1,69,1,69,
|
||||
1,69,1,69,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,70,1,71,1,71,1,71,
|
||||
1,71,1,71,1,71,1,71,1,71,1,72,1,72,1,73,1,73,1,74,1,74,1,75,1,75,
|
||||
1,76,1,76,5,76,796,8,76,10,76,12,76,799,9,76,1,76,1,76,1,76,4,76,
|
||||
804,8,76,11,76,12,76,805,3,76,808,8,76,1,77,1,77,1,78,1,78,1,79,
|
||||
1,79,5,79,816,8,79,10,79,12,79,819,9,79,3,79,821,8,79,1,79,1,79,
|
||||
1,79,5,79,826,8,79,10,79,12,79,829,9,79,1,79,3,79,832,8,79,3,79,
|
||||
834,8,79,1,80,1,80,1,80,1,80,1,80,1,81,1,81,1,82,1,82,1,82,1,82,
|
||||
1,82,1,82,1,82,1,82,1,82,3,82,852,8,82,1,83,1,83,1,83,1,83,1,83,
|
||||
1,83,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,84,1,85,1,85,
|
||||
1,86,1,86,1,86,1,86,1,86,1,86,1,86,1,86,1,86,3,86,881,8,86,1,87,
|
||||
1,87,1,87,1,87,1,87,1,87,1,88,1,88,1,88,1,88,1,88,1,88,1,88,1,88,
|
||||
1,88,1,88,1,89,1,89,1,90,4,90,902,8,90,11,90,12,90,903,1,91,1,91,
|
||||
4,91,908,8,91,11,91,12,91,909,3,797,817,827,0,92,1,1,3,2,5,3,7,4,
|
||||
9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,27,14,29,15,31,16,
|
||||
33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,49,25,51,26,53,27,
|
||||
55,28,57,29,59,30,61,31,63,32,65,33,67,34,69,35,71,36,73,37,75,38,
|
||||
77,39,79,40,81,41,83,42,85,43,87,44,89,45,91,46,93,47,95,48,97,49,
|
||||
99,50,101,51,103,52,105,53,107,54,109,55,111,56,113,57,115,58,117,
|
||||
59,119,60,121,61,123,62,125,63,127,64,129,65,131,66,133,67,135,68,
|
||||
137,69,139,70,141,71,143,72,145,73,147,74,149,75,151,0,153,76,155,
|
||||
77,157,78,159,79,161,80,163,81,165,82,167,83,169,84,171,85,173,86,
|
||||
175,87,177,88,179,89,181,90,183,91,1,0,3,3,0,9,10,13,13,32,32,2,
|
||||
0,65,90,97,122,1,0,48,57,949,0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,
|
||||
0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,
|
||||
17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,
|
||||
27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,
|
||||
37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,
|
||||
47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,
|
||||
57,1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,
|
||||
67,1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,
|
||||
77,1,0,0,0,0,79,1,0,0,0,0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,
|
||||
87,1,0,0,0,0,89,1,0,0,0,0,91,1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,
|
||||
97,1,0,0,0,0,99,1,0,0,0,0,101,1,0,0,0,0,103,1,0,0,0,0,105,1,0,0,
|
||||
0,0,107,1,0,0,0,0,109,1,0,0,0,0,111,1,0,0,0,0,113,1,0,0,0,0,115,
|
||||
1,0,0,0,0,117,1,0,0,0,0,119,1,0,0,0,0,121,1,0,0,0,0,123,1,0,0,0,
|
||||
0,125,1,0,0,0,0,127,1,0,0,0,0,129,1,0,0,0,0,131,1,0,0,0,0,133,1,
|
||||
0,0,0,0,135,1,0,0,0,0,137,1,0,0,0,0,139,1,0,0,0,0,141,1,0,0,0,0,
|
||||
143,1,0,0,0,0,145,1,0,0,0,0,147,1,0,0,0,0,149,1,0,0,0,0,153,1,0,
|
||||
0,0,0,155,1,0,0,0,0,157,1,0,0,0,0,159,1,0,0,0,0,161,1,0,0,0,0,163,
|
||||
1,0,0,0,0,165,1,0,0,0,0,167,1,0,0,0,0,169,1,0,0,0,0,171,1,0,0,0,
|
||||
0,173,1,0,0,0,0,175,1,0,0,0,0,177,1,0,0,0,0,179,1,0,0,0,0,181,1,
|
||||
0,0,0,0,183,1,0,0,0,1,185,1,0,0,0,3,187,1,0,0,0,5,190,1,0,0,0,7,
|
||||
208,1,0,0,0,9,223,1,0,0,0,11,240,1,0,0,0,13,244,1,0,0,0,15,252,1,
|
||||
0,0,0,17,276,1,0,0,0,19,280,1,0,0,0,21,295,1,0,0,0,23,312,1,0,0,
|
||||
0,25,320,1,0,0,0,27,380,1,0,0,0,29,384,1,0,0,0,31,386,1,0,0,0,33,
|
||||
388,1,0,0,0,35,390,1,0,0,0,37,392,1,0,0,0,39,394,1,0,0,0,41,396,
|
||||
1,0,0,0,43,398,1,0,0,0,45,400,1,0,0,0,47,403,1,0,0,0,49,406,1,0,
|
||||
0,0,51,408,1,0,0,0,53,410,1,0,0,0,55,412,1,0,0,0,57,420,1,0,0,0,
|
||||
59,427,1,0,0,0,61,435,1,0,0,0,63,443,1,0,0,0,65,503,1,0,0,0,67,520,
|
||||
1,0,0,0,69,522,1,0,0,0,71,527,1,0,0,0,73,533,1,0,0,0,75,538,1,0,
|
||||
0,0,77,543,1,0,0,0,79,547,1,0,0,0,81,551,1,0,0,0,83,556,1,0,0,0,
|
||||
85,561,1,0,0,0,87,566,1,0,0,0,89,571,1,0,0,0,91,576,1,0,0,0,93,581,
|
||||
1,0,0,0,95,589,1,0,0,0,97,597,1,0,0,0,99,605,1,0,0,0,101,613,1,0,
|
||||
0,0,103,621,1,0,0,0,105,629,1,0,0,0,107,635,1,0,0,0,109,641,1,0,
|
||||
0,0,111,647,1,0,0,0,113,655,1,0,0,0,115,663,1,0,0,0,117,671,1,0,
|
||||
0,0,119,679,1,0,0,0,121,687,1,0,0,0,123,694,1,0,0,0,125,701,1,0,
|
||||
0,0,127,707,1,0,0,0,129,717,1,0,0,0,131,724,1,0,0,0,133,730,1,0,
|
||||
0,0,135,752,1,0,0,0,137,754,1,0,0,0,139,761,1,0,0,0,141,769,1,0,
|
||||
0,0,143,777,1,0,0,0,145,785,1,0,0,0,147,787,1,0,0,0,149,789,1,0,
|
||||
0,0,151,791,1,0,0,0,153,793,1,0,0,0,155,809,1,0,0,0,157,811,1,0,
|
||||
0,0,159,833,1,0,0,0,161,835,1,0,0,0,163,840,1,0,0,0,165,851,1,0,
|
||||
0,0,167,853,1,0,0,0,169,859,1,0,0,0,171,869,1,0,0,0,173,880,1,0,
|
||||
0,0,175,882,1,0,0,0,177,888,1,0,0,0,179,898,1,0,0,0,181,901,1,0,
|
||||
0,0,183,905,1,0,0,0,185,186,5,44,0,0,186,2,1,0,0,0,187,188,5,46,
|
||||
0,0,188,4,1,0,0,0,189,191,7,0,0,0,190,189,1,0,0,0,191,192,1,0,0,
|
||||
0,192,190,1,0,0,0,192,193,1,0,0,0,193,194,1,0,0,0,194,195,6,2,0,
|
||||
0,195,6,1,0,0,0,196,197,5,92,0,0,197,209,5,44,0,0,198,199,5,92,0,
|
||||
0,199,200,5,116,0,0,200,201,5,104,0,0,201,202,5,105,0,0,202,203,
|
||||
5,110,0,0,203,204,5,115,0,0,204,205,5,112,0,0,205,206,5,97,0,0,206,
|
||||
207,5,99,0,0,207,209,5,101,0,0,208,196,1,0,0,0,208,198,1,0,0,0,209,
|
||||
210,1,0,0,0,210,211,6,3,0,0,211,8,1,0,0,0,212,213,5,92,0,0,213,224,
|
||||
5,58,0,0,214,215,5,92,0,0,215,216,5,109,0,0,216,217,5,101,0,0,217,
|
||||
218,5,100,0,0,218,219,5,115,0,0,219,220,5,112,0,0,220,221,5,97,0,
|
||||
0,221,222,5,99,0,0,222,224,5,101,0,0,223,212,1,0,0,0,223,214,1,0,
|
||||
0,0,224,225,1,0,0,0,225,226,6,4,0,0,226,10,1,0,0,0,227,228,5,92,
|
||||
0,0,228,241,5,59,0,0,229,230,5,92,0,0,230,231,5,116,0,0,231,232,
|
||||
5,104,0,0,232,233,5,105,0,0,233,234,5,99,0,0,234,235,5,107,0,0,235,
|
||||
236,5,115,0,0,236,237,5,112,0,0,237,238,5,97,0,0,238,239,5,99,0,
|
||||
0,239,241,5,101,0,0,240,227,1,0,0,0,240,229,1,0,0,0,241,242,1,0,
|
||||
0,0,242,243,6,5,0,0,243,12,1,0,0,0,244,245,5,92,0,0,245,246,5,113,
|
||||
0,0,246,247,5,117,0,0,247,248,5,97,0,0,248,249,5,100,0,0,249,250,
|
||||
1,0,0,0,250,251,6,6,0,0,251,14,1,0,0,0,252,253,5,92,0,0,253,254,
|
||||
5,113,0,0,254,255,5,113,0,0,255,256,5,117,0,0,256,257,5,97,0,0,257,
|
||||
258,5,100,0,0,258,259,1,0,0,0,259,260,6,7,0,0,260,16,1,0,0,0,261,
|
||||
262,5,92,0,0,262,277,5,33,0,0,263,264,5,92,0,0,264,265,5,110,0,0,
|
||||
265,266,5,101,0,0,266,267,5,103,0,0,267,268,5,116,0,0,268,269,5,
|
||||
104,0,0,269,270,5,105,0,0,270,271,5,110,0,0,271,272,5,115,0,0,272,
|
||||
273,5,112,0,0,273,274,5,97,0,0,274,275,5,99,0,0,275,277,5,101,0,
|
||||
0,276,261,1,0,0,0,276,263,1,0,0,0,277,278,1,0,0,0,278,279,6,8,0,
|
||||
0,279,18,1,0,0,0,280,281,5,92,0,0,281,282,5,110,0,0,282,283,5,101,
|
||||
0,0,283,284,5,103,0,0,284,285,5,109,0,0,285,286,5,101,0,0,286,287,
|
||||
5,100,0,0,287,288,5,115,0,0,288,289,5,112,0,0,289,290,5,97,0,0,290,
|
||||
291,5,99,0,0,291,292,5,101,0,0,292,293,1,0,0,0,293,294,6,9,0,0,294,
|
||||
20,1,0,0,0,295,296,5,92,0,0,296,297,5,110,0,0,297,298,5,101,0,0,
|
||||
298,299,5,103,0,0,299,300,5,116,0,0,300,301,5,104,0,0,301,302,5,
|
||||
105,0,0,302,303,5,99,0,0,303,304,5,107,0,0,304,305,5,115,0,0,305,
|
||||
306,5,112,0,0,306,307,5,97,0,0,307,308,5,99,0,0,308,309,5,101,0,
|
||||
0,309,310,1,0,0,0,310,311,6,10,0,0,311,22,1,0,0,0,312,313,5,92,0,
|
||||
0,313,314,5,108,0,0,314,315,5,101,0,0,315,316,5,102,0,0,316,317,
|
||||
5,116,0,0,317,318,1,0,0,0,318,319,6,11,0,0,319,24,1,0,0,0,320,321,
|
||||
5,92,0,0,321,322,5,114,0,0,322,323,5,105,0,0,323,324,5,103,0,0,324,
|
||||
325,5,104,0,0,325,326,5,116,0,0,326,327,1,0,0,0,327,328,6,12,0,0,
|
||||
328,26,1,0,0,0,329,330,5,92,0,0,330,331,5,118,0,0,331,332,5,114,
|
||||
0,0,332,333,5,117,0,0,333,334,5,108,0,0,334,381,5,101,0,0,335,336,
|
||||
5,92,0,0,336,337,5,118,0,0,337,338,5,99,0,0,338,339,5,101,0,0,339,
|
||||
340,5,110,0,0,340,341,5,116,0,0,341,342,5,101,0,0,342,381,5,114,
|
||||
0,0,343,344,5,92,0,0,344,345,5,118,0,0,345,346,5,98,0,0,346,347,
|
||||
5,111,0,0,347,381,5,120,0,0,348,349,5,92,0,0,349,350,5,118,0,0,350,
|
||||
351,5,115,0,0,351,352,5,107,0,0,352,353,5,105,0,0,353,381,5,112,
|
||||
0,0,354,355,5,92,0,0,355,356,5,118,0,0,356,357,5,115,0,0,357,358,
|
||||
5,112,0,0,358,359,5,97,0,0,359,360,5,99,0,0,360,381,5,101,0,0,361,
|
||||
362,5,92,0,0,362,363,5,104,0,0,363,364,5,102,0,0,364,365,5,105,0,
|
||||
0,365,381,5,108,0,0,366,367,5,92,0,0,367,381,5,42,0,0,368,369,5,
|
||||
92,0,0,369,381,5,45,0,0,370,371,5,92,0,0,371,381,5,46,0,0,372,373,
|
||||
5,92,0,0,373,381,5,47,0,0,374,375,5,92,0,0,375,381,5,34,0,0,376,
|
||||
377,5,92,0,0,377,381,5,40,0,0,378,379,5,92,0,0,379,381,5,61,0,0,
|
||||
380,329,1,0,0,0,380,335,1,0,0,0,380,343,1,0,0,0,380,348,1,0,0,0,
|
||||
380,354,1,0,0,0,380,361,1,0,0,0,380,366,1,0,0,0,380,368,1,0,0,0,
|
||||
380,370,1,0,0,0,380,372,1,0,0,0,380,374,1,0,0,0,380,376,1,0,0,0,
|
||||
380,378,1,0,0,0,381,382,1,0,0,0,382,383,6,13,0,0,383,28,1,0,0,0,
|
||||
384,385,5,43,0,0,385,30,1,0,0,0,386,387,5,45,0,0,387,32,1,0,0,0,
|
||||
388,389,5,42,0,0,389,34,1,0,0,0,390,391,5,47,0,0,391,36,1,0,0,0,
|
||||
392,393,5,40,0,0,393,38,1,0,0,0,394,395,5,41,0,0,395,40,1,0,0,0,
|
||||
396,397,5,123,0,0,397,42,1,0,0,0,398,399,5,125,0,0,399,44,1,0,0,
|
||||
0,400,401,5,92,0,0,401,402,5,123,0,0,402,46,1,0,0,0,403,404,5,92,
|
||||
0,0,404,405,5,125,0,0,405,48,1,0,0,0,406,407,5,91,0,0,407,50,1,0,
|
||||
0,0,408,409,5,93,0,0,409,52,1,0,0,0,410,411,5,124,0,0,411,54,1,0,
|
||||
0,0,412,413,5,92,0,0,413,414,5,114,0,0,414,415,5,105,0,0,415,416,
|
||||
5,103,0,0,416,417,5,104,0,0,417,418,5,116,0,0,418,419,5,124,0,0,
|
||||
419,56,1,0,0,0,420,421,5,92,0,0,421,422,5,108,0,0,422,423,5,101,
|
||||
0,0,423,424,5,102,0,0,424,425,5,116,0,0,425,426,5,124,0,0,426,58,
|
||||
1,0,0,0,427,428,5,92,0,0,428,429,5,108,0,0,429,430,5,97,0,0,430,
|
||||
431,5,110,0,0,431,432,5,103,0,0,432,433,5,108,0,0,433,434,5,101,
|
||||
0,0,434,60,1,0,0,0,435,436,5,92,0,0,436,437,5,114,0,0,437,438,5,
|
||||
97,0,0,438,439,5,110,0,0,439,440,5,103,0,0,440,441,5,108,0,0,441,
|
||||
442,5,101,0,0,442,62,1,0,0,0,443,444,5,92,0,0,444,445,5,108,0,0,
|
||||
445,446,5,105,0,0,446,447,5,109,0,0,447,64,1,0,0,0,448,449,5,92,
|
||||
0,0,449,450,5,116,0,0,450,504,5,111,0,0,451,452,5,92,0,0,452,453,
|
||||
5,114,0,0,453,454,5,105,0,0,454,455,5,103,0,0,455,456,5,104,0,0,
|
||||
456,457,5,116,0,0,457,458,5,97,0,0,458,459,5,114,0,0,459,460,5,114,
|
||||
0,0,460,461,5,111,0,0,461,504,5,119,0,0,462,463,5,92,0,0,463,464,
|
||||
5,82,0,0,464,465,5,105,0,0,465,466,5,103,0,0,466,467,5,104,0,0,467,
|
||||
468,5,116,0,0,468,469,5,97,0,0,469,470,5,114,0,0,470,471,5,114,0,
|
||||
0,471,472,5,111,0,0,472,504,5,119,0,0,473,474,5,92,0,0,474,475,5,
|
||||
108,0,0,475,476,5,111,0,0,476,477,5,110,0,0,477,478,5,103,0,0,478,
|
||||
479,5,114,0,0,479,480,5,105,0,0,480,481,5,103,0,0,481,482,5,104,
|
||||
0,0,482,483,5,116,0,0,483,484,5,97,0,0,484,485,5,114,0,0,485,486,
|
||||
5,114,0,0,486,487,5,111,0,0,487,504,5,119,0,0,488,489,5,92,0,0,489,
|
||||
490,5,76,0,0,490,491,5,111,0,0,491,492,5,110,0,0,492,493,5,103,0,
|
||||
0,493,494,5,114,0,0,494,495,5,105,0,0,495,496,5,103,0,0,496,497,
|
||||
5,104,0,0,497,498,5,116,0,0,498,499,5,97,0,0,499,500,5,114,0,0,500,
|
||||
501,5,114,0,0,501,502,5,111,0,0,502,504,5,119,0,0,503,448,1,0,0,
|
||||
0,503,451,1,0,0,0,503,462,1,0,0,0,503,473,1,0,0,0,503,488,1,0,0,
|
||||
0,504,66,1,0,0,0,505,506,5,92,0,0,506,507,5,105,0,0,507,508,5,110,
|
||||
0,0,508,521,5,116,0,0,509,510,5,92,0,0,510,511,5,105,0,0,511,512,
|
||||
5,110,0,0,512,513,5,116,0,0,513,514,5,92,0,0,514,515,5,108,0,0,515,
|
||||
516,5,105,0,0,516,517,5,109,0,0,517,518,5,105,0,0,518,519,5,116,
|
||||
0,0,519,521,5,115,0,0,520,505,1,0,0,0,520,509,1,0,0,0,521,68,1,0,
|
||||
0,0,522,523,5,92,0,0,523,524,5,115,0,0,524,525,5,117,0,0,525,526,
|
||||
5,109,0,0,526,70,1,0,0,0,527,528,5,92,0,0,528,529,5,112,0,0,529,
|
||||
530,5,114,0,0,530,531,5,111,0,0,531,532,5,100,0,0,532,72,1,0,0,0,
|
||||
533,534,5,92,0,0,534,535,5,101,0,0,535,536,5,120,0,0,536,537,5,112,
|
||||
0,0,537,74,1,0,0,0,538,539,5,92,0,0,539,540,5,108,0,0,540,541,5,
|
||||
111,0,0,541,542,5,103,0,0,542,76,1,0,0,0,543,544,5,92,0,0,544,545,
|
||||
5,108,0,0,545,546,5,103,0,0,546,78,1,0,0,0,547,548,5,92,0,0,548,
|
||||
549,5,108,0,0,549,550,5,110,0,0,550,80,1,0,0,0,551,552,5,92,0,0,
|
||||
552,553,5,115,0,0,553,554,5,105,0,0,554,555,5,110,0,0,555,82,1,0,
|
||||
0,0,556,557,5,92,0,0,557,558,5,99,0,0,558,559,5,111,0,0,559,560,
|
||||
5,115,0,0,560,84,1,0,0,0,561,562,5,92,0,0,562,563,5,116,0,0,563,
|
||||
564,5,97,0,0,564,565,5,110,0,0,565,86,1,0,0,0,566,567,5,92,0,0,567,
|
||||
568,5,99,0,0,568,569,5,115,0,0,569,570,5,99,0,0,570,88,1,0,0,0,571,
|
||||
572,5,92,0,0,572,573,5,115,0,0,573,574,5,101,0,0,574,575,5,99,0,
|
||||
0,575,90,1,0,0,0,576,577,5,92,0,0,577,578,5,99,0,0,578,579,5,111,
|
||||
0,0,579,580,5,116,0,0,580,92,1,0,0,0,581,582,5,92,0,0,582,583,5,
|
||||
97,0,0,583,584,5,114,0,0,584,585,5,99,0,0,585,586,5,115,0,0,586,
|
||||
587,5,105,0,0,587,588,5,110,0,0,588,94,1,0,0,0,589,590,5,92,0,0,
|
||||
590,591,5,97,0,0,591,592,5,114,0,0,592,593,5,99,0,0,593,594,5,99,
|
||||
0,0,594,595,5,111,0,0,595,596,5,115,0,0,596,96,1,0,0,0,597,598,5,
|
||||
92,0,0,598,599,5,97,0,0,599,600,5,114,0,0,600,601,5,99,0,0,601,602,
|
||||
5,116,0,0,602,603,5,97,0,0,603,604,5,110,0,0,604,98,1,0,0,0,605,
|
||||
606,5,92,0,0,606,607,5,97,0,0,607,608,5,114,0,0,608,609,5,99,0,0,
|
||||
609,610,5,99,0,0,610,611,5,115,0,0,611,612,5,99,0,0,612,100,1,0,
|
||||
0,0,613,614,5,92,0,0,614,615,5,97,0,0,615,616,5,114,0,0,616,617,
|
||||
5,99,0,0,617,618,5,115,0,0,618,619,5,101,0,0,619,620,5,99,0,0,620,
|
||||
102,1,0,0,0,621,622,5,92,0,0,622,623,5,97,0,0,623,624,5,114,0,0,
|
||||
624,625,5,99,0,0,625,626,5,99,0,0,626,627,5,111,0,0,627,628,5,116,
|
||||
0,0,628,104,1,0,0,0,629,630,5,92,0,0,630,631,5,115,0,0,631,632,5,
|
||||
105,0,0,632,633,5,110,0,0,633,634,5,104,0,0,634,106,1,0,0,0,635,
|
||||
636,5,92,0,0,636,637,5,99,0,0,637,638,5,111,0,0,638,639,5,115,0,
|
||||
0,639,640,5,104,0,0,640,108,1,0,0,0,641,642,5,92,0,0,642,643,5,116,
|
||||
0,0,643,644,5,97,0,0,644,645,5,110,0,0,645,646,5,104,0,0,646,110,
|
||||
1,0,0,0,647,648,5,92,0,0,648,649,5,97,0,0,649,650,5,114,0,0,650,
|
||||
651,5,115,0,0,651,652,5,105,0,0,652,653,5,110,0,0,653,654,5,104,
|
||||
0,0,654,112,1,0,0,0,655,656,5,92,0,0,656,657,5,97,0,0,657,658,5,
|
||||
114,0,0,658,659,5,99,0,0,659,660,5,111,0,0,660,661,5,115,0,0,661,
|
||||
662,5,104,0,0,662,114,1,0,0,0,663,664,5,92,0,0,664,665,5,97,0,0,
|
||||
665,666,5,114,0,0,666,667,5,116,0,0,667,668,5,97,0,0,668,669,5,110,
|
||||
0,0,669,670,5,104,0,0,670,116,1,0,0,0,671,672,5,92,0,0,672,673,5,
|
||||
108,0,0,673,674,5,102,0,0,674,675,5,108,0,0,675,676,5,111,0,0,676,
|
||||
677,5,111,0,0,677,678,5,114,0,0,678,118,1,0,0,0,679,680,5,92,0,0,
|
||||
680,681,5,114,0,0,681,682,5,102,0,0,682,683,5,108,0,0,683,684,5,
|
||||
111,0,0,684,685,5,111,0,0,685,686,5,114,0,0,686,120,1,0,0,0,687,
|
||||
688,5,92,0,0,688,689,5,108,0,0,689,690,5,99,0,0,690,691,5,101,0,
|
||||
0,691,692,5,105,0,0,692,693,5,108,0,0,693,122,1,0,0,0,694,695,5,
|
||||
92,0,0,695,696,5,114,0,0,696,697,5,99,0,0,697,698,5,101,0,0,698,
|
||||
699,5,105,0,0,699,700,5,108,0,0,700,124,1,0,0,0,701,702,5,92,0,0,
|
||||
702,703,5,115,0,0,703,704,5,113,0,0,704,705,5,114,0,0,705,706,5,
|
||||
116,0,0,706,126,1,0,0,0,707,708,5,92,0,0,708,709,5,111,0,0,709,710,
|
||||
5,118,0,0,710,711,5,101,0,0,711,712,5,114,0,0,712,713,5,108,0,0,
|
||||
713,714,5,105,0,0,714,715,5,110,0,0,715,716,5,101,0,0,716,128,1,
|
||||
0,0,0,717,718,5,92,0,0,718,719,5,116,0,0,719,720,5,105,0,0,720,721,
|
||||
5,109,0,0,721,722,5,101,0,0,722,723,5,115,0,0,723,130,1,0,0,0,724,
|
||||
725,5,92,0,0,725,726,5,99,0,0,726,727,5,100,0,0,727,728,5,111,0,
|
||||
0,728,729,5,116,0,0,729,132,1,0,0,0,730,731,5,92,0,0,731,732,5,100,
|
||||
0,0,732,733,5,105,0,0,733,734,5,118,0,0,734,134,1,0,0,0,735,736,
|
||||
5,92,0,0,736,737,5,102,0,0,737,738,5,114,0,0,738,739,5,97,0,0,739,
|
||||
753,5,99,0,0,740,741,5,92,0,0,741,742,5,100,0,0,742,743,5,102,0,
|
||||
0,743,744,5,114,0,0,744,745,5,97,0,0,745,753,5,99,0,0,746,747,5,
|
||||
92,0,0,747,748,5,116,0,0,748,749,5,102,0,0,749,750,5,114,0,0,750,
|
||||
751,5,97,0,0,751,753,5,99,0,0,752,735,1,0,0,0,752,740,1,0,0,0,752,
|
||||
746,1,0,0,0,753,136,1,0,0,0,754,755,5,92,0,0,755,756,5,98,0,0,756,
|
||||
757,5,105,0,0,757,758,5,110,0,0,758,759,5,111,0,0,759,760,5,109,
|
||||
0,0,760,138,1,0,0,0,761,762,5,92,0,0,762,763,5,100,0,0,763,764,5,
|
||||
98,0,0,764,765,5,105,0,0,765,766,5,110,0,0,766,767,5,111,0,0,767,
|
||||
768,5,109,0,0,768,140,1,0,0,0,769,770,5,92,0,0,770,771,5,116,0,0,
|
||||
771,772,5,98,0,0,772,773,5,105,0,0,773,774,5,110,0,0,774,775,5,111,
|
||||
0,0,775,776,5,109,0,0,776,142,1,0,0,0,777,778,5,92,0,0,778,779,5,
|
||||
109,0,0,779,780,5,97,0,0,780,781,5,116,0,0,781,782,5,104,0,0,782,
|
||||
783,5,105,0,0,783,784,5,116,0,0,784,144,1,0,0,0,785,786,5,95,0,0,
|
||||
786,146,1,0,0,0,787,788,5,94,0,0,788,148,1,0,0,0,789,790,5,58,0,
|
||||
0,790,150,1,0,0,0,791,792,7,0,0,0,792,152,1,0,0,0,793,797,5,100,
|
||||
0,0,794,796,3,151,75,0,795,794,1,0,0,0,796,799,1,0,0,0,797,798,1,
|
||||
0,0,0,797,795,1,0,0,0,798,807,1,0,0,0,799,797,1,0,0,0,800,808,7,
|
||||
1,0,0,801,803,5,92,0,0,802,804,7,1,0,0,803,802,1,0,0,0,804,805,1,
|
||||
0,0,0,805,803,1,0,0,0,805,806,1,0,0,0,806,808,1,0,0,0,807,800,1,
|
||||
0,0,0,807,801,1,0,0,0,808,154,1,0,0,0,809,810,7,1,0,0,810,156,1,
|
||||
0,0,0,811,812,7,2,0,0,812,158,1,0,0,0,813,817,5,38,0,0,814,816,3,
|
||||
151,75,0,815,814,1,0,0,0,816,819,1,0,0,0,817,818,1,0,0,0,817,815,
|
||||
1,0,0,0,818,821,1,0,0,0,819,817,1,0,0,0,820,813,1,0,0,0,820,821,
|
||||
1,0,0,0,821,822,1,0,0,0,822,834,5,61,0,0,823,831,5,61,0,0,824,826,
|
||||
3,151,75,0,825,824,1,0,0,0,826,829,1,0,0,0,827,828,1,0,0,0,827,825,
|
||||
1,0,0,0,828,830,1,0,0,0,829,827,1,0,0,0,830,832,5,38,0,0,831,827,
|
||||
1,0,0,0,831,832,1,0,0,0,832,834,1,0,0,0,833,820,1,0,0,0,833,823,
|
||||
1,0,0,0,834,160,1,0,0,0,835,836,5,92,0,0,836,837,5,110,0,0,837,838,
|
||||
5,101,0,0,838,839,5,113,0,0,839,162,1,0,0,0,840,841,5,60,0,0,841,
|
||||
164,1,0,0,0,842,843,5,92,0,0,843,844,5,108,0,0,844,845,5,101,0,0,
|
||||
845,852,5,113,0,0,846,847,5,92,0,0,847,848,5,108,0,0,848,852,5,101,
|
||||
0,0,849,852,3,167,83,0,850,852,3,169,84,0,851,842,1,0,0,0,851,846,
|
||||
1,0,0,0,851,849,1,0,0,0,851,850,1,0,0,0,852,166,1,0,0,0,853,854,
|
||||
5,92,0,0,854,855,5,108,0,0,855,856,5,101,0,0,856,857,5,113,0,0,857,
|
||||
858,5,113,0,0,858,168,1,0,0,0,859,860,5,92,0,0,860,861,5,108,0,0,
|
||||
861,862,5,101,0,0,862,863,5,113,0,0,863,864,5,115,0,0,864,865,5,
|
||||
108,0,0,865,866,5,97,0,0,866,867,5,110,0,0,867,868,5,116,0,0,868,
|
||||
170,1,0,0,0,869,870,5,62,0,0,870,172,1,0,0,0,871,872,5,92,0,0,872,
|
||||
873,5,103,0,0,873,874,5,101,0,0,874,881,5,113,0,0,875,876,5,92,0,
|
||||
0,876,877,5,103,0,0,877,881,5,101,0,0,878,881,3,175,87,0,879,881,
|
||||
3,177,88,0,880,871,1,0,0,0,880,875,1,0,0,0,880,878,1,0,0,0,880,879,
|
||||
1,0,0,0,881,174,1,0,0,0,882,883,5,92,0,0,883,884,5,103,0,0,884,885,
|
||||
5,101,0,0,885,886,5,113,0,0,886,887,5,113,0,0,887,176,1,0,0,0,888,
|
||||
889,5,92,0,0,889,890,5,103,0,0,890,891,5,101,0,0,891,892,5,113,0,
|
||||
0,892,893,5,115,0,0,893,894,5,108,0,0,894,895,5,97,0,0,895,896,5,
|
||||
110,0,0,896,897,5,116,0,0,897,178,1,0,0,0,898,899,5,33,0,0,899,180,
|
||||
1,0,0,0,900,902,5,39,0,0,901,900,1,0,0,0,902,903,1,0,0,0,903,901,
|
||||
1,0,0,0,903,904,1,0,0,0,904,182,1,0,0,0,905,907,5,92,0,0,906,908,
|
||||
7,1,0,0,907,906,1,0,0,0,908,909,1,0,0,0,909,907,1,0,0,0,909,910,
|
||||
1,0,0,0,910,184,1,0,0,0,22,0,192,208,223,240,276,380,503,520,752,
|
||||
797,805,807,817,820,827,831,833,851,880,903,909,1,6,0,0
|
||||
]
|
||||
|
||||
class LaTeXLexer(Lexer):
|
||||
|
||||
atn = ATNDeserializer().deserialize(serializedATN())
|
||||
|
||||
decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ]
|
||||
|
||||
T__0 = 1
|
||||
T__1 = 2
|
||||
WS = 3
|
||||
THINSPACE = 4
|
||||
MEDSPACE = 5
|
||||
THICKSPACE = 6
|
||||
QUAD = 7
|
||||
QQUAD = 8
|
||||
NEGTHINSPACE = 9
|
||||
NEGMEDSPACE = 10
|
||||
NEGTHICKSPACE = 11
|
||||
CMD_LEFT = 12
|
||||
CMD_RIGHT = 13
|
||||
IGNORE = 14
|
||||
ADD = 15
|
||||
SUB = 16
|
||||
MUL = 17
|
||||
DIV = 18
|
||||
L_PAREN = 19
|
||||
R_PAREN = 20
|
||||
L_BRACE = 21
|
||||
R_BRACE = 22
|
||||
L_BRACE_LITERAL = 23
|
||||
R_BRACE_LITERAL = 24
|
||||
L_BRACKET = 25
|
||||
R_BRACKET = 26
|
||||
BAR = 27
|
||||
R_BAR = 28
|
||||
L_BAR = 29
|
||||
L_ANGLE = 30
|
||||
R_ANGLE = 31
|
||||
FUNC_LIM = 32
|
||||
LIM_APPROACH_SYM = 33
|
||||
FUNC_INT = 34
|
||||
FUNC_SUM = 35
|
||||
FUNC_PROD = 36
|
||||
FUNC_EXP = 37
|
||||
FUNC_LOG = 38
|
||||
FUNC_LG = 39
|
||||
FUNC_LN = 40
|
||||
FUNC_SIN = 41
|
||||
FUNC_COS = 42
|
||||
FUNC_TAN = 43
|
||||
FUNC_CSC = 44
|
||||
FUNC_SEC = 45
|
||||
FUNC_COT = 46
|
||||
FUNC_ARCSIN = 47
|
||||
FUNC_ARCCOS = 48
|
||||
FUNC_ARCTAN = 49
|
||||
FUNC_ARCCSC = 50
|
||||
FUNC_ARCSEC = 51
|
||||
FUNC_ARCCOT = 52
|
||||
FUNC_SINH = 53
|
||||
FUNC_COSH = 54
|
||||
FUNC_TANH = 55
|
||||
FUNC_ARSINH = 56
|
||||
FUNC_ARCOSH = 57
|
||||
FUNC_ARTANH = 58
|
||||
L_FLOOR = 59
|
||||
R_FLOOR = 60
|
||||
L_CEIL = 61
|
||||
R_CEIL = 62
|
||||
FUNC_SQRT = 63
|
||||
FUNC_OVERLINE = 64
|
||||
CMD_TIMES = 65
|
||||
CMD_CDOT = 66
|
||||
CMD_DIV = 67
|
||||
CMD_FRAC = 68
|
||||
CMD_BINOM = 69
|
||||
CMD_DBINOM = 70
|
||||
CMD_TBINOM = 71
|
||||
CMD_MATHIT = 72
|
||||
UNDERSCORE = 73
|
||||
CARET = 74
|
||||
COLON = 75
|
||||
DIFFERENTIAL = 76
|
||||
LETTER = 77
|
||||
DIGIT = 78
|
||||
EQUAL = 79
|
||||
NEQ = 80
|
||||
LT = 81
|
||||
LTE = 82
|
||||
LTE_Q = 83
|
||||
LTE_S = 84
|
||||
GT = 85
|
||||
GTE = 86
|
||||
GTE_Q = 87
|
||||
GTE_S = 88
|
||||
BANG = 89
|
||||
SINGLE_QUOTES = 90
|
||||
SYMBOL = 91
|
||||
|
||||
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
|
||||
|
||||
modeNames = [ "DEFAULT_MODE" ]
|
||||
|
||||
literalNames = [ "<INVALID>",
|
||||
"','", "'.'", "'\\quad'", "'\\qquad'", "'\\negmedspace'", "'\\negthickspace'",
|
||||
"'\\left'", "'\\right'", "'+'", "'-'", "'*'", "'/'", "'('",
|
||||
"')'", "'{'", "'}'", "'\\{'", "'\\}'", "'['", "']'", "'|'",
|
||||
"'\\right|'", "'\\left|'", "'\\langle'", "'\\rangle'", "'\\lim'",
|
||||
"'\\sum'", "'\\prod'", "'\\exp'", "'\\log'", "'\\lg'", "'\\ln'",
|
||||
"'\\sin'", "'\\cos'", "'\\tan'", "'\\csc'", "'\\sec'", "'\\cot'",
|
||||
"'\\arcsin'", "'\\arccos'", "'\\arctan'", "'\\arccsc'", "'\\arcsec'",
|
||||
"'\\arccot'", "'\\sinh'", "'\\cosh'", "'\\tanh'", "'\\arsinh'",
|
||||
"'\\arcosh'", "'\\artanh'", "'\\lfloor'", "'\\rfloor'", "'\\lceil'",
|
||||
"'\\rceil'", "'\\sqrt'", "'\\overline'", "'\\times'", "'\\cdot'",
|
||||
"'\\div'", "'\\binom'", "'\\dbinom'", "'\\tbinom'", "'\\mathit'",
|
||||
"'_'", "'^'", "':'", "'\\neq'", "'<'", "'\\leqq'", "'\\leqslant'",
|
||||
"'>'", "'\\geqq'", "'\\geqslant'", "'!'" ]
|
||||
|
||||
symbolicNames = [ "<INVALID>",
|
||||
"WS", "THINSPACE", "MEDSPACE", "THICKSPACE", "QUAD", "QQUAD",
|
||||
"NEGTHINSPACE", "NEGMEDSPACE", "NEGTHICKSPACE", "CMD_LEFT",
|
||||
"CMD_RIGHT", "IGNORE", "ADD", "SUB", "MUL", "DIV", "L_PAREN",
|
||||
"R_PAREN", "L_BRACE", "R_BRACE", "L_BRACE_LITERAL", "R_BRACE_LITERAL",
|
||||
"L_BRACKET", "R_BRACKET", "BAR", "R_BAR", "L_BAR", "L_ANGLE",
|
||||
"R_ANGLE", "FUNC_LIM", "LIM_APPROACH_SYM", "FUNC_INT", "FUNC_SUM",
|
||||
"FUNC_PROD", "FUNC_EXP", "FUNC_LOG", "FUNC_LG", "FUNC_LN", "FUNC_SIN",
|
||||
"FUNC_COS", "FUNC_TAN", "FUNC_CSC", "FUNC_SEC", "FUNC_COT",
|
||||
"FUNC_ARCSIN", "FUNC_ARCCOS", "FUNC_ARCTAN", "FUNC_ARCCSC",
|
||||
"FUNC_ARCSEC", "FUNC_ARCCOT", "FUNC_SINH", "FUNC_COSH", "FUNC_TANH",
|
||||
"FUNC_ARSINH", "FUNC_ARCOSH", "FUNC_ARTANH", "L_FLOOR", "R_FLOOR",
|
||||
"L_CEIL", "R_CEIL", "FUNC_SQRT", "FUNC_OVERLINE", "CMD_TIMES",
|
||||
"CMD_CDOT", "CMD_DIV", "CMD_FRAC", "CMD_BINOM", "CMD_DBINOM",
|
||||
"CMD_TBINOM", "CMD_MATHIT", "UNDERSCORE", "CARET", "COLON",
|
||||
"DIFFERENTIAL", "LETTER", "DIGIT", "EQUAL", "NEQ", "LT", "LTE",
|
||||
"LTE_Q", "LTE_S", "GT", "GTE", "GTE_Q", "GTE_S", "BANG", "SINGLE_QUOTES",
|
||||
"SYMBOL" ]
|
||||
|
||||
ruleNames = [ "T__0", "T__1", "WS", "THINSPACE", "MEDSPACE", "THICKSPACE",
|
||||
"QUAD", "QQUAD", "NEGTHINSPACE", "NEGMEDSPACE", "NEGTHICKSPACE",
|
||||
"CMD_LEFT", "CMD_RIGHT", "IGNORE", "ADD", "SUB", "MUL",
|
||||
"DIV", "L_PAREN", "R_PAREN", "L_BRACE", "R_BRACE", "L_BRACE_LITERAL",
|
||||
"R_BRACE_LITERAL", "L_BRACKET", "R_BRACKET", "BAR", "R_BAR",
|
||||
"L_BAR", "L_ANGLE", "R_ANGLE", "FUNC_LIM", "LIM_APPROACH_SYM",
|
||||
"FUNC_INT", "FUNC_SUM", "FUNC_PROD", "FUNC_EXP", "FUNC_LOG",
|
||||
"FUNC_LG", "FUNC_LN", "FUNC_SIN", "FUNC_COS", "FUNC_TAN",
|
||||
"FUNC_CSC", "FUNC_SEC", "FUNC_COT", "FUNC_ARCSIN", "FUNC_ARCCOS",
|
||||
"FUNC_ARCTAN", "FUNC_ARCCSC", "FUNC_ARCSEC", "FUNC_ARCCOT",
|
||||
"FUNC_SINH", "FUNC_COSH", "FUNC_TANH", "FUNC_ARSINH",
|
||||
"FUNC_ARCOSH", "FUNC_ARTANH", "L_FLOOR", "R_FLOOR", "L_CEIL",
|
||||
"R_CEIL", "FUNC_SQRT", "FUNC_OVERLINE", "CMD_TIMES", "CMD_CDOT",
|
||||
"CMD_DIV", "CMD_FRAC", "CMD_BINOM", "CMD_DBINOM", "CMD_TBINOM",
|
||||
"CMD_MATHIT", "UNDERSCORE", "CARET", "COLON", "WS_CHAR",
|
||||
"DIFFERENTIAL", "LETTER", "DIGIT", "EQUAL", "NEQ", "LT",
|
||||
"LTE", "LTE_Q", "LTE_S", "GT", "GTE", "GTE_Q", "GTE_S",
|
||||
"BANG", "SINGLE_QUOTES", "SYMBOL" ]
|
||||
|
||||
grammarFileName = "LaTeX.g4"
|
||||
|
||||
def __init__(self, input=None, output:TextIO = sys.stdout):
|
||||
super().__init__(input, output)
|
||||
self.checkVersion("4.11.1")
|
||||
self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache())
|
||||
self._actions = None
|
||||
self._predicates = None
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,91 @@
|
||||
import os
|
||||
import subprocess
|
||||
import glob
|
||||
|
||||
from sympy.utilities.misc import debug
|
||||
|
||||
here = os.path.dirname(__file__)
|
||||
grammar_file = os.path.abspath(os.path.join(here, "LaTeX.g4"))
|
||||
dir_latex_antlr = os.path.join(here, "_antlr")
|
||||
|
||||
header = '''\
|
||||
# *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND ***
|
||||
#
|
||||
# Generated from ../LaTeX.g4, derived from latex2sympy
|
||||
# latex2sympy is licensed under the MIT license
|
||||
# https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt
|
||||
#
|
||||
# Generated with antlr4
|
||||
# antlr4 is licensed under the BSD-3-Clause License
|
||||
# https://github.com/antlr/antlr4/blob/master/LICENSE.txt
|
||||
'''
|
||||
|
||||
|
||||
def check_antlr_version():
|
||||
debug("Checking antlr4 version...")
|
||||
|
||||
try:
|
||||
debug(subprocess.check_output(["antlr4"])
|
||||
.decode('utf-8').split("\n")[0])
|
||||
return True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
debug("The 'antlr4' command line tool is not installed, "
|
||||
"or not on your PATH.\n"
|
||||
"> Please refer to the README.md file for more information.")
|
||||
return False
|
||||
|
||||
|
||||
def build_parser(output_dir=dir_latex_antlr):
|
||||
check_antlr_version()
|
||||
|
||||
debug("Updating ANTLR-generated code in {}".format(output_dir))
|
||||
|
||||
if not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
with open(os.path.join(output_dir, "__init__.py"), "w+") as fp:
|
||||
fp.write(header)
|
||||
|
||||
args = [
|
||||
"antlr4",
|
||||
grammar_file,
|
||||
"-o", output_dir,
|
||||
# for now, not generating these as latex2sympy did not use them
|
||||
"-no-visitor",
|
||||
"-no-listener",
|
||||
]
|
||||
|
||||
debug("Running code generation...\n\t$ {}".format(" ".join(args)))
|
||||
subprocess.check_output(args, cwd=output_dir)
|
||||
|
||||
debug("Applying headers, removing unnecessary files and renaming...")
|
||||
# Handle case insensitive file systems. If the files are already
|
||||
# generated, they will be written to latex* but LaTeX*.* won't match them.
|
||||
for path in (glob.glob(os.path.join(output_dir, "LaTeX*.*")) or
|
||||
glob.glob(os.path.join(output_dir, "latex*.*"))):
|
||||
|
||||
# Remove files ending in .interp or .tokens as they are not needed.
|
||||
if not path.endswith(".py"):
|
||||
os.unlink(path)
|
||||
continue
|
||||
|
||||
new_path = os.path.join(output_dir, os.path.basename(path).lower())
|
||||
with open(path, 'r') as f:
|
||||
lines = [line.rstrip() + '\n' for line in f]
|
||||
|
||||
os.unlink(path)
|
||||
|
||||
with open(new_path, "w") as out_file:
|
||||
offset = 0
|
||||
while lines[offset].startswith('#'):
|
||||
offset += 1
|
||||
out_file.write(header)
|
||||
out_file.writelines(lines[offset:])
|
||||
|
||||
debug("\t{}".format(new_path))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
build_parser()
|
||||
@@ -0,0 +1,607 @@
|
||||
# Ported from latex2sympy by @augustt198
|
||||
# https://github.com/augustt198/latex2sympy
|
||||
# See license in LICENSE.txt
|
||||
from importlib.metadata import version
|
||||
import sympy
|
||||
from sympy.external import import_module
|
||||
from sympy.printing.str import StrPrinter
|
||||
from sympy.physics.quantum.state import Bra, Ket
|
||||
|
||||
from .errors import LaTeXParsingError
|
||||
|
||||
|
||||
LaTeXParser = LaTeXLexer = MathErrorListener = None
|
||||
|
||||
try:
|
||||
LaTeXParser = import_module('sympy.parsing.latex._antlr.latexparser',
|
||||
import_kwargs={'fromlist': ['LaTeXParser']}).LaTeXParser
|
||||
LaTeXLexer = import_module('sympy.parsing.latex._antlr.latexlexer',
|
||||
import_kwargs={'fromlist': ['LaTeXLexer']}).LaTeXLexer
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ErrorListener = import_module('antlr4.error.ErrorListener',
|
||||
warn_not_installed=True,
|
||||
import_kwargs={'fromlist': ['ErrorListener']}
|
||||
)
|
||||
|
||||
|
||||
|
||||
if ErrorListener:
|
||||
class MathErrorListener(ErrorListener.ErrorListener): # type:ignore # noqa:F811
|
||||
def __init__(self, src):
|
||||
super(ErrorListener.ErrorListener, self).__init__()
|
||||
self.src = src
|
||||
|
||||
def syntaxError(self, recog, symbol, line, col, msg, e):
|
||||
fmt = "%s\n%s\n%s"
|
||||
marker = "~" * col + "^"
|
||||
|
||||
if msg.startswith("missing"):
|
||||
err = fmt % (msg, self.src, marker)
|
||||
elif msg.startswith("no viable"):
|
||||
err = fmt % ("I expected something else here", self.src, marker)
|
||||
elif msg.startswith("mismatched"):
|
||||
names = LaTeXParser.literalNames
|
||||
expected = [
|
||||
names[i] for i in e.getExpectedTokens() if i < len(names)
|
||||
]
|
||||
if len(expected) < 10:
|
||||
expected = " ".join(expected)
|
||||
err = (fmt % ("I expected one of these: " + expected, self.src,
|
||||
marker))
|
||||
else:
|
||||
err = (fmt % ("I expected something else here", self.src,
|
||||
marker))
|
||||
else:
|
||||
err = fmt % ("I don't understand this", self.src, marker)
|
||||
raise LaTeXParsingError(err)
|
||||
|
||||
|
||||
def parse_latex(sympy, strict=False):
|
||||
antlr4 = import_module('antlr4')
|
||||
|
||||
if None in [antlr4, MathErrorListener] or \
|
||||
not version('antlr4-python3-runtime').startswith('4.11'):
|
||||
raise ImportError("LaTeX parsing requires the antlr4 Python package,"
|
||||
" provided by pip (antlr4-python3-runtime) or"
|
||||
" conda (antlr-python-runtime), version 4.11")
|
||||
|
||||
sympy = sympy.strip()
|
||||
matherror = MathErrorListener(sympy)
|
||||
|
||||
stream = antlr4.InputStream(sympy)
|
||||
lex = LaTeXLexer(stream)
|
||||
lex.removeErrorListeners()
|
||||
lex.addErrorListener(matherror)
|
||||
|
||||
tokens = antlr4.CommonTokenStream(lex)
|
||||
parser = LaTeXParser(tokens)
|
||||
|
||||
# remove default console error listener
|
||||
parser.removeErrorListeners()
|
||||
parser.addErrorListener(matherror)
|
||||
|
||||
relation = parser.math().relation()
|
||||
if strict and (relation.start.start != 0 or relation.stop.stop != len(sympy) - 1):
|
||||
raise LaTeXParsingError("Invalid LaTeX")
|
||||
expr = convert_relation(relation)
|
||||
|
||||
return expr
|
||||
|
||||
|
||||
def convert_relation(rel):
|
||||
if rel.expr():
|
||||
return convert_expr(rel.expr())
|
||||
|
||||
lh = convert_relation(rel.relation(0))
|
||||
rh = convert_relation(rel.relation(1))
|
||||
if rel.LT():
|
||||
return sympy.StrictLessThan(lh, rh)
|
||||
elif rel.LTE():
|
||||
return sympy.LessThan(lh, rh)
|
||||
elif rel.GT():
|
||||
return sympy.StrictGreaterThan(lh, rh)
|
||||
elif rel.GTE():
|
||||
return sympy.GreaterThan(lh, rh)
|
||||
elif rel.EQUAL():
|
||||
return sympy.Eq(lh, rh)
|
||||
elif rel.NEQ():
|
||||
return sympy.Ne(lh, rh)
|
||||
|
||||
|
||||
def convert_expr(expr):
|
||||
return convert_add(expr.additive())
|
||||
|
||||
|
||||
def convert_add(add):
|
||||
if add.ADD():
|
||||
lh = convert_add(add.additive(0))
|
||||
rh = convert_add(add.additive(1))
|
||||
return sympy.Add(lh, rh, evaluate=False)
|
||||
elif add.SUB():
|
||||
lh = convert_add(add.additive(0))
|
||||
rh = convert_add(add.additive(1))
|
||||
if hasattr(rh, "is_Atom") and rh.is_Atom:
|
||||
return sympy.Add(lh, -1 * rh, evaluate=False)
|
||||
return sympy.Add(lh, sympy.Mul(-1, rh, evaluate=False), evaluate=False)
|
||||
else:
|
||||
return convert_mp(add.mp())
|
||||
|
||||
|
||||
def convert_mp(mp):
|
||||
if hasattr(mp, 'mp'):
|
||||
mp_left = mp.mp(0)
|
||||
mp_right = mp.mp(1)
|
||||
else:
|
||||
mp_left = mp.mp_nofunc(0)
|
||||
mp_right = mp.mp_nofunc(1)
|
||||
|
||||
if mp.MUL() or mp.CMD_TIMES() or mp.CMD_CDOT():
|
||||
lh = convert_mp(mp_left)
|
||||
rh = convert_mp(mp_right)
|
||||
return sympy.Mul(lh, rh, evaluate=False)
|
||||
elif mp.DIV() or mp.CMD_DIV() or mp.COLON():
|
||||
lh = convert_mp(mp_left)
|
||||
rh = convert_mp(mp_right)
|
||||
return sympy.Mul(lh, sympy.Pow(rh, -1, evaluate=False), evaluate=False)
|
||||
else:
|
||||
if hasattr(mp, 'unary'):
|
||||
return convert_unary(mp.unary())
|
||||
else:
|
||||
return convert_unary(mp.unary_nofunc())
|
||||
|
||||
|
||||
def convert_unary(unary):
|
||||
if hasattr(unary, 'unary'):
|
||||
nested_unary = unary.unary()
|
||||
else:
|
||||
nested_unary = unary.unary_nofunc()
|
||||
if hasattr(unary, 'postfix_nofunc'):
|
||||
first = unary.postfix()
|
||||
tail = unary.postfix_nofunc()
|
||||
postfix = [first] + tail
|
||||
else:
|
||||
postfix = unary.postfix()
|
||||
|
||||
if unary.ADD():
|
||||
return convert_unary(nested_unary)
|
||||
elif unary.SUB():
|
||||
numabs = convert_unary(nested_unary)
|
||||
# Use Integer(-n) instead of Mul(-1, n)
|
||||
return -numabs
|
||||
elif postfix:
|
||||
return convert_postfix_list(postfix)
|
||||
|
||||
|
||||
def convert_postfix_list(arr, i=0):
|
||||
if i >= len(arr):
|
||||
raise LaTeXParsingError("Index out of bounds")
|
||||
|
||||
res = convert_postfix(arr[i])
|
||||
if isinstance(res, sympy.Expr):
|
||||
if i == len(arr) - 1:
|
||||
return res # nothing to multiply by
|
||||
else:
|
||||
if i > 0:
|
||||
left = convert_postfix(arr[i - 1])
|
||||
right = convert_postfix(arr[i + 1])
|
||||
if isinstance(left, sympy.Expr) and isinstance(
|
||||
right, sympy.Expr):
|
||||
left_syms = convert_postfix(arr[i - 1]).atoms(sympy.Symbol)
|
||||
right_syms = convert_postfix(arr[i + 1]).atoms(
|
||||
sympy.Symbol)
|
||||
# if the left and right sides contain no variables and the
|
||||
# symbol in between is 'x', treat as multiplication.
|
||||
if not (left_syms or right_syms) and str(res) == 'x':
|
||||
return convert_postfix_list(arr, i + 1)
|
||||
# multiply by next
|
||||
return sympy.Mul(
|
||||
res, convert_postfix_list(arr, i + 1), evaluate=False)
|
||||
else: # must be derivative
|
||||
wrt = res[0]
|
||||
if i == len(arr) - 1:
|
||||
raise LaTeXParsingError("Expected expression for derivative")
|
||||
else:
|
||||
expr = convert_postfix_list(arr, i + 1)
|
||||
return sympy.Derivative(expr, wrt)
|
||||
|
||||
|
||||
def do_subs(expr, at):
|
||||
if at.expr():
|
||||
at_expr = convert_expr(at.expr())
|
||||
syms = at_expr.atoms(sympy.Symbol)
|
||||
if len(syms) == 0:
|
||||
return expr
|
||||
elif len(syms) > 0:
|
||||
sym = next(iter(syms))
|
||||
return expr.subs(sym, at_expr)
|
||||
elif at.equality():
|
||||
lh = convert_expr(at.equality().expr(0))
|
||||
rh = convert_expr(at.equality().expr(1))
|
||||
return expr.subs(lh, rh)
|
||||
|
||||
|
||||
def convert_postfix(postfix):
|
||||
if hasattr(postfix, 'exp'):
|
||||
exp_nested = postfix.exp()
|
||||
else:
|
||||
exp_nested = postfix.exp_nofunc()
|
||||
|
||||
exp = convert_exp(exp_nested)
|
||||
for op in postfix.postfix_op():
|
||||
if op.BANG():
|
||||
if isinstance(exp, list):
|
||||
raise LaTeXParsingError("Cannot apply postfix to derivative")
|
||||
exp = sympy.factorial(exp, evaluate=False)
|
||||
elif op.eval_at():
|
||||
ev = op.eval_at()
|
||||
at_b = None
|
||||
at_a = None
|
||||
if ev.eval_at_sup():
|
||||
at_b = do_subs(exp, ev.eval_at_sup())
|
||||
if ev.eval_at_sub():
|
||||
at_a = do_subs(exp, ev.eval_at_sub())
|
||||
if at_b is not None and at_a is not None:
|
||||
exp = sympy.Add(at_b, -1 * at_a, evaluate=False)
|
||||
elif at_b is not None:
|
||||
exp = at_b
|
||||
elif at_a is not None:
|
||||
exp = at_a
|
||||
|
||||
return exp
|
||||
|
||||
|
||||
def convert_exp(exp):
|
||||
if hasattr(exp, 'exp'):
|
||||
exp_nested = exp.exp()
|
||||
else:
|
||||
exp_nested = exp.exp_nofunc()
|
||||
|
||||
if exp_nested:
|
||||
base = convert_exp(exp_nested)
|
||||
if isinstance(base, list):
|
||||
raise LaTeXParsingError("Cannot raise derivative to power")
|
||||
if exp.atom():
|
||||
exponent = convert_atom(exp.atom())
|
||||
elif exp.expr():
|
||||
exponent = convert_expr(exp.expr())
|
||||
return sympy.Pow(base, exponent, evaluate=False)
|
||||
else:
|
||||
if hasattr(exp, 'comp'):
|
||||
return convert_comp(exp.comp())
|
||||
else:
|
||||
return convert_comp(exp.comp_nofunc())
|
||||
|
||||
|
||||
def convert_comp(comp):
|
||||
if comp.group():
|
||||
return convert_expr(comp.group().expr())
|
||||
elif comp.abs_group():
|
||||
return sympy.Abs(convert_expr(comp.abs_group().expr()), evaluate=False)
|
||||
elif comp.atom():
|
||||
return convert_atom(comp.atom())
|
||||
elif comp.floor():
|
||||
return convert_floor(comp.floor())
|
||||
elif comp.ceil():
|
||||
return convert_ceil(comp.ceil())
|
||||
elif comp.func():
|
||||
return convert_func(comp.func())
|
||||
|
||||
|
||||
def convert_atom(atom):
|
||||
if atom.LETTER():
|
||||
sname = atom.LETTER().getText()
|
||||
if atom.subexpr():
|
||||
if atom.subexpr().expr(): # subscript is expr
|
||||
subscript = convert_expr(atom.subexpr().expr())
|
||||
else: # subscript is atom
|
||||
subscript = convert_atom(atom.subexpr().atom())
|
||||
sname += '_{' + StrPrinter().doprint(subscript) + '}'
|
||||
if atom.SINGLE_QUOTES():
|
||||
sname += atom.SINGLE_QUOTES().getText() # put after subscript for easy identify
|
||||
return sympy.Symbol(sname)
|
||||
elif atom.SYMBOL():
|
||||
s = atom.SYMBOL().getText()[1:]
|
||||
if s == "infty":
|
||||
return sympy.oo
|
||||
else:
|
||||
if atom.subexpr():
|
||||
subscript = None
|
||||
if atom.subexpr().expr(): # subscript is expr
|
||||
subscript = convert_expr(atom.subexpr().expr())
|
||||
else: # subscript is atom
|
||||
subscript = convert_atom(atom.subexpr().atom())
|
||||
subscriptName = StrPrinter().doprint(subscript)
|
||||
s += '_{' + subscriptName + '}'
|
||||
return sympy.Symbol(s)
|
||||
elif atom.number():
|
||||
s = atom.number().getText().replace(",", "")
|
||||
return sympy.Number(s)
|
||||
elif atom.DIFFERENTIAL():
|
||||
var = get_differential_var(atom.DIFFERENTIAL())
|
||||
return sympy.Symbol('d' + var.name)
|
||||
elif atom.mathit():
|
||||
text = rule2text(atom.mathit().mathit_text())
|
||||
return sympy.Symbol(text)
|
||||
elif atom.frac():
|
||||
return convert_frac(atom.frac())
|
||||
elif atom.binom():
|
||||
return convert_binom(atom.binom())
|
||||
elif atom.bra():
|
||||
val = convert_expr(atom.bra().expr())
|
||||
return Bra(val)
|
||||
elif atom.ket():
|
||||
val = convert_expr(atom.ket().expr())
|
||||
return Ket(val)
|
||||
|
||||
|
||||
def rule2text(ctx):
|
||||
stream = ctx.start.getInputStream()
|
||||
# starting index of starting token
|
||||
startIdx = ctx.start.start
|
||||
# stopping index of stopping token
|
||||
stopIdx = ctx.stop.stop
|
||||
|
||||
return stream.getText(startIdx, stopIdx)
|
||||
|
||||
|
||||
def convert_frac(frac):
|
||||
diff_op = False
|
||||
partial_op = False
|
||||
if frac.lower and frac.upper:
|
||||
lower_itv = frac.lower.getSourceInterval()
|
||||
lower_itv_len = lower_itv[1] - lower_itv[0] + 1
|
||||
if (frac.lower.start == frac.lower.stop
|
||||
and frac.lower.start.type == LaTeXLexer.DIFFERENTIAL):
|
||||
wrt = get_differential_var_str(frac.lower.start.text)
|
||||
diff_op = True
|
||||
elif (lower_itv_len == 2 and frac.lower.start.type == LaTeXLexer.SYMBOL
|
||||
and frac.lower.start.text == '\\partial'
|
||||
and (frac.lower.stop.type == LaTeXLexer.LETTER
|
||||
or frac.lower.stop.type == LaTeXLexer.SYMBOL)):
|
||||
partial_op = True
|
||||
wrt = frac.lower.stop.text
|
||||
if frac.lower.stop.type == LaTeXLexer.SYMBOL:
|
||||
wrt = wrt[1:]
|
||||
|
||||
if diff_op or partial_op:
|
||||
wrt = sympy.Symbol(wrt)
|
||||
if (diff_op and frac.upper.start == frac.upper.stop
|
||||
and frac.upper.start.type == LaTeXLexer.LETTER
|
||||
and frac.upper.start.text == 'd'):
|
||||
return [wrt]
|
||||
elif (partial_op and frac.upper.start == frac.upper.stop
|
||||
and frac.upper.start.type == LaTeXLexer.SYMBOL
|
||||
and frac.upper.start.text == '\\partial'):
|
||||
return [wrt]
|
||||
upper_text = rule2text(frac.upper)
|
||||
|
||||
expr_top = None
|
||||
if diff_op and upper_text.startswith('d'):
|
||||
expr_top = parse_latex(upper_text[1:])
|
||||
elif partial_op and frac.upper.start.text == '\\partial':
|
||||
expr_top = parse_latex(upper_text[len('\\partial'):])
|
||||
if expr_top:
|
||||
return sympy.Derivative(expr_top, wrt)
|
||||
if frac.upper:
|
||||
expr_top = convert_expr(frac.upper)
|
||||
else:
|
||||
expr_top = sympy.Number(frac.upperd.text)
|
||||
if frac.lower:
|
||||
expr_bot = convert_expr(frac.lower)
|
||||
else:
|
||||
expr_bot = sympy.Number(frac.lowerd.text)
|
||||
inverse_denom = sympy.Pow(expr_bot, -1, evaluate=False)
|
||||
if expr_top == 1:
|
||||
return inverse_denom
|
||||
else:
|
||||
return sympy.Mul(expr_top, inverse_denom, evaluate=False)
|
||||
|
||||
def convert_binom(binom):
|
||||
expr_n = convert_expr(binom.n)
|
||||
expr_k = convert_expr(binom.k)
|
||||
return sympy.binomial(expr_n, expr_k, evaluate=False)
|
||||
|
||||
def convert_floor(floor):
|
||||
val = convert_expr(floor.val)
|
||||
return sympy.floor(val, evaluate=False)
|
||||
|
||||
def convert_ceil(ceil):
|
||||
val = convert_expr(ceil.val)
|
||||
return sympy.ceiling(val, evaluate=False)
|
||||
|
||||
def convert_func(func):
|
||||
if func.func_normal():
|
||||
if func.L_PAREN(): # function called with parenthesis
|
||||
arg = convert_func_arg(func.func_arg())
|
||||
else:
|
||||
arg = convert_func_arg(func.func_arg_noparens())
|
||||
|
||||
name = func.func_normal().start.text[1:]
|
||||
|
||||
# change arc<trig> -> a<trig>
|
||||
if name in [
|
||||
"arcsin", "arccos", "arctan", "arccsc", "arcsec", "arccot"
|
||||
]:
|
||||
name = "a" + name[3:]
|
||||
expr = getattr(sympy.functions, name)(arg, evaluate=False)
|
||||
if name in ["arsinh", "arcosh", "artanh"]:
|
||||
name = "a" + name[2:]
|
||||
expr = getattr(sympy.functions, name)(arg, evaluate=False)
|
||||
|
||||
if name == "exp":
|
||||
expr = sympy.exp(arg, evaluate=False)
|
||||
|
||||
if name in ("log", "lg", "ln"):
|
||||
if func.subexpr():
|
||||
if func.subexpr().expr():
|
||||
base = convert_expr(func.subexpr().expr())
|
||||
else:
|
||||
base = convert_atom(func.subexpr().atom())
|
||||
elif name == "lg": # ISO 80000-2:2019
|
||||
base = 10
|
||||
elif name in ("ln", "log"): # SymPy's latex printer prints ln as log by default
|
||||
base = sympy.E
|
||||
expr = sympy.log(arg, base, evaluate=False)
|
||||
|
||||
func_pow = None
|
||||
should_pow = True
|
||||
if func.supexpr():
|
||||
if func.supexpr().expr():
|
||||
func_pow = convert_expr(func.supexpr().expr())
|
||||
else:
|
||||
func_pow = convert_atom(func.supexpr().atom())
|
||||
|
||||
if name in [
|
||||
"sin", "cos", "tan", "csc", "sec", "cot", "sinh", "cosh",
|
||||
"tanh"
|
||||
]:
|
||||
if func_pow == -1:
|
||||
name = "a" + name
|
||||
should_pow = False
|
||||
expr = getattr(sympy.functions, name)(arg, evaluate=False)
|
||||
|
||||
if func_pow and should_pow:
|
||||
expr = sympy.Pow(expr, func_pow, evaluate=False)
|
||||
|
||||
return expr
|
||||
elif func.LETTER() or func.SYMBOL():
|
||||
if func.LETTER():
|
||||
fname = func.LETTER().getText()
|
||||
elif func.SYMBOL():
|
||||
fname = func.SYMBOL().getText()[1:]
|
||||
fname = str(fname) # can't be unicode
|
||||
if func.subexpr():
|
||||
if func.subexpr().expr(): # subscript is expr
|
||||
subscript = convert_expr(func.subexpr().expr())
|
||||
else: # subscript is atom
|
||||
subscript = convert_atom(func.subexpr().atom())
|
||||
subscriptName = StrPrinter().doprint(subscript)
|
||||
fname += '_{' + subscriptName + '}'
|
||||
if func.SINGLE_QUOTES():
|
||||
fname += func.SINGLE_QUOTES().getText()
|
||||
input_args = func.args()
|
||||
output_args = []
|
||||
while input_args.args(): # handle multiple arguments to function
|
||||
output_args.append(convert_expr(input_args.expr()))
|
||||
input_args = input_args.args()
|
||||
output_args.append(convert_expr(input_args.expr()))
|
||||
return sympy.Function(fname)(*output_args)
|
||||
elif func.FUNC_INT():
|
||||
return handle_integral(func)
|
||||
elif func.FUNC_SQRT():
|
||||
expr = convert_expr(func.base)
|
||||
if func.root:
|
||||
r = convert_expr(func.root)
|
||||
return sympy.root(expr, r, evaluate=False)
|
||||
else:
|
||||
return sympy.sqrt(expr, evaluate=False)
|
||||
elif func.FUNC_OVERLINE():
|
||||
expr = convert_expr(func.base)
|
||||
return sympy.conjugate(expr, evaluate=False)
|
||||
elif func.FUNC_SUM():
|
||||
return handle_sum_or_prod(func, "summation")
|
||||
elif func.FUNC_PROD():
|
||||
return handle_sum_or_prod(func, "product")
|
||||
elif func.FUNC_LIM():
|
||||
return handle_limit(func)
|
||||
|
||||
|
||||
def convert_func_arg(arg):
|
||||
if hasattr(arg, 'expr'):
|
||||
return convert_expr(arg.expr())
|
||||
else:
|
||||
return convert_mp(arg.mp_nofunc())
|
||||
|
||||
|
||||
def handle_integral(func):
|
||||
if func.additive():
|
||||
integrand = convert_add(func.additive())
|
||||
elif func.frac():
|
||||
integrand = convert_frac(func.frac())
|
||||
else:
|
||||
integrand = 1
|
||||
|
||||
int_var = None
|
||||
if func.DIFFERENTIAL():
|
||||
int_var = get_differential_var(func.DIFFERENTIAL())
|
||||
else:
|
||||
for sym in integrand.atoms(sympy.Symbol):
|
||||
s = str(sym)
|
||||
if len(s) > 1 and s[0] == 'd':
|
||||
if s[1] == '\\':
|
||||
int_var = sympy.Symbol(s[2:])
|
||||
else:
|
||||
int_var = sympy.Symbol(s[1:])
|
||||
int_sym = sym
|
||||
if int_var:
|
||||
integrand = integrand.subs(int_sym, 1)
|
||||
else:
|
||||
# Assume dx by default
|
||||
int_var = sympy.Symbol('x')
|
||||
|
||||
if func.subexpr():
|
||||
if func.subexpr().atom():
|
||||
lower = convert_atom(func.subexpr().atom())
|
||||
else:
|
||||
lower = convert_expr(func.subexpr().expr())
|
||||
if func.supexpr().atom():
|
||||
upper = convert_atom(func.supexpr().atom())
|
||||
else:
|
||||
upper = convert_expr(func.supexpr().expr())
|
||||
return sympy.Integral(integrand, (int_var, lower, upper))
|
||||
else:
|
||||
return sympy.Integral(integrand, int_var)
|
||||
|
||||
|
||||
def handle_sum_or_prod(func, name):
|
||||
val = convert_mp(func.mp())
|
||||
iter_var = convert_expr(func.subeq().equality().expr(0))
|
||||
start = convert_expr(func.subeq().equality().expr(1))
|
||||
if func.supexpr().expr(): # ^{expr}
|
||||
end = convert_expr(func.supexpr().expr())
|
||||
else: # ^atom
|
||||
end = convert_atom(func.supexpr().atom())
|
||||
|
||||
if name == "summation":
|
||||
return sympy.Sum(val, (iter_var, start, end))
|
||||
elif name == "product":
|
||||
return sympy.Product(val, (iter_var, start, end))
|
||||
|
||||
|
||||
def handle_limit(func):
|
||||
sub = func.limit_sub()
|
||||
if sub.LETTER():
|
||||
var = sympy.Symbol(sub.LETTER().getText())
|
||||
elif sub.SYMBOL():
|
||||
var = sympy.Symbol(sub.SYMBOL().getText()[1:])
|
||||
else:
|
||||
var = sympy.Symbol('x')
|
||||
if sub.SUB():
|
||||
direction = "-"
|
||||
elif sub.ADD():
|
||||
direction = "+"
|
||||
else:
|
||||
direction = "+-"
|
||||
approaching = convert_expr(sub.expr())
|
||||
content = convert_mp(func.mp())
|
||||
|
||||
return sympy.Limit(content, var, approaching, direction)
|
||||
|
||||
|
||||
def get_differential_var(d):
|
||||
text = get_differential_var_str(d.getText())
|
||||
return sympy.Symbol(text)
|
||||
|
||||
|
||||
def get_differential_var_str(text):
|
||||
for i in range(1, len(text)):
|
||||
c = text[i]
|
||||
if not (c == " " or c == "\r" or c == "\n" or c == "\t"):
|
||||
idx = i
|
||||
break
|
||||
text = text[idx:]
|
||||
if text[0] == "\\":
|
||||
text = text[1:]
|
||||
return text
|
||||
@@ -0,0 +1,2 @@
|
||||
class LaTeXParsingError(Exception):
|
||||
pass
|
||||
@@ -0,0 +1,2 @@
|
||||
from .latex_parser import parse_latex_lark, LarkLaTeXParser # noqa
|
||||
from .transformer import TransformToSymPyExpr # noqa
|
||||
@@ -0,0 +1,28 @@
|
||||
// Greek symbols
|
||||
// TODO: Shouold we include the uppercase variants for the symbols where the uppercase variant doesn't have a separate meaning?
|
||||
ALPHA: "\\alpha"
|
||||
BETA: "\\beta"
|
||||
GAMMA: "\\gamma"
|
||||
DELTA: "\\delta" // TODO: Should this be included? Delta usually denotes other things.
|
||||
EPSILON: "\\epsilon" | "\\varepsilon"
|
||||
ZETA: "\\zeta"
|
||||
ETA: "\\eta"
|
||||
THETA: "\\theta" | "\\vartheta"
|
||||
// TODO: Should I add iota to the list?
|
||||
KAPPA: "\\kappa"
|
||||
LAMBDA: "\\lambda" // TODO: What about the uppercase variant?
|
||||
MU: "\\mu"
|
||||
NU: "\\nu"
|
||||
XI: "\\xi"
|
||||
// TODO: Should there be a separate note for transforming \pi into sympy.pi?
|
||||
RHO: "\\rho" | "\\varrho"
|
||||
// TODO: What should we do about sigma?
|
||||
TAU: "\\tau"
|
||||
UPSILON: "\\upsilon"
|
||||
PHI: "\\phi" | "\\varphi"
|
||||
CHI: "\\chi"
|
||||
PSI: "\\psi"
|
||||
OMEGA: "\\omega"
|
||||
|
||||
GREEK_SYMBOL: ALPHA | BETA | GAMMA | DELTA | EPSILON | ZETA | ETA | THETA | KAPPA
|
||||
| LAMBDA | MU | NU | XI | RHO | TAU | UPSILON | PHI | CHI | PSI | OMEGA
|
||||
@@ -0,0 +1,403 @@
|
||||
%ignore /[ \t\n\r]+/
|
||||
|
||||
%ignore "\\," | "\\thinspace" | "\\:" | "\\medspace" | "\\;" | "\\thickspace"
|
||||
%ignore "\\quad" | "\\qquad"
|
||||
%ignore "\\!" | "\\negthinspace" | "\\negmedspace" | "\\negthickspace"
|
||||
%ignore "\\vrule" | "\\vcenter" | "\\vbox" | "\\vskip" | "\\vspace" | "\\hfill"
|
||||
%ignore "\\*" | "\\-" | "\\." | "\\/" | "\\(" | "\\="
|
||||
|
||||
%ignore "\\left" | "\\right"
|
||||
%ignore "\\limits" | "\\nolimits"
|
||||
%ignore "\\displaystyle"
|
||||
|
||||
///////////////////// tokens ///////////////////////
|
||||
|
||||
// basic binary operators
|
||||
ADD: "+"
|
||||
SUB: "-"
|
||||
MUL: "*"
|
||||
DIV: "/"
|
||||
|
||||
// tokens with distinct left and right symbols
|
||||
L_BRACE: "{"
|
||||
R_BRACE: "}"
|
||||
L_BRACE_LITERAL: "\\{"
|
||||
R_BRACE_LITERAL: "\\}"
|
||||
L_BRACKET: "["
|
||||
R_BRACKET: "]"
|
||||
L_CEIL: "\\lceil"
|
||||
R_CEIL: "\\rceil"
|
||||
L_FLOOR: "\\lfloor"
|
||||
R_FLOOR: "\\rfloor"
|
||||
L_PAREN: "("
|
||||
R_PAREN: ")"
|
||||
|
||||
// limit, integral, sum, and product symbols
|
||||
FUNC_LIM: "\\lim"
|
||||
LIM_APPROACH_SYM: "\\to" | "\\rightarrow" | "\\Rightarrow" | "\\longrightarrow" | "\\Longrightarrow"
|
||||
FUNC_INT: "\\int" | "\\intop"
|
||||
FUNC_SUM: "\\sum"
|
||||
FUNC_PROD: "\\prod"
|
||||
|
||||
// common functions
|
||||
FUNC_EXP: "\\exp"
|
||||
FUNC_LOG: "\\log"
|
||||
FUNC_LN: "\\ln"
|
||||
FUNC_LG: "\\lg"
|
||||
FUNC_MIN: "\\min"
|
||||
FUNC_MAX: "\\max"
|
||||
|
||||
// trigonometric functions
|
||||
FUNC_SIN: "\\sin"
|
||||
FUNC_COS: "\\cos"
|
||||
FUNC_TAN: "\\tan"
|
||||
FUNC_CSC: "\\csc"
|
||||
FUNC_SEC: "\\sec"
|
||||
FUNC_COT: "\\cot"
|
||||
|
||||
// inverse trigonometric functions
|
||||
FUNC_ARCSIN: "\\arcsin"
|
||||
FUNC_ARCCOS: "\\arccos"
|
||||
FUNC_ARCTAN: "\\arctan"
|
||||
FUNC_ARCCSC: "\\arccsc"
|
||||
FUNC_ARCSEC: "\\arcsec"
|
||||
FUNC_ARCCOT: "\\arccot"
|
||||
|
||||
// hyperbolic trigonometric functions
|
||||
FUNC_SINH: "\\sinh"
|
||||
FUNC_COSH: "\\cosh"
|
||||
FUNC_TANH: "\\tanh"
|
||||
FUNC_ARSINH: "\\arsinh"
|
||||
FUNC_ARCOSH: "\\arcosh"
|
||||
FUNC_ARTANH: "\\artanh"
|
||||
|
||||
FUNC_SQRT: "\\sqrt"
|
||||
|
||||
// miscellaneous symbols
|
||||
CMD_TIMES: "\\times"
|
||||
CMD_CDOT: "\\cdot"
|
||||
CMD_DIV: "\\div"
|
||||
CMD_FRAC: "\\frac" | "\\dfrac" | "\\tfrac" | "\\nicefrac"
|
||||
CMD_BINOM: "\\binom" | "\\dbinom" | "\\tbinom"
|
||||
CMD_OVERLINE: "\\overline"
|
||||
CMD_LANGLE: "\\langle"
|
||||
CMD_RANGLE: "\\rangle"
|
||||
|
||||
CMD_MATHIT: "\\mathit"
|
||||
|
||||
CMD_INFTY: "\\infty"
|
||||
|
||||
BANG: "!"
|
||||
BAR: "|"
|
||||
CARET: "^"
|
||||
COLON: ":"
|
||||
UNDERSCORE: "_"
|
||||
|
||||
// relational symbols
|
||||
EQUAL: "="
|
||||
NOT_EQUAL: "\\neq" | "\\ne"
|
||||
LT: "<"
|
||||
LTE: "\\leq" | "\\le" | "\\leqslant"
|
||||
GT: ">"
|
||||
GTE: "\\geq" | "\\ge" | "\\geqslant"
|
||||
|
||||
DIV_SYMBOL: CMD_DIV | DIV
|
||||
MUL_SYMBOL: MUL | CMD_TIMES | CMD_CDOT
|
||||
|
||||
%import .greek_symbols.GREEK_SYMBOL
|
||||
|
||||
UPRIGHT_DIFFERENTIAL_SYMBOL: "\\text{d}" | "\\mathrm{d}"
|
||||
DIFFERENTIAL_SYMBOL: "d" | UPRIGHT_DIFFERENTIAL_SYMBOL
|
||||
|
||||
// disallow "d" as a variable name because we want to parse "d" as a differential symbol.
|
||||
SYMBOL: /[a-zA-Z]'*/
|
||||
GREEK_SYMBOL_WITH_PRIMES: GREEK_SYMBOL "'"*
|
||||
LATIN_SYMBOL_WITH_LATIN_SUBSCRIPT: /([a-zA-Z]'*)_(([A-Za-z0-9]|[a-zA-Z]+)|\{([A-Za-z0-9]|[a-zA-Z]+'*)\})/
|
||||
LATIN_SYMBOL_WITH_GREEK_SUBSCRIPT: /([a-zA-Z]'*)_/ GREEK_SYMBOL | /([a-zA-Z]'*)_/ L_BRACE GREEK_SYMBOL_WITH_PRIMES R_BRACE
|
||||
// best to define the variant with braces like that instead of shoving it all into one case like in
|
||||
// /([a-zA-Z])_/ L_BRACE? GREEK_SYMBOL R_BRACE? because then we can easily error out on input like
|
||||
// r"h_{\theta"
|
||||
GREEK_SYMBOL_WITH_LATIN_SUBSCRIPT: GREEK_SYMBOL_WITH_PRIMES /_(([A-Za-z0-9]|[a-zA-Z]+)|\{([A-Za-z0-9]|[a-zA-Z]+'*)\})/
|
||||
GREEK_SYMBOL_WITH_GREEK_SUBSCRIPT: GREEK_SYMBOL_WITH_PRIMES /_/ (GREEK_SYMBOL | L_BRACE GREEK_SYMBOL_WITH_PRIMES R_BRACE)
|
||||
MULTI_LETTER_SYMBOL: /[a-zA-Z]+(\s+[a-zA-Z]+)*'*/
|
||||
|
||||
%import common.DIGIT -> DIGIT
|
||||
|
||||
CMD_PRIME: "\\prime"
|
||||
CMD_ASTERISK: "\\ast"
|
||||
|
||||
PRIMES: "'"+
|
||||
STARS: "*"+
|
||||
PRIMES_VIA_CMD: CMD_PRIME+
|
||||
STARS_VIA_CMD: CMD_ASTERISK+
|
||||
|
||||
CMD_IMAGINARY_UNIT: "\\imaginaryunit"
|
||||
|
||||
CMD_BEGIN: "\\begin"
|
||||
CMD_END: "\\end"
|
||||
|
||||
// matrices
|
||||
IGNORE_L: /[ \t\n\r]*/ L_BRACE* /[ \t\n\r]*/
|
||||
IGNORE_R: /[ \t\n\r]*/ R_BRACE* /[ \t\n\r]*/
|
||||
ARRAY_MATRIX_BEGIN: L_BRACE "array" R_BRACE L_BRACE /[^}]*/ R_BRACE
|
||||
ARRAY_MATRIX_END: L_BRACE "array" R_BRACE
|
||||
AMSMATH_MATRIX: L_BRACE "matrix" R_BRACE
|
||||
AMSMATH_PMATRIX: L_BRACE "pmatrix" R_BRACE
|
||||
AMSMATH_BMATRIX: L_BRACE "bmatrix" R_BRACE
|
||||
// Without the (L|R)_PARENs and (L|R)_BRACKETs, a matrix defined using
|
||||
// \begin{array}...\end{array} or \begin{matrix}...\end{matrix} must
|
||||
// not qualify as a complete matrix expression; this is done so that
|
||||
// if we have \begin{array}...\end{array} or \begin{matrix}...\end{matrix}
|
||||
// between BAR pairs, then they should be interpreted as determinants as
|
||||
// opposed to sympy.Abs (absolute value) applied to a matrix.
|
||||
CMD_BEGIN_AMSPMATRIX_AMSBMATRIX: CMD_BEGIN (AMSMATH_PMATRIX | AMSMATH_BMATRIX)
|
||||
CMD_BEGIN_ARRAY_AMSMATRIX: (L_PAREN | L_BRACKET) IGNORE_L CMD_BEGIN (ARRAY_MATRIX_BEGIN | AMSMATH_MATRIX)
|
||||
CMD_MATRIX_BEGIN: CMD_BEGIN_AMSPMATRIX_AMSBMATRIX | CMD_BEGIN_ARRAY_AMSMATRIX
|
||||
CMD_END_AMSPMATRIX_AMSBMATRIX: CMD_END (AMSMATH_PMATRIX | AMSMATH_BMATRIX)
|
||||
CMD_END_ARRAY_AMSMATRIX: CMD_END (ARRAY_MATRIX_END | AMSMATH_MATRIX) IGNORE_R "\\right"? (R_PAREN | R_BRACKET)
|
||||
CMD_MATRIX_END: CMD_END_AMSPMATRIX_AMSBMATRIX | CMD_END_ARRAY_AMSMATRIX
|
||||
MATRIX_COL_DELIM: "&"
|
||||
MATRIX_ROW_DELIM: "\\\\"
|
||||
FUNC_MATRIX_TRACE: "\\trace"
|
||||
FUNC_MATRIX_ADJUGATE: "\\adjugate"
|
||||
|
||||
// determinants
|
||||
AMSMATH_VMATRIX: L_BRACE "vmatrix" R_BRACE
|
||||
CMD_DETERMINANT_BEGIN_SIMPLE: CMD_BEGIN AMSMATH_VMATRIX
|
||||
CMD_DETERMINANT_BEGIN_VARIANT: BAR IGNORE_L CMD_BEGIN (ARRAY_MATRIX_BEGIN | AMSMATH_MATRIX)
|
||||
CMD_DETERMINANT_BEGIN: CMD_DETERMINANT_BEGIN_SIMPLE | CMD_DETERMINANT_BEGIN_VARIANT
|
||||
CMD_DETERMINANT_END_SIMPLE: CMD_END AMSMATH_VMATRIX
|
||||
CMD_DETERMINANT_END_VARIANT: CMD_END (ARRAY_MATRIX_END | AMSMATH_MATRIX) IGNORE_R "\\right"? BAR
|
||||
CMD_DETERMINANT_END: CMD_DETERMINANT_END_SIMPLE | CMD_DETERMINANT_END_VARIANT
|
||||
FUNC_DETERMINANT: "\\det"
|
||||
|
||||
//////////////////// grammar //////////////////////
|
||||
|
||||
latex_string: _relation | _expression
|
||||
|
||||
_one_letter_symbol: SYMBOL
|
||||
| LATIN_SYMBOL_WITH_LATIN_SUBSCRIPT
|
||||
| LATIN_SYMBOL_WITH_GREEK_SUBSCRIPT
|
||||
| GREEK_SYMBOL_WITH_LATIN_SUBSCRIPT
|
||||
| GREEK_SYMBOL_WITH_GREEK_SUBSCRIPT
|
||||
| GREEK_SYMBOL_WITH_PRIMES
|
||||
// LuaTeX-generated outputs of \mathit{foo'} and \mathit{foo}'
|
||||
// seem to be the same on the surface. We allow both styles.
|
||||
multi_letter_symbol: CMD_MATHIT L_BRACE MULTI_LETTER_SYMBOL R_BRACE
|
||||
| CMD_MATHIT L_BRACE MULTI_LETTER_SYMBOL R_BRACE /'+/
|
||||
number: /\d+(\.\d*)?/ | CMD_IMAGINARY_UNIT
|
||||
|
||||
_atomic_expr: _one_letter_symbol
|
||||
| multi_letter_symbol
|
||||
| number
|
||||
| CMD_INFTY
|
||||
|
||||
group_round_parentheses: L_PAREN _expression R_PAREN
|
||||
group_square_brackets: L_BRACKET _expression R_BRACKET
|
||||
group_curly_parentheses: L_BRACE _expression R_BRACE
|
||||
|
||||
_relation: eq | ne | lt | lte | gt | gte
|
||||
|
||||
eq: _expression EQUAL _expression
|
||||
ne: _expression NOT_EQUAL _expression
|
||||
lt: _expression LT _expression
|
||||
lte: _expression LTE _expression
|
||||
gt: _expression GT _expression
|
||||
gte: _expression GTE _expression
|
||||
|
||||
_expression_core: _atomic_expr | group_curly_parentheses
|
||||
|
||||
add: _expression ADD _expression_mul
|
||||
| ADD _expression_mul
|
||||
sub: _expression SUB _expression_mul
|
||||
| SUB _expression_mul
|
||||
mul: _expression_mul MUL_SYMBOL _expression_power
|
||||
div: _expression_mul DIV_SYMBOL _expression_power
|
||||
|
||||
adjacent_expressions: (_one_letter_symbol | number) _expression_mul
|
||||
| group_round_parentheses (group_round_parentheses | _one_letter_symbol)
|
||||
| _function _function
|
||||
| fraction _expression_mul
|
||||
|
||||
_expression_func: _expression_core
|
||||
| group_round_parentheses
|
||||
| fraction
|
||||
| binomial
|
||||
| _function
|
||||
| _integral// | derivative
|
||||
| limit
|
||||
| matrix
|
||||
|
||||
_expression_power: _expression_func | superscript | matrix_prime | symbol_prime
|
||||
|
||||
_expression_mul: _expression_power
|
||||
| mul | div | adjacent_expressions
|
||||
| summation | product
|
||||
|
||||
_expression: _expression_mul | add | sub
|
||||
|
||||
_limit_dir: "+" | "-" | L_BRACE ("+" | "-") R_BRACE
|
||||
|
||||
limit_dir_expr: _expression CARET _limit_dir
|
||||
|
||||
group_curly_parentheses_lim: L_BRACE _expression LIM_APPROACH_SYM (limit_dir_expr | _expression) R_BRACE
|
||||
|
||||
limit: FUNC_LIM UNDERSCORE group_curly_parentheses_lim _expression
|
||||
|
||||
differential: DIFFERENTIAL_SYMBOL _one_letter_symbol
|
||||
|
||||
//_derivative_operator: CMD_FRAC L_BRACE DIFFERENTIAL_SYMBOL R_BRACE L_BRACE differential R_BRACE
|
||||
|
||||
//derivative: _derivative_operator _expression
|
||||
|
||||
_integral: normal_integral | integral_with_special_fraction
|
||||
|
||||
normal_integral: FUNC_INT _expression DIFFERENTIAL_SYMBOL _one_letter_symbol
|
||||
| FUNC_INT (CARET _expression_core UNDERSCORE _expression_core)? _expression? DIFFERENTIAL_SYMBOL _one_letter_symbol
|
||||
| FUNC_INT (UNDERSCORE _expression_core CARET _expression_core)? _expression? DIFFERENTIAL_SYMBOL _one_letter_symbol
|
||||
|
||||
group_curly_parentheses_int: L_BRACE _expression? differential R_BRACE
|
||||
|
||||
special_fraction: CMD_FRAC group_curly_parentheses_int group_curly_parentheses
|
||||
|
||||
integral_with_special_fraction: FUNC_INT special_fraction
|
||||
| FUNC_INT (CARET _expression_core UNDERSCORE _expression_core)? special_fraction
|
||||
| FUNC_INT (UNDERSCORE _expression_core CARET _expression_core)? special_fraction
|
||||
|
||||
group_curly_parentheses_special: UNDERSCORE L_BRACE _atomic_expr EQUAL _atomic_expr R_BRACE CARET _expression_core
|
||||
| CARET _expression_core UNDERSCORE L_BRACE _atomic_expr EQUAL _atomic_expr R_BRACE
|
||||
|
||||
summation: FUNC_SUM group_curly_parentheses_special _expression
|
||||
| FUNC_SUM group_curly_parentheses_special _expression
|
||||
|
||||
product: FUNC_PROD group_curly_parentheses_special _expression
|
||||
| FUNC_PROD group_curly_parentheses_special _expression
|
||||
|
||||
superscript: _expression_func CARET (_expression_power | CMD_PRIME | CMD_ASTERISK)
|
||||
| _expression_func CARET L_BRACE (PRIMES | STARS | PRIMES_VIA_CMD | STARS_VIA_CMD) R_BRACE
|
||||
|
||||
matrix_prime: (matrix | group_round_parentheses) PRIMES
|
||||
|
||||
symbol_prime: (LATIN_SYMBOL_WITH_LATIN_SUBSCRIPT
|
||||
| LATIN_SYMBOL_WITH_GREEK_SUBSCRIPT
|
||||
| GREEK_SYMBOL_WITH_LATIN_SUBSCRIPT
|
||||
| GREEK_SYMBOL_WITH_GREEK_SUBSCRIPT) PRIMES
|
||||
|
||||
fraction: _basic_fraction
|
||||
| _simple_fraction
|
||||
| _general_fraction
|
||||
|
||||
_basic_fraction: CMD_FRAC DIGIT (DIGIT | SYMBOL | GREEK_SYMBOL_WITH_PRIMES)
|
||||
|
||||
_simple_fraction: CMD_FRAC DIGIT group_curly_parentheses
|
||||
| CMD_FRAC group_curly_parentheses (DIGIT | SYMBOL | GREEK_SYMBOL_WITH_PRIMES)
|
||||
|
||||
_general_fraction: CMD_FRAC group_curly_parentheses group_curly_parentheses
|
||||
|
||||
binomial: _basic_binomial
|
||||
| _simple_binomial
|
||||
| _general_binomial
|
||||
|
||||
_basic_binomial: CMD_BINOM DIGIT (DIGIT | SYMBOL | GREEK_SYMBOL_WITH_PRIMES)
|
||||
|
||||
_simple_binomial: CMD_BINOM DIGIT group_curly_parentheses
|
||||
| CMD_BINOM group_curly_parentheses (DIGIT | SYMBOL | GREEK_SYMBOL_WITH_PRIMES)
|
||||
|
||||
_general_binomial: CMD_BINOM group_curly_parentheses group_curly_parentheses
|
||||
|
||||
list_of_expressions: _expression ("," _expression)*
|
||||
|
||||
function_applied: _one_letter_symbol L_PAREN list_of_expressions R_PAREN
|
||||
|
||||
min: FUNC_MIN L_PAREN list_of_expressions R_PAREN
|
||||
|
||||
max: FUNC_MAX L_PAREN list_of_expressions R_PAREN
|
||||
|
||||
bra: CMD_LANGLE _expression BAR
|
||||
|
||||
ket: BAR _expression CMD_RANGLE
|
||||
|
||||
inner_product: CMD_LANGLE _expression BAR _expression CMD_RANGLE
|
||||
|
||||
_function: function_applied
|
||||
| abs | floor | ceil
|
||||
| _trigonometric_function | _inverse_trigonometric_function
|
||||
| _trigonometric_function_power
|
||||
| _hyperbolic_trigonometric_function | _inverse_hyperbolic_trigonometric_function
|
||||
| exponential
|
||||
| log
|
||||
| square_root
|
||||
| factorial
|
||||
| conjugate
|
||||
| max | min
|
||||
| bra | ket | inner_product
|
||||
| determinant
|
||||
| trace
|
||||
| adjugate
|
||||
|
||||
exponential: FUNC_EXP _expression
|
||||
|
||||
log: FUNC_LOG _expression
|
||||
| FUNC_LN _expression
|
||||
| FUNC_LG _expression
|
||||
| FUNC_LOG UNDERSCORE (DIGIT | _one_letter_symbol) _expression
|
||||
| FUNC_LOG UNDERSCORE group_curly_parentheses _expression
|
||||
|
||||
square_root: FUNC_SQRT group_curly_parentheses
|
||||
| FUNC_SQRT group_square_brackets group_curly_parentheses
|
||||
|
||||
factorial: _expression_func BANG
|
||||
|
||||
conjugate: CMD_OVERLINE group_curly_parentheses
|
||||
| CMD_OVERLINE DIGIT
|
||||
|
||||
_trigonometric_function: sin | cos | tan | csc | sec | cot
|
||||
|
||||
sin: FUNC_SIN _expression
|
||||
cos: FUNC_COS _expression
|
||||
tan: FUNC_TAN _expression
|
||||
csc: FUNC_CSC _expression
|
||||
sec: FUNC_SEC _expression
|
||||
cot: FUNC_COT _expression
|
||||
|
||||
_trigonometric_function_power: sin_power | cos_power | tan_power | csc_power | sec_power | cot_power
|
||||
|
||||
sin_power: FUNC_SIN CARET _expression_core _expression
|
||||
cos_power: FUNC_COS CARET _expression_core _expression
|
||||
tan_power: FUNC_TAN CARET _expression_core _expression
|
||||
csc_power: FUNC_CSC CARET _expression_core _expression
|
||||
sec_power: FUNC_SEC CARET _expression_core _expression
|
||||
cot_power: FUNC_COT CARET _expression_core _expression
|
||||
|
||||
_hyperbolic_trigonometric_function: sinh | cosh | tanh
|
||||
|
||||
sinh: FUNC_SINH _expression
|
||||
cosh: FUNC_COSH _expression
|
||||
tanh: FUNC_TANH _expression
|
||||
|
||||
_inverse_trigonometric_function: arcsin | arccos | arctan | arccsc | arcsec | arccot
|
||||
|
||||
arcsin: FUNC_ARCSIN _expression
|
||||
arccos: FUNC_ARCCOS _expression
|
||||
arctan: FUNC_ARCTAN _expression
|
||||
arccsc: FUNC_ARCCSC _expression
|
||||
arcsec: FUNC_ARCSEC _expression
|
||||
arccot: FUNC_ARCCOT _expression
|
||||
|
||||
_inverse_hyperbolic_trigonometric_function: asinh | acosh | atanh
|
||||
|
||||
asinh: FUNC_ARSINH _expression
|
||||
acosh: FUNC_ARCOSH _expression
|
||||
atanh: FUNC_ARTANH _expression
|
||||
|
||||
abs: BAR _expression BAR
|
||||
floor: L_FLOOR _expression R_FLOOR
|
||||
ceil: L_CEIL _expression R_CEIL
|
||||
|
||||
matrix: CMD_MATRIX_BEGIN matrix_body CMD_MATRIX_END
|
||||
matrix_body: matrix_row (MATRIX_ROW_DELIM matrix_row)* (MATRIX_ROW_DELIM)?
|
||||
matrix_row: _expression (MATRIX_COL_DELIM _expression)*
|
||||
determinant: (CMD_DETERMINANT_BEGIN matrix_body CMD_DETERMINANT_END)
|
||||
| FUNC_DETERMINANT _expression
|
||||
trace: FUNC_MATRIX_TRACE _expression
|
||||
adjugate: FUNC_MATRIX_ADJUGATE _expression
|
||||
@@ -0,0 +1,145 @@
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from sympy.external import import_module
|
||||
from sympy.parsing.latex.lark.transformer import TransformToSymPyExpr
|
||||
|
||||
_lark = import_module("lark")
|
||||
|
||||
|
||||
class LarkLaTeXParser:
|
||||
r"""Class for converting input `\mathrm{\LaTeX}` strings into SymPy Expressions.
|
||||
It holds all the necessary internal data for doing so, and exposes hooks for
|
||||
customizing its behavior.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
print_debug_output : bool, optional
|
||||
|
||||
If set to ``True``, prints debug output to the logger. Defaults to ``False``.
|
||||
|
||||
transform : bool, optional
|
||||
|
||||
If set to ``True``, the class runs the Transformer class on the parse tree
|
||||
generated by running ``Lark.parse`` on the input string. Defaults to ``True``.
|
||||
|
||||
Setting it to ``False`` can help with debugging the `\mathrm{\LaTeX}` grammar.
|
||||
|
||||
grammar_file : str, optional
|
||||
|
||||
The path to the grammar file that the parser should use. If set to ``None``,
|
||||
it uses the default grammar, which is in ``grammar/latex.lark``, relative to
|
||||
the ``sympy/parsing/latex/lark/`` directory.
|
||||
|
||||
transformer : str, optional
|
||||
|
||||
The name of the Transformer class to use. If set to ``None``, it uses the
|
||||
default transformer class, which is :py:func:`TransformToSymPyExpr`.
|
||||
|
||||
"""
|
||||
def __init__(self, print_debug_output=False, transform=True, grammar_file=None, transformer=None):
|
||||
grammar_dir_path = os.path.join(os.path.dirname(__file__), "grammar/")
|
||||
|
||||
if grammar_file is None:
|
||||
latex_grammar = Path(os.path.join(grammar_dir_path, "latex.lark")).read_text(encoding="utf-8")
|
||||
else:
|
||||
latex_grammar = Path(grammar_file).read_text(encoding="utf-8")
|
||||
|
||||
self.parser = _lark.Lark(
|
||||
latex_grammar,
|
||||
source_path=grammar_dir_path,
|
||||
parser="earley",
|
||||
start="latex_string",
|
||||
lexer="auto",
|
||||
ambiguity="explicit",
|
||||
propagate_positions=False,
|
||||
maybe_placeholders=False,
|
||||
keep_all_tokens=True)
|
||||
|
||||
self.print_debug_output = print_debug_output
|
||||
self.transform_expr = transform
|
||||
|
||||
if transformer is None:
|
||||
self.transformer = TransformToSymPyExpr()
|
||||
else:
|
||||
self.transformer = transformer()
|
||||
|
||||
def doparse(self, s: str):
|
||||
if self.print_debug_output:
|
||||
_lark.logger.setLevel(logging.DEBUG)
|
||||
|
||||
parse_tree = self.parser.parse(s)
|
||||
|
||||
if not self.transform_expr:
|
||||
# exit early and return the parse tree
|
||||
_lark.logger.debug("expression = %s", s)
|
||||
_lark.logger.debug(parse_tree)
|
||||
_lark.logger.debug(parse_tree.pretty())
|
||||
return parse_tree
|
||||
|
||||
if self.print_debug_output:
|
||||
# print this stuff before attempting to run the transformer
|
||||
_lark.logger.debug("expression = %s", s)
|
||||
# print the `parse_tree` variable
|
||||
_lark.logger.debug(parse_tree.pretty())
|
||||
|
||||
sympy_expression = self.transformer.transform(parse_tree)
|
||||
|
||||
if self.print_debug_output:
|
||||
_lark.logger.debug("SymPy expression = %s", sympy_expression)
|
||||
|
||||
return sympy_expression
|
||||
|
||||
|
||||
if _lark is not None:
|
||||
_lark_latex_parser = LarkLaTeXParser()
|
||||
|
||||
|
||||
def parse_latex_lark(s: str):
|
||||
"""
|
||||
Experimental LaTeX parser using Lark.
|
||||
|
||||
This function is still under development and its API may change with the
|
||||
next releases of SymPy.
|
||||
"""
|
||||
if _lark is None:
|
||||
raise ImportError("Lark is probably not installed")
|
||||
return _lark_latex_parser.doparse(s)
|
||||
|
||||
|
||||
def _pretty_print_lark_trees(tree, indent=0, show_expr=True):
|
||||
if isinstance(tree, _lark.Token):
|
||||
return tree.value
|
||||
|
||||
data = str(tree.data)
|
||||
|
||||
is_expr = data.startswith("expression")
|
||||
|
||||
if is_expr:
|
||||
data = re.sub(r"^expression", "E", data)
|
||||
|
||||
is_ambig = (data == "_ambig")
|
||||
|
||||
if is_ambig:
|
||||
new_indent = indent + 2
|
||||
else:
|
||||
new_indent = indent
|
||||
|
||||
output = ""
|
||||
show_node = not is_expr or show_expr
|
||||
|
||||
if show_node:
|
||||
output += str(data) + "("
|
||||
|
||||
if is_ambig:
|
||||
output += "\n" + "\n".join([" " * new_indent + _pretty_print_lark_trees(i, new_indent, show_expr) for i in tree.children])
|
||||
else:
|
||||
output += ",".join([_pretty_print_lark_trees(i, new_indent, show_expr) for i in tree.children])
|
||||
|
||||
if show_node:
|
||||
output += ")"
|
||||
|
||||
return output
|
||||
@@ -0,0 +1,730 @@
|
||||
import re
|
||||
|
||||
import sympy
|
||||
from sympy.external import import_module
|
||||
from sympy.parsing.latex.errors import LaTeXParsingError
|
||||
|
||||
lark = import_module("lark")
|
||||
|
||||
if lark:
|
||||
from lark import Transformer, Token, Tree # type: ignore
|
||||
else:
|
||||
class Transformer: # type: ignore
|
||||
def transform(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
class Token: # type: ignore
|
||||
pass
|
||||
|
||||
|
||||
class Tree: # type: ignore
|
||||
pass
|
||||
|
||||
|
||||
# noinspection PyPep8Naming,PyMethodMayBeStatic
|
||||
class TransformToSymPyExpr(Transformer):
|
||||
"""Returns a SymPy expression that is generated by traversing the ``lark.Tree``
|
||||
passed to the ``.transform()`` function.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
**This class is never supposed to be used directly.**
|
||||
|
||||
In order to tweak the behavior of this class, it has to be subclassed and then after
|
||||
the required modifications are made, the name of the new class should be passed to
|
||||
the :py:class:`LarkLaTeXParser` class by using the ``transformer`` argument in the
|
||||
constructor.
|
||||
|
||||
Parameters
|
||||
==========
|
||||
|
||||
visit_tokens : bool, optional
|
||||
For information about what this option does, see `here
|
||||
<https://lark-parser.readthedocs.io/en/latest/visitors.html#lark.visitors.Transformer>`_.
|
||||
|
||||
Note that the option must be set to ``True`` for the default parser to work.
|
||||
"""
|
||||
|
||||
SYMBOL = sympy.Symbol
|
||||
DIGIT = sympy.core.numbers.Integer
|
||||
|
||||
def CMD_INFTY(self, tokens):
|
||||
return sympy.oo
|
||||
|
||||
def GREEK_SYMBOL_WITH_PRIMES(self, tokens):
|
||||
# we omit the first character because it is a backslash. Also, if the variable name has "var" in it,
|
||||
# like "varphi" or "varepsilon", we remove that too
|
||||
variable_name = re.sub("var", "", tokens[1:])
|
||||
|
||||
return sympy.Symbol(variable_name)
|
||||
|
||||
def LATIN_SYMBOL_WITH_LATIN_SUBSCRIPT(self, tokens):
|
||||
base, sub = tokens.value.split("_")
|
||||
if sub.startswith("{"):
|
||||
return sympy.Symbol("%s_{%s}" % (base, sub[1:-1]))
|
||||
else:
|
||||
return sympy.Symbol("%s_{%s}" % (base, sub))
|
||||
|
||||
def GREEK_SYMBOL_WITH_LATIN_SUBSCRIPT(self, tokens):
|
||||
base, sub = tokens.value.split("_")
|
||||
greek_letter = re.sub("var", "", base[1:])
|
||||
|
||||
if sub.startswith("{"):
|
||||
return sympy.Symbol("%s_{%s}" % (greek_letter, sub[1:-1]))
|
||||
else:
|
||||
return sympy.Symbol("%s_{%s}" % (greek_letter, sub))
|
||||
|
||||
def LATIN_SYMBOL_WITH_GREEK_SUBSCRIPT(self, tokens):
|
||||
base, sub = tokens.value.split("_")
|
||||
if sub.startswith("{"):
|
||||
greek_letter = sub[2:-1]
|
||||
else:
|
||||
greek_letter = sub[1:]
|
||||
|
||||
greek_letter = re.sub("var", "", greek_letter)
|
||||
return sympy.Symbol("%s_{%s}" % (base, greek_letter))
|
||||
|
||||
|
||||
def GREEK_SYMBOL_WITH_GREEK_SUBSCRIPT(self, tokens):
|
||||
base, sub = tokens.value.split("_")
|
||||
greek_base = re.sub("var", "", base[1:])
|
||||
|
||||
if sub.startswith("{"):
|
||||
greek_sub = sub[2:-1]
|
||||
else:
|
||||
greek_sub = sub[1:]
|
||||
|
||||
greek_sub = re.sub("var", "", greek_sub)
|
||||
return sympy.Symbol("%s_{%s}" % (greek_base, greek_sub))
|
||||
|
||||
def multi_letter_symbol(self, tokens):
|
||||
if len(tokens) == 4: # no primes (single quotes) on symbol
|
||||
return sympy.Symbol(tokens[2])
|
||||
if len(tokens) == 5: # there are primes on the symbol
|
||||
return sympy.Symbol(tokens[2] + tokens[4])
|
||||
|
||||
def number(self, tokens):
|
||||
if tokens[0].type == "CMD_IMAGINARY_UNIT":
|
||||
return sympy.I
|
||||
|
||||
if "." in tokens[0]:
|
||||
return sympy.core.numbers.Float(tokens[0])
|
||||
else:
|
||||
return sympy.core.numbers.Integer(tokens[0])
|
||||
|
||||
def latex_string(self, tokens):
|
||||
return tokens[0]
|
||||
|
||||
def group_round_parentheses(self, tokens):
|
||||
return tokens[1]
|
||||
|
||||
def group_square_brackets(self, tokens):
|
||||
return tokens[1]
|
||||
|
||||
def group_curly_parentheses(self, tokens):
|
||||
return tokens[1]
|
||||
|
||||
def eq(self, tokens):
|
||||
return sympy.Eq(tokens[0], tokens[2])
|
||||
|
||||
def ne(self, tokens):
|
||||
return sympy.Ne(tokens[0], tokens[2])
|
||||
|
||||
def lt(self, tokens):
|
||||
return sympy.Lt(tokens[0], tokens[2])
|
||||
|
||||
def lte(self, tokens):
|
||||
return sympy.Le(tokens[0], tokens[2])
|
||||
|
||||
def gt(self, tokens):
|
||||
return sympy.Gt(tokens[0], tokens[2])
|
||||
|
||||
def gte(self, tokens):
|
||||
return sympy.Ge(tokens[0], tokens[2])
|
||||
|
||||
def add(self, tokens):
|
||||
if len(tokens) == 2: # +a
|
||||
return tokens[1]
|
||||
if len(tokens) == 3: # a + b
|
||||
lh = tokens[0]
|
||||
rh = tokens[2]
|
||||
|
||||
if self._obj_is_sympy_Matrix(lh) or self._obj_is_sympy_Matrix(rh):
|
||||
return sympy.MatAdd(lh, rh)
|
||||
|
||||
return sympy.Add(lh, rh)
|
||||
|
||||
def sub(self, tokens):
|
||||
if len(tokens) == 2: # -a
|
||||
x = tokens[1]
|
||||
|
||||
if self._obj_is_sympy_Matrix(x):
|
||||
return sympy.MatMul(-1, x)
|
||||
|
||||
return -x
|
||||
if len(tokens) == 3: # a - b
|
||||
lh = tokens[0]
|
||||
rh = tokens[2]
|
||||
|
||||
if self._obj_is_sympy_Matrix(lh) or self._obj_is_sympy_Matrix(rh):
|
||||
return sympy.MatAdd(lh, sympy.MatMul(-1, rh))
|
||||
|
||||
return sympy.Add(lh, -rh)
|
||||
|
||||
def mul(self, tokens):
|
||||
lh = tokens[0]
|
||||
rh = tokens[2]
|
||||
|
||||
if self._obj_is_sympy_Matrix(lh) or self._obj_is_sympy_Matrix(rh):
|
||||
return sympy.MatMul(lh, rh)
|
||||
|
||||
return sympy.Mul(lh, rh)
|
||||
|
||||
def div(self, tokens):
|
||||
return self._handle_division(tokens[0], tokens[2])
|
||||
|
||||
def adjacent_expressions(self, tokens):
|
||||
# Most of the time, if two expressions are next to each other, it means implicit multiplication,
|
||||
# but not always
|
||||
from sympy.physics.quantum import Bra, Ket
|
||||
if isinstance(tokens[0], Ket) and isinstance(tokens[1], Bra):
|
||||
from sympy.physics.quantum import OuterProduct
|
||||
return OuterProduct(tokens[0], tokens[1])
|
||||
elif tokens[0] == sympy.Symbol("d"):
|
||||
# If the leftmost token is a "d", then it is highly likely that this is a differential
|
||||
return tokens[0], tokens[1]
|
||||
elif isinstance(tokens[0], tuple):
|
||||
# then we have a derivative
|
||||
return sympy.Derivative(tokens[1], tokens[0][1])
|
||||
else:
|
||||
return sympy.Mul(tokens[0], tokens[1])
|
||||
|
||||
def superscript(self, tokens):
|
||||
def isprime(x):
|
||||
return isinstance(x, Token) and x.type == "PRIMES"
|
||||
|
||||
def iscmdprime(x):
|
||||
return isinstance(x, Token) and (x.type == "PRIMES_VIA_CMD"
|
||||
or x.type == "CMD_PRIME")
|
||||
|
||||
def isstar(x):
|
||||
return isinstance(x, Token) and x.type == "STARS"
|
||||
|
||||
def iscmdstar(x):
|
||||
return isinstance(x, Token) and (x.type == "STARS_VIA_CMD"
|
||||
or x.type == "CMD_ASTERISK")
|
||||
|
||||
base = tokens[0]
|
||||
if len(tokens) == 3: # a^b OR a^\prime OR a^\ast
|
||||
sup = tokens[2]
|
||||
if len(tokens) == 5:
|
||||
# a^{'}, a^{''}, ... OR
|
||||
# a^{*}, a^{**}, ... OR
|
||||
# a^{\prime}, a^{\prime\prime}, ... OR
|
||||
# a^{\ast}, a^{\ast\ast}, ...
|
||||
sup = tokens[3]
|
||||
|
||||
if self._obj_is_sympy_Matrix(base):
|
||||
if sup == sympy.Symbol("T"):
|
||||
return sympy.Transpose(base)
|
||||
if sup == sympy.Symbol("H"):
|
||||
return sympy.adjoint(base)
|
||||
if isprime(sup):
|
||||
sup = sup.value
|
||||
if len(sup) % 2 == 0:
|
||||
return base
|
||||
return sympy.Transpose(base)
|
||||
if iscmdprime(sup):
|
||||
sup = sup.value
|
||||
if (len(sup)/len(r"\prime")) % 2 == 0:
|
||||
return base
|
||||
return sympy.Transpose(base)
|
||||
if isstar(sup):
|
||||
sup = sup.value
|
||||
# need .doit() in order to be consistent with
|
||||
# sympy.adjoint() which returns the evaluated adjoint
|
||||
# of a matrix
|
||||
if len(sup) % 2 == 0:
|
||||
return base.doit()
|
||||
return sympy.adjoint(base)
|
||||
if iscmdstar(sup):
|
||||
sup = sup.value
|
||||
# need .doit() for same reason as above
|
||||
if (len(sup)/len(r"\ast")) % 2 == 0:
|
||||
return base.doit()
|
||||
return sympy.adjoint(base)
|
||||
|
||||
if isprime(sup) or iscmdprime(sup) or isstar(sup) or iscmdstar(sup):
|
||||
raise LaTeXParsingError(f"{base} with superscript {sup} is not understood.")
|
||||
|
||||
return sympy.Pow(base, sup)
|
||||
|
||||
def matrix_prime(self, tokens):
|
||||
base = tokens[0]
|
||||
primes = tokens[1].value
|
||||
|
||||
if not self._obj_is_sympy_Matrix(base):
|
||||
raise LaTeXParsingError(f"({base}){primes} is not understood.")
|
||||
|
||||
if len(primes) % 2 == 0:
|
||||
return base
|
||||
|
||||
return sympy.Transpose(base)
|
||||
|
||||
def symbol_prime(self, tokens):
|
||||
base = tokens[0]
|
||||
primes = tokens[1].value
|
||||
|
||||
return sympy.Symbol(f"{base.name}{primes}")
|
||||
|
||||
def fraction(self, tokens):
|
||||
numerator = tokens[1]
|
||||
if isinstance(tokens[2], tuple):
|
||||
# we only need the variable w.r.t. which we are differentiating
|
||||
_, variable = tokens[2]
|
||||
|
||||
# we will pass this information upwards
|
||||
return "derivative", variable
|
||||
else:
|
||||
denominator = tokens[2]
|
||||
return self._handle_division(numerator, denominator)
|
||||
|
||||
def binomial(self, tokens):
|
||||
return sympy.binomial(tokens[1], tokens[2])
|
||||
|
||||
def normal_integral(self, tokens):
|
||||
underscore_index = None
|
||||
caret_index = None
|
||||
|
||||
if "_" in tokens:
|
||||
# we need to know the index because the next item in the list is the
|
||||
# arguments for the lower bound of the integral
|
||||
underscore_index = tokens.index("_")
|
||||
|
||||
if "^" in tokens:
|
||||
# we need to know the index because the next item in the list is the
|
||||
# arguments for the upper bound of the integral
|
||||
caret_index = tokens.index("^")
|
||||
|
||||
lower_bound = tokens[underscore_index + 1] if underscore_index else None
|
||||
upper_bound = tokens[caret_index + 1] if caret_index else None
|
||||
|
||||
differential_symbol = self._extract_differential_symbol(tokens)
|
||||
|
||||
if differential_symbol is None:
|
||||
raise LaTeXParsingError("Differential symbol was not found in the expression."
|
||||
"Valid differential symbols are \"d\", \"\\text{d}, and \"\\mathrm{d}\".")
|
||||
|
||||
# else we can assume that a differential symbol was found
|
||||
differential_variable_index = tokens.index(differential_symbol) + 1
|
||||
differential_variable = tokens[differential_variable_index]
|
||||
|
||||
# we can't simply do something like `if (lower_bound and not upper_bound) ...` because this would
|
||||
# evaluate to `True` if the `lower_bound` is 0 and upper bound is non-zero
|
||||
if lower_bound is not None and upper_bound is None:
|
||||
# then one was given and the other wasn't
|
||||
raise LaTeXParsingError("Lower bound for the integral was found, but upper bound was not found.")
|
||||
|
||||
if upper_bound is not None and lower_bound is None:
|
||||
# then one was given and the other wasn't
|
||||
raise LaTeXParsingError("Upper bound for the integral was found, but lower bound was not found.")
|
||||
|
||||
# check if any expression was given or not. If it wasn't, then set the integrand to 1.
|
||||
if underscore_index is not None and underscore_index == differential_variable_index - 3:
|
||||
# The Token at differential_variable_index - 2 should be the integrand. However, if going one more step
|
||||
# backwards after that gives us the underscore, then that means that there _was_ no integrand.
|
||||
# Example: \int^7_0 dx
|
||||
integrand = 1
|
||||
elif caret_index is not None and caret_index == differential_variable_index - 3:
|
||||
# The Token at differential_variable_index - 2 should be the integrand. However, if going one more step
|
||||
# backwards after that gives us the caret, then that means that there _was_ no integrand.
|
||||
# Example: \int_0^7 dx
|
||||
integrand = 1
|
||||
elif differential_variable_index == 2:
|
||||
# this means we have something like "\int dx", because the "\int" symbol will always be
|
||||
# at index 0 in `tokens`
|
||||
integrand = 1
|
||||
else:
|
||||
# The Token at differential_variable_index - 1 is the differential symbol itself, so we need to go one
|
||||
# more step before that.
|
||||
integrand = tokens[differential_variable_index - 2]
|
||||
|
||||
if lower_bound is not None:
|
||||
# then we have a definite integral
|
||||
|
||||
# we can assume that either both the lower and upper bounds are given, or
|
||||
# neither of them are
|
||||
return sympy.Integral(integrand, (differential_variable, lower_bound, upper_bound))
|
||||
else:
|
||||
# we have an indefinite integral
|
||||
return sympy.Integral(integrand, differential_variable)
|
||||
|
||||
def group_curly_parentheses_int(self, tokens):
|
||||
# return signature is a tuple consisting of the expression in the numerator, along with the variable of
|
||||
# integration
|
||||
if len(tokens) == 3:
|
||||
return 1, tokens[1]
|
||||
elif len(tokens) == 4:
|
||||
return tokens[1], tokens[2]
|
||||
# there are no other possibilities
|
||||
|
||||
def special_fraction(self, tokens):
|
||||
numerator, variable = tokens[1]
|
||||
denominator = tokens[2]
|
||||
|
||||
# We pass the integrand, along with information about the variable of integration, upw
|
||||
return sympy.Mul(numerator, sympy.Pow(denominator, -1)), variable
|
||||
|
||||
def integral_with_special_fraction(self, tokens):
|
||||
underscore_index = None
|
||||
caret_index = None
|
||||
|
||||
if "_" in tokens:
|
||||
# we need to know the index because the next item in the list is the
|
||||
# arguments for the lower bound of the integral
|
||||
underscore_index = tokens.index("_")
|
||||
|
||||
if "^" in tokens:
|
||||
# we need to know the index because the next item in the list is the
|
||||
# arguments for the upper bound of the integral
|
||||
caret_index = tokens.index("^")
|
||||
|
||||
lower_bound = tokens[underscore_index + 1] if underscore_index else None
|
||||
upper_bound = tokens[caret_index + 1] if caret_index else None
|
||||
|
||||
# we can't simply do something like `if (lower_bound and not upper_bound) ...` because this would
|
||||
# evaluate to `True` if the `lower_bound` is 0 and upper bound is non-zero
|
||||
if lower_bound is not None and upper_bound is None:
|
||||
# then one was given and the other wasn't
|
||||
raise LaTeXParsingError("Lower bound for the integral was found, but upper bound was not found.")
|
||||
|
||||
if upper_bound is not None and lower_bound is None:
|
||||
# then one was given and the other wasn't
|
||||
raise LaTeXParsingError("Upper bound for the integral was found, but lower bound was not found.")
|
||||
|
||||
integrand, differential_variable = tokens[-1]
|
||||
|
||||
if lower_bound is not None:
|
||||
# then we have a definite integral
|
||||
|
||||
# we can assume that either both the lower and upper bounds are given, or
|
||||
# neither of them are
|
||||
return sympy.Integral(integrand, (differential_variable, lower_bound, upper_bound))
|
||||
else:
|
||||
# we have an indefinite integral
|
||||
return sympy.Integral(integrand, differential_variable)
|
||||
|
||||
def group_curly_parentheses_special(self, tokens):
|
||||
underscore_index = tokens.index("_")
|
||||
caret_index = tokens.index("^")
|
||||
|
||||
# given the type of expressions we are parsing, we can assume that the lower limit
|
||||
# will always use braces around its arguments. This is because we don't support
|
||||
# converting unconstrained sums into SymPy expressions.
|
||||
|
||||
# first we isolate the bottom limit
|
||||
left_brace_index = tokens.index("{", underscore_index)
|
||||
right_brace_index = tokens.index("}", underscore_index)
|
||||
|
||||
bottom_limit = tokens[left_brace_index + 1: right_brace_index]
|
||||
|
||||
# next, we isolate the upper limit
|
||||
top_limit = tokens[caret_index + 1:]
|
||||
|
||||
# the code below will be useful for supporting things like `\sum_{n = 0}^{n = 5} n^2`
|
||||
# if "{" in top_limit:
|
||||
# left_brace_index = tokens.index("{", caret_index)
|
||||
# if left_brace_index != -1:
|
||||
# # then there's a left brace in the string, and we need to find the closing right brace
|
||||
# right_brace_index = tokens.index("}", caret_index)
|
||||
# top_limit = tokens[left_brace_index + 1: right_brace_index]
|
||||
|
||||
# print(f"top limit = {top_limit}")
|
||||
|
||||
index_variable = bottom_limit[0]
|
||||
lower_limit = bottom_limit[-1]
|
||||
upper_limit = top_limit[0] # for now, the index will always be 0
|
||||
|
||||
# print(f"return value = ({index_variable}, {lower_limit}, {upper_limit})")
|
||||
|
||||
return index_variable, lower_limit, upper_limit
|
||||
|
||||
def summation(self, tokens):
|
||||
return sympy.Sum(tokens[2], tokens[1])
|
||||
|
||||
def product(self, tokens):
|
||||
return sympy.Product(tokens[2], tokens[1])
|
||||
|
||||
def limit_dir_expr(self, tokens):
|
||||
caret_index = tokens.index("^")
|
||||
|
||||
if "{" in tokens:
|
||||
left_curly_brace_index = tokens.index("{", caret_index)
|
||||
direction = tokens[left_curly_brace_index + 1]
|
||||
else:
|
||||
direction = tokens[caret_index + 1]
|
||||
|
||||
if direction == "+":
|
||||
return tokens[0], "+"
|
||||
elif direction == "-":
|
||||
return tokens[0], "-"
|
||||
else:
|
||||
return tokens[0], "+-"
|
||||
|
||||
def group_curly_parentheses_lim(self, tokens):
|
||||
limit_variable = tokens[1]
|
||||
if isinstance(tokens[3], tuple):
|
||||
destination, direction = tokens[3]
|
||||
else:
|
||||
destination = tokens[3]
|
||||
direction = "+-"
|
||||
|
||||
return limit_variable, destination, direction
|
||||
|
||||
def limit(self, tokens):
|
||||
limit_variable, destination, direction = tokens[2]
|
||||
|
||||
return sympy.Limit(tokens[-1], limit_variable, destination, direction)
|
||||
|
||||
def differential(self, tokens):
|
||||
return tokens[1]
|
||||
|
||||
def derivative(self, tokens):
|
||||
return sympy.Derivative(tokens[-1], tokens[5])
|
||||
|
||||
def list_of_expressions(self, tokens):
|
||||
if len(tokens) == 1:
|
||||
# we return it verbatim because the function_applied node expects
|
||||
# a list
|
||||
return tokens
|
||||
else:
|
||||
def remove_tokens(args):
|
||||
if isinstance(args, Token):
|
||||
if args.type != "COMMA":
|
||||
# An unexpected token was encountered
|
||||
raise LaTeXParsingError("A comma token was expected, but some other token was encountered.")
|
||||
return False
|
||||
return True
|
||||
|
||||
return filter(remove_tokens, tokens)
|
||||
|
||||
def function_applied(self, tokens):
|
||||
return sympy.Function(tokens[0])(*tokens[2])
|
||||
|
||||
def min(self, tokens):
|
||||
return sympy.Min(*tokens[2])
|
||||
|
||||
def max(self, tokens):
|
||||
return sympy.Max(*tokens[2])
|
||||
|
||||
def bra(self, tokens):
|
||||
from sympy.physics.quantum import Bra
|
||||
return Bra(tokens[1])
|
||||
|
||||
def ket(self, tokens):
|
||||
from sympy.physics.quantum import Ket
|
||||
return Ket(tokens[1])
|
||||
|
||||
def inner_product(self, tokens):
|
||||
from sympy.physics.quantum import Bra, Ket, InnerProduct
|
||||
return InnerProduct(Bra(tokens[1]), Ket(tokens[3]))
|
||||
|
||||
def sin(self, tokens):
|
||||
return sympy.sin(tokens[1])
|
||||
|
||||
def cos(self, tokens):
|
||||
return sympy.cos(tokens[1])
|
||||
|
||||
def tan(self, tokens):
|
||||
return sympy.tan(tokens[1])
|
||||
|
||||
def csc(self, tokens):
|
||||
return sympy.csc(tokens[1])
|
||||
|
||||
def sec(self, tokens):
|
||||
return sympy.sec(tokens[1])
|
||||
|
||||
def cot(self, tokens):
|
||||
return sympy.cot(tokens[1])
|
||||
|
||||
def sin_power(self, tokens):
|
||||
exponent = tokens[2]
|
||||
if exponent == -1:
|
||||
return sympy.asin(tokens[-1])
|
||||
else:
|
||||
return sympy.Pow(sympy.sin(tokens[-1]), exponent)
|
||||
|
||||
def cos_power(self, tokens):
|
||||
exponent = tokens[2]
|
||||
if exponent == -1:
|
||||
return sympy.acos(tokens[-1])
|
||||
else:
|
||||
return sympy.Pow(sympy.cos(tokens[-1]), exponent)
|
||||
|
||||
def tan_power(self, tokens):
|
||||
exponent = tokens[2]
|
||||
if exponent == -1:
|
||||
return sympy.atan(tokens[-1])
|
||||
else:
|
||||
return sympy.Pow(sympy.tan(tokens[-1]), exponent)
|
||||
|
||||
def csc_power(self, tokens):
|
||||
exponent = tokens[2]
|
||||
if exponent == -1:
|
||||
return sympy.acsc(tokens[-1])
|
||||
else:
|
||||
return sympy.Pow(sympy.csc(tokens[-1]), exponent)
|
||||
|
||||
def sec_power(self, tokens):
|
||||
exponent = tokens[2]
|
||||
if exponent == -1:
|
||||
return sympy.asec(tokens[-1])
|
||||
else:
|
||||
return sympy.Pow(sympy.sec(tokens[-1]), exponent)
|
||||
|
||||
def cot_power(self, tokens):
|
||||
exponent = tokens[2]
|
||||
if exponent == -1:
|
||||
return sympy.acot(tokens[-1])
|
||||
else:
|
||||
return sympy.Pow(sympy.cot(tokens[-1]), exponent)
|
||||
|
||||
def arcsin(self, tokens):
|
||||
return sympy.asin(tokens[1])
|
||||
|
||||
def arccos(self, tokens):
|
||||
return sympy.acos(tokens[1])
|
||||
|
||||
def arctan(self, tokens):
|
||||
return sympy.atan(tokens[1])
|
||||
|
||||
def arccsc(self, tokens):
|
||||
return sympy.acsc(tokens[1])
|
||||
|
||||
def arcsec(self, tokens):
|
||||
return sympy.asec(tokens[1])
|
||||
|
||||
def arccot(self, tokens):
|
||||
return sympy.acot(tokens[1])
|
||||
|
||||
def sinh(self, tokens):
|
||||
return sympy.sinh(tokens[1])
|
||||
|
||||
def cosh(self, tokens):
|
||||
return sympy.cosh(tokens[1])
|
||||
|
||||
def tanh(self, tokens):
|
||||
return sympy.tanh(tokens[1])
|
||||
|
||||
def asinh(self, tokens):
|
||||
return sympy.asinh(tokens[1])
|
||||
|
||||
def acosh(self, tokens):
|
||||
return sympy.acosh(tokens[1])
|
||||
|
||||
def atanh(self, tokens):
|
||||
return sympy.atanh(tokens[1])
|
||||
|
||||
def abs(self, tokens):
|
||||
return sympy.Abs(tokens[1])
|
||||
|
||||
def floor(self, tokens):
|
||||
return sympy.floor(tokens[1])
|
||||
|
||||
def ceil(self, tokens):
|
||||
return sympy.ceiling(tokens[1])
|
||||
|
||||
def factorial(self, tokens):
|
||||
return sympy.factorial(tokens[0])
|
||||
|
||||
def conjugate(self, tokens):
|
||||
return sympy.conjugate(tokens[1])
|
||||
|
||||
def square_root(self, tokens):
|
||||
if len(tokens) == 2:
|
||||
# then there was no square bracket argument
|
||||
return sympy.sqrt(tokens[1])
|
||||
elif len(tokens) == 3:
|
||||
# then there _was_ a square bracket argument
|
||||
return sympy.root(tokens[2], tokens[1])
|
||||
|
||||
def exponential(self, tokens):
|
||||
return sympy.exp(tokens[1])
|
||||
|
||||
def log(self, tokens):
|
||||
if tokens[0].type == "FUNC_LG":
|
||||
# we don't need to check if there's an underscore or not because having one
|
||||
# in this case would be meaningless
|
||||
# TODO: ANTLR refers to ISO 80000-2:2019. should we keep base 10 or base 2?
|
||||
return sympy.log(tokens[1], 10)
|
||||
elif tokens[0].type == "FUNC_LN":
|
||||
return sympy.log(tokens[1])
|
||||
elif tokens[0].type == "FUNC_LOG":
|
||||
# we check if a base was specified or not
|
||||
if "_" in tokens:
|
||||
# then a base was specified
|
||||
return sympy.log(tokens[3], tokens[2])
|
||||
else:
|
||||
# a base was not specified
|
||||
return sympy.log(tokens[1])
|
||||
|
||||
def _extract_differential_symbol(self, s: str):
|
||||
differential_symbols = {"d", r"\text{d}", r"\mathrm{d}"}
|
||||
|
||||
differential_symbol = next((symbol for symbol in differential_symbols if symbol in s), None)
|
||||
|
||||
return differential_symbol
|
||||
|
||||
def matrix(self, tokens):
|
||||
def is_matrix_row(x):
|
||||
return (isinstance(x, Tree) and x.data == "matrix_row")
|
||||
|
||||
def is_not_col_delim(y):
|
||||
return (not isinstance(y, Token) or y.type != "MATRIX_COL_DELIM")
|
||||
|
||||
matrix_body = tokens[1].children
|
||||
return sympy.Matrix([[y for y in x.children if is_not_col_delim(y)]
|
||||
for x in matrix_body if is_matrix_row(x)])
|
||||
|
||||
def determinant(self, tokens):
|
||||
if len(tokens) == 2: # \det A
|
||||
if not self._obj_is_sympy_Matrix(tokens[1]):
|
||||
raise LaTeXParsingError("Cannot take determinant of non-matrix.")
|
||||
|
||||
return tokens[1].det()
|
||||
|
||||
if len(tokens) == 3: # | A |
|
||||
return self.matrix(tokens).det()
|
||||
|
||||
def trace(self, tokens):
|
||||
if not self._obj_is_sympy_Matrix(tokens[1]):
|
||||
raise LaTeXParsingError("Cannot take trace of non-matrix.")
|
||||
|
||||
return sympy.Trace(tokens[1])
|
||||
|
||||
def adjugate(self, tokens):
|
||||
if not self._obj_is_sympy_Matrix(tokens[1]):
|
||||
raise LaTeXParsingError("Cannot take adjugate of non-matrix.")
|
||||
|
||||
# need .doit() since MatAdd does not support .adjugate() method
|
||||
return tokens[1].doit().adjugate()
|
||||
|
||||
def _obj_is_sympy_Matrix(self, obj):
|
||||
if hasattr(obj, "is_Matrix"):
|
||||
return obj.is_Matrix
|
||||
|
||||
return isinstance(obj, sympy.Matrix)
|
||||
|
||||
def _handle_division(self, numerator, denominator):
|
||||
if self._obj_is_sympy_Matrix(denominator):
|
||||
raise LaTeXParsingError("Cannot divide by matrices like this since "
|
||||
"it is not clear if left or right multiplication "
|
||||
"by the inverse is intended. Try explicitly "
|
||||
"multiplying by the inverse instead.")
|
||||
|
||||
if self._obj_is_sympy_Matrix(numerator):
|
||||
return sympy.MatMul(numerator, sympy.Pow(denominator, -1))
|
||||
|
||||
return sympy.Mul(numerator, sympy.Pow(denominator, -1))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,71 @@
|
||||
import re
|
||||
from sympy.concrete.products import product
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
|
||||
|
||||
class MaximaHelpers:
|
||||
def maxima_expand(expr):
|
||||
return expr.expand()
|
||||
|
||||
def maxima_float(expr):
|
||||
return expr.evalf()
|
||||
|
||||
def maxima_trigexpand(expr):
|
||||
return expr.expand(trig=True)
|
||||
|
||||
def maxima_sum(a1, a2, a3, a4):
|
||||
return Sum(a1, (a2, a3, a4)).doit()
|
||||
|
||||
def maxima_product(a1, a2, a3, a4):
|
||||
return product(a1, (a2, a3, a4))
|
||||
|
||||
def maxima_csc(expr):
|
||||
return 1/sin(expr)
|
||||
|
||||
def maxima_sec(expr):
|
||||
return 1/cos(expr)
|
||||
|
||||
sub_dict = {
|
||||
'pi': re.compile(r'%pi'),
|
||||
'E': re.compile(r'%e'),
|
||||
'I': re.compile(r'%i'),
|
||||
'**': re.compile(r'\^'),
|
||||
'oo': re.compile(r'\binf\b'),
|
||||
'-oo': re.compile(r'\bminf\b'),
|
||||
"'-'": re.compile(r'\bminus\b'),
|
||||
'maxima_expand': re.compile(r'\bexpand\b'),
|
||||
'maxima_float': re.compile(r'\bfloat\b'),
|
||||
'maxima_trigexpand': re.compile(r'\btrigexpand'),
|
||||
'maxima_sum': re.compile(r'\bsum\b'),
|
||||
'maxima_product': re.compile(r'\bproduct\b'),
|
||||
'cancel': re.compile(r'\bratsimp\b'),
|
||||
'maxima_csc': re.compile(r'\bcsc\b'),
|
||||
'maxima_sec': re.compile(r'\bsec\b')
|
||||
}
|
||||
|
||||
var_name = re.compile(r'^\s*(\w+)\s*:')
|
||||
|
||||
|
||||
def parse_maxima(str, globals=None, name_dict={}):
|
||||
str = str.strip()
|
||||
str = str.rstrip('; ')
|
||||
|
||||
for k, v in sub_dict.items():
|
||||
str = v.sub(k, str)
|
||||
|
||||
assign_var = None
|
||||
var_match = var_name.search(str)
|
||||
if var_match:
|
||||
assign_var = var_match.group(1)
|
||||
str = str[var_match.end():].strip()
|
||||
|
||||
dct = MaximaHelpers.__dict__.copy()
|
||||
dct.update(name_dict)
|
||||
obj = sympify(str, locals=dct)
|
||||
|
||||
if assign_var and globals:
|
||||
globals[assign_var] = obj
|
||||
|
||||
return obj
|
||||
@@ -0,0 +1,279 @@
|
||||
from sympy.printing import pycode, ccode, fcode
|
||||
from sympy.external import import_module
|
||||
from sympy.utilities.decorator import doctest_depends_on
|
||||
|
||||
lfortran = import_module('lfortran')
|
||||
cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']})
|
||||
|
||||
if lfortran:
|
||||
from sympy.parsing.fortran.fortran_parser import src_to_sympy
|
||||
if cin:
|
||||
from sympy.parsing.c.c_parser import parse_c
|
||||
|
||||
@doctest_depends_on(modules=['lfortran', 'clang.cindex'])
|
||||
class SymPyExpression: # type: ignore
|
||||
"""Class to store and handle SymPy expressions
|
||||
|
||||
This class will hold SymPy Expressions and handle the API for the
|
||||
conversion to and from different languages.
|
||||
|
||||
It works with the C and the Fortran Parser to generate SymPy expressions
|
||||
which are stored here and which can be converted to multiple language's
|
||||
source code.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
The module and its API are currently under development and experimental
|
||||
and can be changed during development.
|
||||
|
||||
The Fortran parser does not support numeric assignments, so all the
|
||||
variables have been Initialized to zero.
|
||||
|
||||
The module also depends on external dependencies:
|
||||
|
||||
- LFortran which is required to use the Fortran parser
|
||||
- Clang which is required for the C parser
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Example of parsing C code:
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src = '''
|
||||
... int a,b;
|
||||
... float c = 2, d =4;
|
||||
... '''
|
||||
>>> a = SymPyExpression(src, 'c')
|
||||
>>> a.return_expr()
|
||||
[Declaration(Variable(a, type=intc)),
|
||||
Declaration(Variable(b, type=intc)),
|
||||
Declaration(Variable(c, type=float32, value=2.0)),
|
||||
Declaration(Variable(d, type=float32, value=4.0))]
|
||||
|
||||
An example of variable definition:
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src2 = '''
|
||||
... integer :: a, b, c, d
|
||||
... real :: p, q, r, s
|
||||
... '''
|
||||
>>> p = SymPyExpression()
|
||||
>>> p.convert_to_expr(src2, 'f')
|
||||
>>> p.convert_to_c()
|
||||
['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0']
|
||||
|
||||
An example of Assignment:
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src3 = '''
|
||||
... integer :: a, b, c, d, e
|
||||
... d = a + b - c
|
||||
... e = b * d + c * e / a
|
||||
... '''
|
||||
>>> p = SymPyExpression(src3, 'f')
|
||||
>>> p.convert_to_python()
|
||||
['a = 0', 'b = 0', 'c = 0', 'd = 0', 'e = 0', 'd = a + b - c', 'e = b*d + c*e/a']
|
||||
|
||||
An example of function definition:
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src = '''
|
||||
... integer function f(a,b)
|
||||
... integer, intent(in) :: a, b
|
||||
... integer :: r
|
||||
... end function
|
||||
... '''
|
||||
>>> a = SymPyExpression(src, 'f')
|
||||
>>> a.convert_to_python()
|
||||
['def f(a, b):\\n f = 0\\n r = 0\\n return f']
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, source_code = None, mode = None):
|
||||
"""Constructor for SymPyExpression class"""
|
||||
super().__init__()
|
||||
if not(mode or source_code):
|
||||
self._expr = []
|
||||
elif mode:
|
||||
if source_code:
|
||||
if mode.lower() == 'f':
|
||||
if lfortran:
|
||||
self._expr = src_to_sympy(source_code)
|
||||
else:
|
||||
raise ImportError("LFortran is not installed, cannot parse Fortran code")
|
||||
elif mode.lower() == 'c':
|
||||
if cin:
|
||||
self._expr = parse_c(source_code)
|
||||
else:
|
||||
raise ImportError("Clang is not installed, cannot parse C code")
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
'Parser for specified language is not implemented'
|
||||
)
|
||||
else:
|
||||
raise ValueError('Source code not present')
|
||||
else:
|
||||
raise ValueError('Please specify a mode for conversion')
|
||||
|
||||
def convert_to_expr(self, src_code, mode):
|
||||
"""Converts the given source code to SymPy Expressions
|
||||
|
||||
Attributes
|
||||
==========
|
||||
|
||||
src_code : String
|
||||
the source code or filename of the source code that is to be
|
||||
converted
|
||||
|
||||
mode: String
|
||||
the mode to determine which parser is to be used according to
|
||||
the language of the source code
|
||||
f or F for Fortran
|
||||
c or C for C/C++
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src3 = '''
|
||||
... integer function f(a,b) result(r)
|
||||
... integer, intent(in) :: a, b
|
||||
... integer :: x
|
||||
... r = a + b -x
|
||||
... end function
|
||||
... '''
|
||||
>>> p = SymPyExpression()
|
||||
>>> p.convert_to_expr(src3, 'f')
|
||||
>>> p.return_expr()
|
||||
[FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock(
|
||||
Declaration(Variable(r, type=integer, value=0)),
|
||||
Declaration(Variable(x, type=integer, value=0)),
|
||||
Assignment(Variable(r), a + b - x),
|
||||
Return(Variable(r))
|
||||
))]
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
if mode.lower() == 'f':
|
||||
if lfortran:
|
||||
self._expr = src_to_sympy(src_code)
|
||||
else:
|
||||
raise ImportError("LFortran is not installed, cannot parse Fortran code")
|
||||
elif mode.lower() == 'c':
|
||||
if cin:
|
||||
self._expr = parse_c(src_code)
|
||||
else:
|
||||
raise ImportError("Clang is not installed, cannot parse C code")
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"Parser for specified language has not been implemented"
|
||||
)
|
||||
|
||||
def convert_to_python(self):
|
||||
"""Returns a list with Python code for the SymPy expressions
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src2 = '''
|
||||
... integer :: a, b, c, d
|
||||
... real :: p, q, r, s
|
||||
... c = a/b
|
||||
... d = c/a
|
||||
... s = p/q
|
||||
... r = q/p
|
||||
... '''
|
||||
>>> p = SymPyExpression(src2, 'f')
|
||||
>>> p.convert_to_python()
|
||||
['a = 0', 'b = 0', 'c = 0', 'd = 0', 'p = 0.0', 'q = 0.0', 'r = 0.0', 's = 0.0', 'c = a/b', 'd = c/a', 's = p/q', 'r = q/p']
|
||||
|
||||
"""
|
||||
self._pycode = []
|
||||
for iter in self._expr:
|
||||
self._pycode.append(pycode(iter))
|
||||
return self._pycode
|
||||
|
||||
def convert_to_c(self):
|
||||
"""Returns a list with the c source code for the SymPy expressions
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src2 = '''
|
||||
... integer :: a, b, c, d
|
||||
... real :: p, q, r, s
|
||||
... c = a/b
|
||||
... d = c/a
|
||||
... s = p/q
|
||||
... r = q/p
|
||||
... '''
|
||||
>>> p = SymPyExpression()
|
||||
>>> p.convert_to_expr(src2, 'f')
|
||||
>>> p.convert_to_c()
|
||||
['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0', 'c = a/b;', 'd = c/a;', 's = p/q;', 'r = q/p;']
|
||||
|
||||
"""
|
||||
self._ccode = []
|
||||
for iter in self._expr:
|
||||
self._ccode.append(ccode(iter))
|
||||
return self._ccode
|
||||
|
||||
def convert_to_fortran(self):
|
||||
"""Returns a list with the fortran source code for the SymPy expressions
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src2 = '''
|
||||
... integer :: a, b, c, d
|
||||
... real :: p, q, r, s
|
||||
... c = a/b
|
||||
... d = c/a
|
||||
... s = p/q
|
||||
... r = q/p
|
||||
... '''
|
||||
>>> p = SymPyExpression(src2, 'f')
|
||||
>>> p.convert_to_fortran()
|
||||
[' integer*4 a', ' integer*4 b', ' integer*4 c', ' integer*4 d', ' real*8 p', ' real*8 q', ' real*8 r', ' real*8 s', ' c = a/b', ' d = c/a', ' s = p/q', ' r = q/p']
|
||||
|
||||
"""
|
||||
self._fcode = []
|
||||
for iter in self._expr:
|
||||
self._fcode.append(fcode(iter))
|
||||
return self._fcode
|
||||
|
||||
def return_expr(self):
|
||||
"""Returns the expression list
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
>>> from sympy.parsing.sym_expr import SymPyExpression
|
||||
>>> src3 = '''
|
||||
... integer function f(a,b)
|
||||
... integer, intent(in) :: a, b
|
||||
... integer :: r
|
||||
... r = a+b
|
||||
... f = r
|
||||
... end function
|
||||
... '''
|
||||
>>> p = SymPyExpression()
|
||||
>>> p.convert_to_expr(src3, 'f')
|
||||
>>> p.return_expr()
|
||||
[FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock(
|
||||
Declaration(Variable(f, type=integer, value=0)),
|
||||
Declaration(Variable(r, type=integer, value=0)),
|
||||
Assignment(Variable(f), Variable(r)),
|
||||
Return(Variable(f))
|
||||
))]
|
||||
|
||||
"""
|
||||
return self._expr
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
from sympy.core.singleton import S
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.parsing.ast_parser import parse_expr
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.core.sympify import SympifyError
|
||||
import warnings
|
||||
|
||||
def test_parse_expr():
|
||||
a, b = symbols('a, b')
|
||||
# tests issue_16393
|
||||
assert parse_expr('a + b', {}) == a + b
|
||||
raises(SympifyError, lambda: parse_expr('a + ', {}))
|
||||
|
||||
# tests Transform.visit_Constant
|
||||
assert parse_expr('1 + 2', {}) == S(3)
|
||||
assert parse_expr('1 + 2.0', {}) == S(3.0)
|
||||
|
||||
# tests Transform.visit_Name
|
||||
assert parse_expr('Rational(1, 2)', {}) == S(1)/2
|
||||
assert parse_expr('a', {'a': a}) == a
|
||||
|
||||
# tests issue_23092
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('error')
|
||||
assert parse_expr('6 * 7', {}) == S(42)
|
||||
@@ -0,0 +1,178 @@
|
||||
import os
|
||||
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.external import import_module
|
||||
from sympy.testing.pytest import skip
|
||||
from sympy.parsing.autolev import parse_autolev
|
||||
|
||||
antlr4 = import_module("antlr4")
|
||||
|
||||
if not antlr4:
|
||||
disabled = True
|
||||
|
||||
FILE_DIR = os.path.dirname(
|
||||
os.path.dirname(os.path.abspath(os.path.realpath(__file__))))
|
||||
|
||||
|
||||
def _test_examples(in_filename, out_filename, test_name=""):
|
||||
|
||||
in_file_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
|
||||
in_filename)
|
||||
correct_file_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
|
||||
out_filename)
|
||||
with open(in_file_path) as f:
|
||||
generated_code = parse_autolev(f, include_numeric=True)
|
||||
|
||||
with open(correct_file_path) as f:
|
||||
for idx, line1 in enumerate(f):
|
||||
if line1.startswith("#"):
|
||||
break
|
||||
try:
|
||||
line2 = generated_code.split('\n')[idx]
|
||||
assert line1.rstrip() == line2.rstrip()
|
||||
except Exception:
|
||||
msg = 'mismatch in ' + test_name + ' in line no: {0}'
|
||||
raise AssertionError(msg.format(idx+1))
|
||||
|
||||
|
||||
def test_rule_tests():
|
||||
|
||||
l = ["ruletest1", "ruletest2", "ruletest3", "ruletest4", "ruletest5",
|
||||
"ruletest6", "ruletest7", "ruletest8", "ruletest9", "ruletest10",
|
||||
"ruletest11", "ruletest12"]
|
||||
|
||||
for i in l:
|
||||
in_filepath = i + ".al"
|
||||
out_filepath = i + ".py"
|
||||
_test_examples(in_filepath, out_filepath, i)
|
||||
|
||||
|
||||
def test_pydy_examples():
|
||||
|
||||
l = ["mass_spring_damper", "chaos_pendulum", "double_pendulum",
|
||||
"non_min_pendulum"]
|
||||
|
||||
for i in l:
|
||||
in_filepath = os.path.join("pydy-example-repo", i + ".al")
|
||||
out_filepath = os.path.join("pydy-example-repo", i + ".py")
|
||||
_test_examples(in_filepath, out_filepath, i)
|
||||
|
||||
|
||||
def test_autolev_tutorial():
|
||||
|
||||
dir_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
|
||||
'autolev-tutorial')
|
||||
|
||||
if os.path.isdir(dir_path):
|
||||
l = ["tutor1", "tutor2", "tutor3", "tutor4", "tutor5", "tutor6",
|
||||
"tutor7"]
|
||||
for i in l:
|
||||
in_filepath = os.path.join("autolev-tutorial", i + ".al")
|
||||
out_filepath = os.path.join("autolev-tutorial", i + ".py")
|
||||
_test_examples(in_filepath, out_filepath, i)
|
||||
|
||||
|
||||
def test_dynamics_online():
|
||||
|
||||
dir_path = os.path.join(FILE_DIR, 'autolev', 'test-examples',
|
||||
'dynamics-online')
|
||||
|
||||
if os.path.isdir(dir_path):
|
||||
ch1 = ["1-4", "1-5", "1-6", "1-7", "1-8", "1-9_1", "1-9_2", "1-9_3"]
|
||||
ch2 = ["2-1", "2-2", "2-3", "2-4", "2-5", "2-6", "2-7", "2-8", "2-9",
|
||||
"circular"]
|
||||
ch3 = ["3-1_1", "3-1_2", "3-2_1", "3-2_2", "3-2_3", "3-2_4", "3-2_5",
|
||||
"3-3"]
|
||||
ch4 = ["4-1_1", "4-2_1", "4-4_1", "4-4_2", "4-5_1", "4-5_2"]
|
||||
chapters = [(ch1, "ch1"), (ch2, "ch2"), (ch3, "ch3"), (ch4, "ch4")]
|
||||
for ch, name in chapters:
|
||||
for i in ch:
|
||||
in_filepath = os.path.join("dynamics-online", name, i + ".al")
|
||||
out_filepath = os.path.join("dynamics-online", name, i + ".py")
|
||||
_test_examples(in_filepath, out_filepath, i)
|
||||
|
||||
|
||||
def test_output_01():
|
||||
"""Autolev example calculates the position, velocity, and acceleration of a
|
||||
point and expresses in a single reference frame::
|
||||
|
||||
(1) FRAMES C,D,F
|
||||
(2) VARIABLES FD'',DC''
|
||||
(3) CONSTANTS R,L
|
||||
(4) POINTS O,E
|
||||
(5) SIMPROT(F,D,1,FD)
|
||||
-> (6) F_D = [1, 0, 0; 0, COS(FD), -SIN(FD); 0, SIN(FD), COS(FD)]
|
||||
(7) SIMPROT(D,C,2,DC)
|
||||
-> (8) D_C = [COS(DC), 0, SIN(DC); 0, 1, 0; -SIN(DC), 0, COS(DC)]
|
||||
(9) W_C_F> = EXPRESS(W_C_F>, F)
|
||||
-> (10) W_C_F> = FD'*F1> + COS(FD)*DC'*F2> + SIN(FD)*DC'*F3>
|
||||
(11) P_O_E>=R*D2>-L*C1>
|
||||
(12) P_O_E>=EXPRESS(P_O_E>, D)
|
||||
-> (13) P_O_E> = -L*COS(DC)*D1> + R*D2> + L*SIN(DC)*D3>
|
||||
(14) V_E_F>=EXPRESS(DT(P_O_E>,F),D)
|
||||
-> (15) V_E_F> = L*SIN(DC)*DC'*D1> - L*SIN(DC)*FD'*D2> + (R*FD'+L*COS(DC)*DC')*D3>
|
||||
(16) A_E_F>=EXPRESS(DT(V_E_F>,F),D)
|
||||
-> (17) A_E_F> = L*(COS(DC)*DC'^2+SIN(DC)*DC'')*D1> + (-R*FD'^2-2*L*COS(DC)*DC'*FD'-L*SIN(DC)*FD'')*D2> + (R*FD''+L*COS(DC)*DC''-L*SIN(DC)*DC'^2-L*SIN(DC)*FD'^2)*D3>
|
||||
|
||||
"""
|
||||
|
||||
if not antlr4:
|
||||
skip('Test skipped: antlr4 is not installed.')
|
||||
|
||||
autolev_input = """\
|
||||
FRAMES C,D,F
|
||||
VARIABLES FD'',DC''
|
||||
CONSTANTS R,L
|
||||
POINTS O,E
|
||||
SIMPROT(F,D,1,FD)
|
||||
SIMPROT(D,C,2,DC)
|
||||
W_C_F>=EXPRESS(W_C_F>,F)
|
||||
P_O_E>=R*D2>-L*C1>
|
||||
P_O_E>=EXPRESS(P_O_E>,D)
|
||||
V_E_F>=EXPRESS(DT(P_O_E>,F),D)
|
||||
A_E_F>=EXPRESS(DT(V_E_F>,F),D)\
|
||||
"""
|
||||
|
||||
sympy_input = parse_autolev(autolev_input)
|
||||
|
||||
g = {}
|
||||
l = {}
|
||||
exec(sympy_input, g, l)
|
||||
|
||||
w_c_f = l['frame_c'].ang_vel_in(l['frame_f'])
|
||||
# P_O_E> means "the position of point E wrt to point O"
|
||||
p_o_e = l['point_e'].pos_from(l['point_o'])
|
||||
v_e_f = l['point_e'].vel(l['frame_f'])
|
||||
a_e_f = l['point_e'].acc(l['frame_f'])
|
||||
|
||||
# NOTE : The Autolev outputs above were manually transformed into
|
||||
# equivalent SymPy physics vector expressions. Would be nice to automate
|
||||
# this transformation.
|
||||
expected_w_c_f = (l['fd'].diff()*l['frame_f'].x +
|
||||
cos(l['fd'])*l['dc'].diff()*l['frame_f'].y +
|
||||
sin(l['fd'])*l['dc'].diff()*l['frame_f'].z)
|
||||
|
||||
assert (w_c_f - expected_w_c_f).simplify() == 0
|
||||
|
||||
expected_p_o_e = (-l['l']*cos(l['dc'])*l['frame_d'].x +
|
||||
l['r']*l['frame_d'].y +
|
||||
l['l']*sin(l['dc'])*l['frame_d'].z)
|
||||
|
||||
assert (p_o_e - expected_p_o_e).simplify() == 0
|
||||
|
||||
expected_v_e_f = (l['l']*sin(l['dc'])*l['dc'].diff()*l['frame_d'].x -
|
||||
l['l']*sin(l['dc'])*l['fd'].diff()*l['frame_d'].y +
|
||||
(l['r']*l['fd'].diff() +
|
||||
l['l']*cos(l['dc'])*l['dc'].diff())*l['frame_d'].z)
|
||||
assert (v_e_f - expected_v_e_f).simplify() == 0
|
||||
|
||||
expected_a_e_f = (l['l']*(cos(l['dc'])*l['dc'].diff()**2 +
|
||||
sin(l['dc'])*l['dc'].diff().diff())*l['frame_d'].x +
|
||||
(-l['r']*l['fd'].diff()**2 -
|
||||
2*l['l']*cos(l['dc'])*l['dc'].diff()*l['fd'].diff() -
|
||||
l['l']*sin(l['dc'])*l['fd'].diff().diff())*l['frame_d'].y +
|
||||
(l['r']*l['fd'].diff().diff() +
|
||||
l['l']*cos(l['dc'])*l['dc'].diff().diff() -
|
||||
l['l']*sin(l['dc'])*l['dc'].diff()**2 -
|
||||
l['l']*sin(l['dc'])*l['fd'].diff()**2)*l['frame_d'].z)
|
||||
assert (a_e_f - expected_a_e_f).simplify() == 0
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import sympy
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.parsing.latex.lark import LarkLaTeXParser, TransformToSymPyExpr, parse_latex_lark
|
||||
from sympy.external import import_module
|
||||
|
||||
lark = import_module("lark")
|
||||
|
||||
# disable tests if lark is not present
|
||||
disabled = lark is None
|
||||
|
||||
grammar_file = os.path.join(os.path.dirname(__file__), "../latex/lark/grammar/latex.lark")
|
||||
|
||||
modification1 = """
|
||||
%override DIV_SYMBOL: DIV
|
||||
%override MUL_SYMBOL: MUL | CMD_TIMES
|
||||
"""
|
||||
|
||||
modification2 = r"""
|
||||
%override number: /\d+(,\d*)?/
|
||||
"""
|
||||
|
||||
def init_custom_parser(modification, transformer=None):
|
||||
latex_grammar = Path(grammar_file).read_text(encoding="utf-8")
|
||||
latex_grammar += modification
|
||||
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
f.write(bytes(latex_grammar, encoding="utf8"))
|
||||
f.flush()
|
||||
|
||||
parser = LarkLaTeXParser(grammar_file=f.name, transformer=transformer)
|
||||
|
||||
return parser
|
||||
|
||||
def test_custom1():
|
||||
# Removes the parser's ability to understand \cdot and \div.
|
||||
|
||||
parser = init_custom_parser(modification1)
|
||||
|
||||
with raises(lark.exceptions.UnexpectedCharacters):
|
||||
parser.doparse(r"a \cdot b")
|
||||
parser.doparse(r"x \div y")
|
||||
|
||||
class CustomTransformer(TransformToSymPyExpr):
|
||||
def number(self, tokens):
|
||||
if "," in tokens[0]:
|
||||
# The Float constructor expects a dot as the decimal separator
|
||||
return sympy.core.numbers.Float(tokens[0].replace(",", "."))
|
||||
else:
|
||||
return sympy.core.numbers.Integer(tokens[0])
|
||||
|
||||
def test_custom2():
|
||||
# Makes the parser parse commas as the decimal separator instead of dots
|
||||
|
||||
parser = init_custom_parser(modification2, CustomTransformer)
|
||||
|
||||
with raises(lark.exceptions.UnexpectedCharacters):
|
||||
# Asserting that the default parser cannot parse numbers which have commas as
|
||||
# the decimal separator
|
||||
parse_latex_lark("100,1")
|
||||
parse_latex_lark("0,009")
|
||||
|
||||
parser.doparse("100,1")
|
||||
parser.doparse("0,009")
|
||||
parser.doparse("2,71828")
|
||||
parser.doparse("3,14159")
|
||||
@@ -0,0 +1,406 @@
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.parsing.sym_expr import SymPyExpression
|
||||
from sympy.external import import_module
|
||||
|
||||
lfortran = import_module('lfortran')
|
||||
|
||||
if lfortran:
|
||||
from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String,
|
||||
Return, FunctionDefinition, Assignment,
|
||||
Declaration, CodeBlock)
|
||||
from sympy.core import Integer, Float, Add
|
||||
from sympy.core.symbol import Symbol
|
||||
|
||||
|
||||
expr1 = SymPyExpression()
|
||||
expr2 = SymPyExpression()
|
||||
src = """\
|
||||
integer :: a, b, c, d
|
||||
real :: p, q, r, s
|
||||
"""
|
||||
|
||||
|
||||
def test_sym_expr():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
d = a + b -c
|
||||
"""
|
||||
)
|
||||
expr3 = SymPyExpression(src,'f')
|
||||
expr4 = SymPyExpression(src1,'f')
|
||||
ls1 = expr3.return_expr()
|
||||
ls2 = expr4.return_expr()
|
||||
for i in range(0, 7):
|
||||
assert isinstance(ls1[i], Declaration)
|
||||
assert isinstance(ls2[i], Declaration)
|
||||
assert isinstance(ls2[8], Assignment)
|
||||
assert ls1[0] == Declaration(
|
||||
Variable(
|
||||
Symbol('a'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls1[1] == Declaration(
|
||||
Variable(
|
||||
Symbol('b'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls1[2] == Declaration(
|
||||
Variable(
|
||||
Symbol('c'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls1[3] == Declaration(
|
||||
Variable(
|
||||
Symbol('d'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls1[4] == Declaration(
|
||||
Variable(
|
||||
Symbol('p'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls1[5] == Declaration(
|
||||
Variable(
|
||||
Symbol('q'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls1[6] == Declaration(
|
||||
Variable(
|
||||
Symbol('r'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls1[7] == Declaration(
|
||||
Variable(
|
||||
Symbol('s'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls2[8] == Assignment(
|
||||
Variable(Symbol('d')),
|
||||
Symbol('a') + Symbol('b') - Symbol('c')
|
||||
)
|
||||
|
||||
def test_assignment():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
a = b
|
||||
c = d
|
||||
p = q
|
||||
r = s
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
ls1 = expr1.return_expr()
|
||||
for iter in range(0, 12):
|
||||
if iter < 8:
|
||||
assert isinstance(ls1[iter], Declaration)
|
||||
else:
|
||||
assert isinstance(ls1[iter], Assignment)
|
||||
assert ls1[8] == Assignment(
|
||||
Variable(Symbol('a')),
|
||||
Variable(Symbol('b'))
|
||||
)
|
||||
assert ls1[9] == Assignment(
|
||||
Variable(Symbol('c')),
|
||||
Variable(Symbol('d'))
|
||||
)
|
||||
assert ls1[10] == Assignment(
|
||||
Variable(Symbol('p')),
|
||||
Variable(Symbol('q'))
|
||||
)
|
||||
assert ls1[11] == Assignment(
|
||||
Variable(Symbol('r')),
|
||||
Variable(Symbol('s'))
|
||||
)
|
||||
|
||||
|
||||
def test_binop_add():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
c = a + b
|
||||
d = a + c
|
||||
s = p + q + r
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
ls1 = expr1.return_expr()
|
||||
for iter in range(8, 11):
|
||||
assert isinstance(ls1[iter], Assignment)
|
||||
assert ls1[8] == Assignment(
|
||||
Variable(Symbol('c')),
|
||||
Symbol('a') + Symbol('b')
|
||||
)
|
||||
assert ls1[9] == Assignment(
|
||||
Variable(Symbol('d')),
|
||||
Symbol('a') + Symbol('c')
|
||||
)
|
||||
assert ls1[10] == Assignment(
|
||||
Variable(Symbol('s')),
|
||||
Symbol('p') + Symbol('q') + Symbol('r')
|
||||
)
|
||||
|
||||
|
||||
def test_binop_sub():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
c = a - b
|
||||
d = a - c
|
||||
s = p - q - r
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
ls1 = expr1.return_expr()
|
||||
for iter in range(8, 11):
|
||||
assert isinstance(ls1[iter], Assignment)
|
||||
assert ls1[8] == Assignment(
|
||||
Variable(Symbol('c')),
|
||||
Symbol('a') - Symbol('b')
|
||||
)
|
||||
assert ls1[9] == Assignment(
|
||||
Variable(Symbol('d')),
|
||||
Symbol('a') - Symbol('c')
|
||||
)
|
||||
assert ls1[10] == Assignment(
|
||||
Variable(Symbol('s')),
|
||||
Symbol('p') - Symbol('q') - Symbol('r')
|
||||
)
|
||||
|
||||
|
||||
def test_binop_mul():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
c = a * b
|
||||
d = a * c
|
||||
s = p * q * r
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
ls1 = expr1.return_expr()
|
||||
for iter in range(8, 11):
|
||||
assert isinstance(ls1[iter], Assignment)
|
||||
assert ls1[8] == Assignment(
|
||||
Variable(Symbol('c')),
|
||||
Symbol('a') * Symbol('b')
|
||||
)
|
||||
assert ls1[9] == Assignment(
|
||||
Variable(Symbol('d')),
|
||||
Symbol('a') * Symbol('c')
|
||||
)
|
||||
assert ls1[10] == Assignment(
|
||||
Variable(Symbol('s')),
|
||||
Symbol('p') * Symbol('q') * Symbol('r')
|
||||
)
|
||||
|
||||
|
||||
def test_binop_div():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
c = a / b
|
||||
d = a / c
|
||||
s = p / q
|
||||
r = q / p
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
ls1 = expr1.return_expr()
|
||||
for iter in range(8, 12):
|
||||
assert isinstance(ls1[iter], Assignment)
|
||||
assert ls1[8] == Assignment(
|
||||
Variable(Symbol('c')),
|
||||
Symbol('a') / Symbol('b')
|
||||
)
|
||||
assert ls1[9] == Assignment(
|
||||
Variable(Symbol('d')),
|
||||
Symbol('a') / Symbol('c')
|
||||
)
|
||||
assert ls1[10] == Assignment(
|
||||
Variable(Symbol('s')),
|
||||
Symbol('p') / Symbol('q')
|
||||
)
|
||||
assert ls1[11] == Assignment(
|
||||
Variable(Symbol('r')),
|
||||
Symbol('q') / Symbol('p')
|
||||
)
|
||||
|
||||
def test_mul_binop():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
d = a + b - c
|
||||
c = a * b + d
|
||||
s = p * q / r
|
||||
r = p * s + q / p
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
ls1 = expr1.return_expr()
|
||||
for iter in range(8, 12):
|
||||
assert isinstance(ls1[iter], Assignment)
|
||||
assert ls1[8] == Assignment(
|
||||
Variable(Symbol('d')),
|
||||
Symbol('a') + Symbol('b') - Symbol('c')
|
||||
)
|
||||
assert ls1[9] == Assignment(
|
||||
Variable(Symbol('c')),
|
||||
Symbol('a') * Symbol('b') + Symbol('d')
|
||||
)
|
||||
assert ls1[10] == Assignment(
|
||||
Variable(Symbol('s')),
|
||||
Symbol('p') * Symbol('q') / Symbol('r')
|
||||
)
|
||||
assert ls1[11] == Assignment(
|
||||
Variable(Symbol('r')),
|
||||
Symbol('p') * Symbol('s') + Symbol('q') / Symbol('p')
|
||||
)
|
||||
|
||||
|
||||
def test_function():
|
||||
src1 = """\
|
||||
integer function f(a,b)
|
||||
integer :: x, y
|
||||
f = x + y
|
||||
end function
|
||||
"""
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
for iter in expr1.return_expr():
|
||||
assert isinstance(iter, FunctionDefinition)
|
||||
assert iter == FunctionDefinition(
|
||||
IntBaseType(String('integer')),
|
||||
name=String('f'),
|
||||
parameters=(
|
||||
Variable(Symbol('a')),
|
||||
Variable(Symbol('b'))
|
||||
),
|
||||
body=CodeBlock(
|
||||
Declaration(
|
||||
Variable(
|
||||
Symbol('a'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
),
|
||||
Declaration(
|
||||
Variable(
|
||||
Symbol('b'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
),
|
||||
Declaration(
|
||||
Variable(
|
||||
Symbol('f'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
),
|
||||
Declaration(
|
||||
Variable(
|
||||
Symbol('x'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
),
|
||||
Declaration(
|
||||
Variable(
|
||||
Symbol('y'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
),
|
||||
Assignment(
|
||||
Variable(Symbol('f')),
|
||||
Add(Symbol('x'), Symbol('y'))
|
||||
),
|
||||
Return(Variable(Symbol('f')))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_var():
|
||||
expr1.convert_to_expr(src, 'f')
|
||||
ls = expr1.return_expr()
|
||||
for iter in expr1.return_expr():
|
||||
assert isinstance(iter, Declaration)
|
||||
assert ls[0] == Declaration(
|
||||
Variable(
|
||||
Symbol('a'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[1] == Declaration(
|
||||
Variable(
|
||||
Symbol('b'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[2] == Declaration(
|
||||
Variable(
|
||||
Symbol('c'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[3] == Declaration(
|
||||
Variable(
|
||||
Symbol('d'),
|
||||
type = IntBaseType(String('integer')),
|
||||
value = Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[4] == Declaration(
|
||||
Variable(
|
||||
Symbol('p'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls[5] == Declaration(
|
||||
Variable(
|
||||
Symbol('q'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls[6] == Declaration(
|
||||
Variable(
|
||||
Symbol('r'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
assert ls[7] == Declaration(
|
||||
Variable(
|
||||
Symbol('s'),
|
||||
type = FloatBaseType(String('real')),
|
||||
value = Float(0.0)
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
def test_raise():
|
||||
from sympy.parsing.fortran.fortran_parser import ASR2PyVisitor
|
||||
raises(ImportError, lambda: ASR2PyVisitor())
|
||||
raises(ImportError, lambda: SymPyExpression(' ', mode = 'f'))
|
||||
@@ -0,0 +1,195 @@
|
||||
import sympy
|
||||
from sympy.parsing.sympy_parser import (
|
||||
parse_expr,
|
||||
standard_transformations,
|
||||
convert_xor,
|
||||
implicit_multiplication_application,
|
||||
implicit_multiplication,
|
||||
implicit_application,
|
||||
function_exponentiation,
|
||||
split_symbols,
|
||||
split_symbols_custom,
|
||||
_token_splittable
|
||||
)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_implicit_multiplication():
|
||||
cases = {
|
||||
'5x': '5*x',
|
||||
'abc': 'a*b*c',
|
||||
'3sin(x)': '3*sin(x)',
|
||||
'(x+1)(x+2)': '(x+1)*(x+2)',
|
||||
'(5 x**2)sin(x)': '(5*x**2)*sin(x)',
|
||||
'2 sin(x) cos(x)': '2*sin(x)*cos(x)',
|
||||
'pi x': 'pi*x',
|
||||
'x pi': 'x*pi',
|
||||
'E x': 'E*x',
|
||||
'EulerGamma y': 'EulerGamma*y',
|
||||
'E pi': 'E*pi',
|
||||
'pi (x + 2)': 'pi*(x+2)',
|
||||
'(x + 2) pi': '(x+2)*pi',
|
||||
'pi sin(x)': 'pi*sin(x)',
|
||||
}
|
||||
transformations = standard_transformations + (convert_xor,)
|
||||
transformations2 = transformations + (split_symbols,
|
||||
implicit_multiplication)
|
||||
for case in cases:
|
||||
implicit = parse_expr(case, transformations=transformations2)
|
||||
normal = parse_expr(cases[case], transformations=transformations)
|
||||
assert(implicit == normal)
|
||||
|
||||
application = ['sin x', 'cos 2*x', 'sin cos x']
|
||||
for case in application:
|
||||
raises(SyntaxError,
|
||||
lambda: parse_expr(case, transformations=transformations2))
|
||||
raises(TypeError,
|
||||
lambda: parse_expr('sin**2(x)', transformations=transformations2))
|
||||
|
||||
|
||||
def test_implicit_application():
|
||||
cases = {
|
||||
'factorial': 'factorial',
|
||||
'sin x': 'sin(x)',
|
||||
'tan y**3': 'tan(y**3)',
|
||||
'cos 2*x': 'cos(2*x)',
|
||||
'(cot)': 'cot',
|
||||
'sin cos tan x': 'sin(cos(tan(x)))'
|
||||
}
|
||||
transformations = standard_transformations + (convert_xor,)
|
||||
transformations2 = transformations + (implicit_application,)
|
||||
for case in cases:
|
||||
implicit = parse_expr(case, transformations=transformations2)
|
||||
normal = parse_expr(cases[case], transformations=transformations)
|
||||
assert(implicit == normal), (implicit, normal)
|
||||
|
||||
multiplication = ['x y', 'x sin x', '2x']
|
||||
for case in multiplication:
|
||||
raises(SyntaxError,
|
||||
lambda: parse_expr(case, transformations=transformations2))
|
||||
raises(TypeError,
|
||||
lambda: parse_expr('sin**2(x)', transformations=transformations2))
|
||||
|
||||
|
||||
def test_function_exponentiation():
|
||||
cases = {
|
||||
'sin**2(x)': 'sin(x)**2',
|
||||
'exp^y(z)': 'exp(z)^y',
|
||||
'sin**2(E^(x))': 'sin(E^(x))**2'
|
||||
}
|
||||
transformations = standard_transformations + (convert_xor,)
|
||||
transformations2 = transformations + (function_exponentiation,)
|
||||
for case in cases:
|
||||
implicit = parse_expr(case, transformations=transformations2)
|
||||
normal = parse_expr(cases[case], transformations=transformations)
|
||||
assert(implicit == normal)
|
||||
|
||||
other_implicit = ['x y', 'x sin x', '2x', 'sin x',
|
||||
'cos 2*x', 'sin cos x']
|
||||
for case in other_implicit:
|
||||
raises(SyntaxError,
|
||||
lambda: parse_expr(case, transformations=transformations2))
|
||||
|
||||
assert parse_expr('x**2', local_dict={ 'x': sympy.Symbol('x') },
|
||||
transformations=transformations2) == parse_expr('x**2')
|
||||
|
||||
|
||||
def test_symbol_splitting():
|
||||
# By default Greek letter names should not be split (lambda is a keyword
|
||||
# so skip it)
|
||||
transformations = standard_transformations + (split_symbols,)
|
||||
greek_letters = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta',
|
||||
'eta', 'theta', 'iota', 'kappa', 'mu', 'nu', 'xi',
|
||||
'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon',
|
||||
'phi', 'chi', 'psi', 'omega')
|
||||
|
||||
for letter in greek_letters:
|
||||
assert(parse_expr(letter, transformations=transformations) ==
|
||||
parse_expr(letter))
|
||||
|
||||
# Make sure symbol splitting resolves names
|
||||
transformations += (implicit_multiplication,)
|
||||
local_dict = { 'e': sympy.E }
|
||||
cases = {
|
||||
'xe': 'E*x',
|
||||
'Iy': 'I*y',
|
||||
'ee': 'E*E',
|
||||
}
|
||||
for case, expected in cases.items():
|
||||
assert(parse_expr(case, local_dict=local_dict,
|
||||
transformations=transformations) ==
|
||||
parse_expr(expected))
|
||||
|
||||
# Make sure custom splitting works
|
||||
def can_split(symbol):
|
||||
if symbol not in ('unsplittable', 'names'):
|
||||
return _token_splittable(symbol)
|
||||
return False
|
||||
transformations = standard_transformations
|
||||
transformations += (split_symbols_custom(can_split),
|
||||
implicit_multiplication)
|
||||
|
||||
assert(parse_expr('unsplittable', transformations=transformations) ==
|
||||
parse_expr('unsplittable'))
|
||||
assert(parse_expr('names', transformations=transformations) ==
|
||||
parse_expr('names'))
|
||||
assert(parse_expr('xy', transformations=transformations) ==
|
||||
parse_expr('x*y'))
|
||||
for letter in greek_letters:
|
||||
assert(parse_expr(letter, transformations=transformations) ==
|
||||
parse_expr(letter))
|
||||
|
||||
|
||||
def test_all_implicit_steps():
|
||||
cases = {
|
||||
'2x': '2*x', # implicit multiplication
|
||||
'x y': 'x*y',
|
||||
'xy': 'x*y',
|
||||
'sin x': 'sin(x)', # add parentheses
|
||||
'2sin x': '2*sin(x)',
|
||||
'x y z': 'x*y*z',
|
||||
'sin(2 * 3x)': 'sin(2 * 3 * x)',
|
||||
'sin(x) (1 + cos(x))': 'sin(x) * (1 + cos(x))',
|
||||
'(x + 2) sin(x)': '(x + 2) * sin(x)',
|
||||
'(x + 2) sin x': '(x + 2) * sin(x)',
|
||||
'sin(sin x)': 'sin(sin(x))',
|
||||
'sin x!': 'sin(factorial(x))',
|
||||
'sin x!!': 'sin(factorial2(x))',
|
||||
'factorial': 'factorial', # don't apply a bare function
|
||||
'x sin x': 'x * sin(x)', # both application and multiplication
|
||||
'xy sin x': 'x * y * sin(x)',
|
||||
'(x+2)(x+3)': '(x + 2) * (x+3)',
|
||||
'x**2 + 2xy + y**2': 'x**2 + 2 * x * y + y**2', # split the xy
|
||||
'pi': 'pi', # don't mess with constants
|
||||
'None': 'None',
|
||||
'ln sin x': 'ln(sin(x))', # multiple implicit function applications
|
||||
'sin x**2': 'sin(x**2)', # implicit application to an exponential
|
||||
'alpha': 'Symbol("alpha")', # don't split Greek letters/subscripts
|
||||
'x_2': 'Symbol("x_2")',
|
||||
'sin^2 x**2': 'sin(x**2)**2', # function raised to a power
|
||||
'sin**3(x)': 'sin(x)**3',
|
||||
'(factorial)': 'factorial',
|
||||
'tan 3x': 'tan(3*x)',
|
||||
'sin^2(3*E^(x))': 'sin(3*E**(x))**2',
|
||||
'sin**2(E^(3x))': 'sin(E**(3*x))**2',
|
||||
'sin^2 (3x*E^(x))': 'sin(3*x*E^x)**2',
|
||||
'pi sin x': 'pi*sin(x)',
|
||||
}
|
||||
transformations = standard_transformations + (convert_xor,)
|
||||
transformations2 = transformations + (implicit_multiplication_application,)
|
||||
for case in cases:
|
||||
implicit = parse_expr(case, transformations=transformations2)
|
||||
normal = parse_expr(cases[case], transformations=transformations)
|
||||
assert(implicit == normal)
|
||||
|
||||
|
||||
def test_no_methods_implicit_multiplication():
|
||||
# Issue 21020
|
||||
u = sympy.Symbol('u')
|
||||
transformations = standard_transformations + \
|
||||
(implicit_multiplication,)
|
||||
expr = parse_expr('x.is_polynomial(x)', transformations=transformations)
|
||||
assert expr == True
|
||||
expr = parse_expr('(exp(x) / (1 + exp(2x))).subs(exp(x), u)',
|
||||
transformations=transformations)
|
||||
assert expr == u/(u**2 + 1)
|
||||
@@ -0,0 +1,358 @@
|
||||
from sympy.testing.pytest import raises, XFAIL
|
||||
from sympy.external import import_module
|
||||
|
||||
from sympy.concrete.products import Product
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.add import Add
|
||||
from sympy.core.function import (Derivative, Function)
|
||||
from sympy.core.mul import Mul
|
||||
from sympy.core.numbers import (E, oo)
|
||||
from sympy.core.power import Pow
|
||||
from sympy.core.relational import (GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, Unequality)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.combinatorial.factorials import (binomial, factorial)
|
||||
from sympy.functions.elementary.complexes import (Abs, conjugate)
|
||||
from sympy.functions.elementary.exponential import (exp, log)
|
||||
from sympy.functions.elementary.integers import (ceiling, floor)
|
||||
from sympy.functions.elementary.miscellaneous import (root, sqrt)
|
||||
from sympy.functions.elementary.trigonometric import (asin, cos, csc, sec, sin, tan)
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.series.limits import Limit
|
||||
|
||||
from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge
|
||||
from sympy.physics.quantum.state import Bra, Ket
|
||||
from sympy.abc import x, y, z, a, b, c, t, k, n
|
||||
antlr4 = import_module("antlr4")
|
||||
|
||||
# disable tests if antlr4-python3-runtime is not present
|
||||
disabled = antlr4 is None
|
||||
|
||||
theta = Symbol('theta')
|
||||
f = Function('f')
|
||||
|
||||
|
||||
# shorthand definitions
|
||||
def _Add(a, b):
|
||||
return Add(a, b, evaluate=False)
|
||||
|
||||
|
||||
def _Mul(a, b):
|
||||
return Mul(a, b, evaluate=False)
|
||||
|
||||
|
||||
def _Pow(a, b):
|
||||
return Pow(a, b, evaluate=False)
|
||||
|
||||
|
||||
def _Sqrt(a):
|
||||
return sqrt(a, evaluate=False)
|
||||
|
||||
|
||||
def _Conjugate(a):
|
||||
return conjugate(a, evaluate=False)
|
||||
|
||||
|
||||
def _Abs(a):
|
||||
return Abs(a, evaluate=False)
|
||||
|
||||
|
||||
def _factorial(a):
|
||||
return factorial(a, evaluate=False)
|
||||
|
||||
|
||||
def _exp(a):
|
||||
return exp(a, evaluate=False)
|
||||
|
||||
|
||||
def _log(a, b):
|
||||
return log(a, b, evaluate=False)
|
||||
|
||||
|
||||
def _binomial(n, k):
|
||||
return binomial(n, k, evaluate=False)
|
||||
|
||||
|
||||
def test_import():
|
||||
from sympy.parsing.latex._build_latex_antlr import (
|
||||
build_parser,
|
||||
check_antlr_version,
|
||||
dir_latex_antlr
|
||||
)
|
||||
# XXX: It would be better to come up with a test for these...
|
||||
del build_parser, check_antlr_version, dir_latex_antlr
|
||||
|
||||
|
||||
# These LaTeX strings should parse to the corresponding SymPy expression
|
||||
GOOD_PAIRS = [
|
||||
(r"0", 0),
|
||||
(r"1", 1),
|
||||
(r"-3.14", -3.14),
|
||||
(r"(-7.13)(1.5)", _Mul(-7.13, 1.5)),
|
||||
(r"x", x),
|
||||
(r"2x", 2*x),
|
||||
(r"x^2", x**2),
|
||||
(r"x^\frac{1}{2}", _Pow(x, _Pow(2, -1))),
|
||||
(r"x^{3 + 1}", x**_Add(3, 1)),
|
||||
(r"-c", -c),
|
||||
(r"a \cdot b", a * b),
|
||||
(r"a / b", a / b),
|
||||
(r"a \div b", a / b),
|
||||
(r"a + b", a + b),
|
||||
(r"a + b - a", _Add(a+b, -a)),
|
||||
(r"a^2 + b^2 = c^2", Eq(a**2 + b**2, c**2)),
|
||||
(r"(x + y) z", _Mul(_Add(x, y), z)),
|
||||
(r"a'b+ab'", _Add(_Mul(Symbol("a'"), b), _Mul(a, Symbol("b'")))),
|
||||
(r"y''_1", Symbol("y_{1}''")),
|
||||
(r"y_1''", Symbol("y_{1}''")),
|
||||
(r"\left(x + y\right) z", _Mul(_Add(x, y), z)),
|
||||
(r"\left( x + y\right ) z", _Mul(_Add(x, y), z)),
|
||||
(r"\left( x + y\right ) z", _Mul(_Add(x, y), z)),
|
||||
(r"\left[x + y\right] z", _Mul(_Add(x, y), z)),
|
||||
(r"\left\{x + y\right\} z", _Mul(_Add(x, y), z)),
|
||||
(r"1+1", _Add(1, 1)),
|
||||
(r"0+1", _Add(0, 1)),
|
||||
(r"1*2", _Mul(1, 2)),
|
||||
(r"0*1", _Mul(0, 1)),
|
||||
(r"1 \times 2 ", _Mul(1, 2)),
|
||||
(r"x = y", Eq(x, y)),
|
||||
(r"x \neq y", Ne(x, y)),
|
||||
(r"x < y", Lt(x, y)),
|
||||
(r"x > y", Gt(x, y)),
|
||||
(r"x \leq y", Le(x, y)),
|
||||
(r"x \geq y", Ge(x, y)),
|
||||
(r"x \le y", Le(x, y)),
|
||||
(r"x \ge y", Ge(x, y)),
|
||||
(r"\lfloor x \rfloor", floor(x)),
|
||||
(r"\lceil x \rceil", ceiling(x)),
|
||||
(r"\langle x |", Bra('x')),
|
||||
(r"| x \rangle", Ket('x')),
|
||||
(r"\sin \theta", sin(theta)),
|
||||
(r"\sin(\theta)", sin(theta)),
|
||||
(r"\sin^{-1} a", asin(a)),
|
||||
(r"\sin a \cos b", _Mul(sin(a), cos(b))),
|
||||
(r"\sin \cos \theta", sin(cos(theta))),
|
||||
(r"\sin(\cos \theta)", sin(cos(theta))),
|
||||
(r"\frac{a}{b}", a / b),
|
||||
(r"\dfrac{a}{b}", a / b),
|
||||
(r"\tfrac{a}{b}", a / b),
|
||||
(r"\frac12", _Pow(2, -1)),
|
||||
(r"\frac12y", _Mul(_Pow(2, -1), y)),
|
||||
(r"\frac1234", _Mul(_Pow(2, -1), 34)),
|
||||
(r"\frac2{3}", _Mul(2, _Pow(3, -1))),
|
||||
(r"\frac{\sin{x}}2", _Mul(sin(x), _Pow(2, -1))),
|
||||
(r"\frac{a + b}{c}", _Mul(a + b, _Pow(c, -1))),
|
||||
(r"\frac{7}{3}", _Mul(7, _Pow(3, -1))),
|
||||
(r"(\csc x)(\sec y)", csc(x)*sec(y)),
|
||||
(r"\lim_{x \to 3} a", Limit(a, x, 3, dir='+-')),
|
||||
(r"\lim_{x \rightarrow 3} a", Limit(a, x, 3, dir='+-')),
|
||||
(r"\lim_{x \Rightarrow 3} a", Limit(a, x, 3, dir='+-')),
|
||||
(r"\lim_{x \longrightarrow 3} a", Limit(a, x, 3, dir='+-')),
|
||||
(r"\lim_{x \Longrightarrow 3} a", Limit(a, x, 3, dir='+-')),
|
||||
(r"\lim_{x \to 3^{+}} a", Limit(a, x, 3, dir='+')),
|
||||
(r"\lim_{x \to 3^{-}} a", Limit(a, x, 3, dir='-')),
|
||||
(r"\lim_{x \to 3^+} a", Limit(a, x, 3, dir='+')),
|
||||
(r"\lim_{x \to 3^-} a", Limit(a, x, 3, dir='-')),
|
||||
(r"\infty", oo),
|
||||
(r"\lim_{x \to \infty} \frac{1}{x}", Limit(_Pow(x, -1), x, oo)),
|
||||
(r"\frac{d}{dx} x", Derivative(x, x)),
|
||||
(r"\frac{d}{dt} x", Derivative(x, t)),
|
||||
(r"f(x)", f(x)),
|
||||
(r"f(x, y)", f(x, y)),
|
||||
(r"f(x, y, z)", f(x, y, z)),
|
||||
(r"f'_1(x)", Function("f_{1}'")(x)),
|
||||
(r"f_{1}''(x+y)", Function("f_{1}''")(x+y)),
|
||||
(r"\frac{d f(x)}{dx}", Derivative(f(x), x)),
|
||||
(r"\frac{d\theta(x)}{dx}", Derivative(Function('theta')(x), x)),
|
||||
(r"x \neq y", Unequality(x, y)),
|
||||
(r"|x|", _Abs(x)),
|
||||
(r"||x||", _Abs(Abs(x))),
|
||||
(r"|x||y|", _Abs(x)*_Abs(y)),
|
||||
(r"||x||y||", _Abs(_Abs(x)*_Abs(y))),
|
||||
(r"\pi^{|xy|}", Symbol('pi')**_Abs(x*y)),
|
||||
(r"\int x dx", Integral(x, x)),
|
||||
(r"\int x d\theta", Integral(x, theta)),
|
||||
(r"\int (x^2 - y)dx", Integral(x**2 - y, x)),
|
||||
(r"\int x + a dx", Integral(_Add(x, a), x)),
|
||||
(r"\int da", Integral(1, a)),
|
||||
(r"\int_0^7 dx", Integral(1, (x, 0, 7))),
|
||||
(r"\int\limits_{0}^{1} x dx", Integral(x, (x, 0, 1))),
|
||||
(r"\int_a^b x dx", Integral(x, (x, a, b))),
|
||||
(r"\int^b_a x dx", Integral(x, (x, a, b))),
|
||||
(r"\int_{a}^b x dx", Integral(x, (x, a, b))),
|
||||
(r"\int^{b}_a x dx", Integral(x, (x, a, b))),
|
||||
(r"\int_{a}^{b} x dx", Integral(x, (x, a, b))),
|
||||
(r"\int^{b}_{a} x dx", Integral(x, (x, a, b))),
|
||||
(r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))),
|
||||
(r"\int (x+a)", Integral(_Add(x, a), x)),
|
||||
(r"\int a + b + c dx", Integral(_Add(_Add(a, b), c), x)),
|
||||
(r"\int \frac{dz}{z}", Integral(Pow(z, -1), z)),
|
||||
(r"\int \frac{3 dz}{z}", Integral(3*Pow(z, -1), z)),
|
||||
(r"\int \frac{1}{x} dx", Integral(Pow(x, -1), x)),
|
||||
(r"\int \frac{1}{a} + \frac{1}{b} dx",
|
||||
Integral(_Add(_Pow(a, -1), Pow(b, -1)), x)),
|
||||
(r"\int \frac{3 \cdot d\theta}{\theta}",
|
||||
Integral(3*_Pow(theta, -1), theta)),
|
||||
(r"\int \frac{1}{x} + 1 dx", Integral(_Add(_Pow(x, -1), 1), x)),
|
||||
(r"x_0", Symbol('x_{0}')),
|
||||
(r"x_{1}", Symbol('x_{1}')),
|
||||
(r"x_a", Symbol('x_{a}')),
|
||||
(r"x_{b}", Symbol('x_{b}')),
|
||||
(r"h_\theta", Symbol('h_{theta}')),
|
||||
(r"h_{\theta}", Symbol('h_{theta}')),
|
||||
(r"h_{\theta}(x_0, x_1)",
|
||||
Function('h_{theta}')(Symbol('x_{0}'), Symbol('x_{1}'))),
|
||||
(r"x!", _factorial(x)),
|
||||
(r"100!", _factorial(100)),
|
||||
(r"\theta!", _factorial(theta)),
|
||||
(r"(x + 1)!", _factorial(_Add(x, 1))),
|
||||
(r"(x!)!", _factorial(_factorial(x))),
|
||||
(r"x!!!", _factorial(_factorial(_factorial(x)))),
|
||||
(r"5!7!", _Mul(_factorial(5), _factorial(7))),
|
||||
(r"\sqrt{x}", sqrt(x)),
|
||||
(r"\sqrt{x + b}", sqrt(_Add(x, b))),
|
||||
(r"\sqrt[3]{\sin x}", root(sin(x), 3)),
|
||||
(r"\sqrt[y]{\sin x}", root(sin(x), y)),
|
||||
(r"\sqrt[\theta]{\sin x}", root(sin(x), theta)),
|
||||
(r"\sqrt{\frac{12}{6}}", _Sqrt(_Mul(12, _Pow(6, -1)))),
|
||||
(r"\overline{z}", _Conjugate(z)),
|
||||
(r"\overline{\overline{z}}", _Conjugate(_Conjugate(z))),
|
||||
(r"\overline{x + y}", _Conjugate(_Add(x, y))),
|
||||
(r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y)),
|
||||
(r"x < y", StrictLessThan(x, y)),
|
||||
(r"x \leq y", LessThan(x, y)),
|
||||
(r"x > y", StrictGreaterThan(x, y)),
|
||||
(r"x \geq y", GreaterThan(x, y)),
|
||||
(r"\mathit{x}", Symbol('x')),
|
||||
(r"\mathit{test}", Symbol('test')),
|
||||
(r"\mathit{TEST}", Symbol('TEST')),
|
||||
(r"\mathit{HELLO world}", Symbol('HELLO world')),
|
||||
(r"\sum_{k = 1}^{3} c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum_{k = 1}^3 c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum^{3}_{k = 1} c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum^3_{k = 1} c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum_{k = 1}^{10} k^2", Sum(k**2, (k, 1, 10))),
|
||||
(r"\sum_{n = 0}^{\infty} \frac{1}{n!}",
|
||||
Sum(_Pow(_factorial(n), -1), (n, 0, oo))),
|
||||
(r"\prod_{a = b}^{c} x", Product(x, (a, b, c))),
|
||||
(r"\prod_{a = b}^c x", Product(x, (a, b, c))),
|
||||
(r"\prod^{c}_{a = b} x", Product(x, (a, b, c))),
|
||||
(r"\prod^c_{a = b} x", Product(x, (a, b, c))),
|
||||
(r"\exp x", _exp(x)),
|
||||
(r"\exp(x)", _exp(x)),
|
||||
(r"\lg x", _log(x, 10)),
|
||||
(r"\ln x", _log(x, E)),
|
||||
(r"\ln xy", _log(x*y, E)),
|
||||
(r"\log x", _log(x, E)),
|
||||
(r"\log xy", _log(x*y, E)),
|
||||
(r"\log_{2} x", _log(x, 2)),
|
||||
(r"\log_{a} x", _log(x, a)),
|
||||
(r"\log_{11} x", _log(x, 11)),
|
||||
(r"\log_{a^2} x", _log(x, _Pow(a, 2))),
|
||||
(r"[x]", x),
|
||||
(r"[a + b]", _Add(a, b)),
|
||||
(r"\frac{d}{dx} [ \tan x ]", Derivative(tan(x), x)),
|
||||
(r"\binom{n}{k}", _binomial(n, k)),
|
||||
(r"\tbinom{n}{k}", _binomial(n, k)),
|
||||
(r"\dbinom{n}{k}", _binomial(n, k)),
|
||||
(r"\binom{n}{0}", _binomial(n, 0)),
|
||||
(r"x^\binom{n}{k}", _Pow(x, _binomial(n, k))),
|
||||
(r"a \, b", _Mul(a, b)),
|
||||
(r"a \thinspace b", _Mul(a, b)),
|
||||
(r"a \: b", _Mul(a, b)),
|
||||
(r"a \medspace b", _Mul(a, b)),
|
||||
(r"a \; b", _Mul(a, b)),
|
||||
(r"a \thickspace b", _Mul(a, b)),
|
||||
(r"a \quad b", _Mul(a, b)),
|
||||
(r"a \qquad b", _Mul(a, b)),
|
||||
(r"a \! b", _Mul(a, b)),
|
||||
(r"a \negthinspace b", _Mul(a, b)),
|
||||
(r"a \negmedspace b", _Mul(a, b)),
|
||||
(r"a \negthickspace b", _Mul(a, b)),
|
||||
(r"\int x \, dx", Integral(x, x)),
|
||||
(r"\log_2 x", _log(x, 2)),
|
||||
(r"\log_a x", _log(x, a)),
|
||||
(r"5^0 - 4^0", _Add(_Pow(5, 0), _Mul(-1, _Pow(4, 0)))),
|
||||
(r"3x - 1", _Add(_Mul(3, x), -1))
|
||||
]
|
||||
|
||||
|
||||
def test_parseable():
|
||||
from sympy.parsing.latex import parse_latex
|
||||
for latex_str, sympy_expr in GOOD_PAIRS:
|
||||
assert parse_latex(latex_str) == sympy_expr, latex_str
|
||||
|
||||
# These bad LaTeX strings should raise a LaTeXParsingError when parsed
|
||||
BAD_STRINGS = [
|
||||
r"(",
|
||||
r")",
|
||||
r"\frac{d}{dx}",
|
||||
r"(\frac{d}{dx})",
|
||||
r"\sqrt{}",
|
||||
r"\sqrt",
|
||||
r"\overline{}",
|
||||
r"\overline",
|
||||
r"{",
|
||||
r"}",
|
||||
r"\mathit{x + y}",
|
||||
r"\mathit{21}",
|
||||
r"\frac{2}{}",
|
||||
r"\frac{}{2}",
|
||||
r"\int",
|
||||
r"!",
|
||||
r"!0",
|
||||
r"_",
|
||||
r"^",
|
||||
r"|",
|
||||
r"||x|",
|
||||
r"()",
|
||||
r"((((((((((((((((()))))))))))))))))",
|
||||
r"-",
|
||||
r"\frac{d}{dx} + \frac{d}{dt}",
|
||||
r"f(x,,y)",
|
||||
r"f(x,y,",
|
||||
r"\sin^x",
|
||||
r"\cos^2",
|
||||
r"@",
|
||||
r"#",
|
||||
r"$",
|
||||
r"%",
|
||||
r"&",
|
||||
r"*",
|
||||
r"" "\\",
|
||||
r"~",
|
||||
r"\frac{(2 + x}{1 - x)}",
|
||||
]
|
||||
|
||||
def test_not_parseable():
|
||||
from sympy.parsing.latex import parse_latex, LaTeXParsingError
|
||||
for latex_str in BAD_STRINGS:
|
||||
with raises(LaTeXParsingError):
|
||||
parse_latex(latex_str)
|
||||
|
||||
# At time of migration from latex2sympy, should fail but doesn't
|
||||
FAILING_BAD_STRINGS = [
|
||||
r"\cos 1 \cos",
|
||||
r"f(,",
|
||||
r"f()",
|
||||
r"a \div \div b",
|
||||
r"a \cdot \cdot b",
|
||||
r"a // b",
|
||||
r"a +",
|
||||
r"1.1.1",
|
||||
r"1 +",
|
||||
r"a / b /",
|
||||
]
|
||||
|
||||
@XFAIL
|
||||
def test_failing_not_parseable():
|
||||
from sympy.parsing.latex import parse_latex, LaTeXParsingError
|
||||
for latex_str in FAILING_BAD_STRINGS:
|
||||
with raises(LaTeXParsingError):
|
||||
parse_latex(latex_str)
|
||||
|
||||
# In strict mode, FAILING_BAD_STRINGS would fail
|
||||
def test_strict_mode():
|
||||
from sympy.parsing.latex import parse_latex, LaTeXParsingError
|
||||
for latex_str in FAILING_BAD_STRINGS:
|
||||
with raises(LaTeXParsingError):
|
||||
parse_latex(latex_str, strict=True)
|
||||
@@ -0,0 +1,16 @@
|
||||
from sympy.external import import_module
|
||||
from sympy.testing.pytest import ignore_warnings, raises
|
||||
|
||||
antlr4 = import_module("antlr4", warn_not_installed=False)
|
||||
|
||||
# disable tests if antlr4-python3-runtime is not present
|
||||
if antlr4:
|
||||
disabled = True
|
||||
|
||||
|
||||
def test_no_import():
|
||||
from sympy.parsing.latex import parse_latex
|
||||
|
||||
with ignore_warnings(UserWarning):
|
||||
with raises(ImportError):
|
||||
parse_latex('1 + 1')
|
||||
@@ -0,0 +1,872 @@
|
||||
from sympy.testing.pytest import XFAIL
|
||||
from sympy.parsing.latex.lark import parse_latex_lark
|
||||
from sympy.external import import_module
|
||||
|
||||
from sympy.concrete.products import Product
|
||||
from sympy.concrete.summations import Sum
|
||||
from sympy.core.function import Derivative, Function
|
||||
from sympy.core.numbers import E, oo, Rational
|
||||
from sympy.core.power import Pow
|
||||
from sympy.core.parameters import evaluate
|
||||
from sympy.core.relational import GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, Unequality
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.combinatorial.factorials import binomial, factorial
|
||||
from sympy.functions.elementary.complexes import Abs, conjugate
|
||||
from sympy.functions.elementary.exponential import exp, log
|
||||
from sympy.functions.elementary.integers import ceiling, floor
|
||||
from sympy.functions.elementary.miscellaneous import root, sqrt, Min, Max
|
||||
from sympy.functions.elementary.trigonometric import asin, cos, csc, sec, sin, tan
|
||||
from sympy.integrals.integrals import Integral
|
||||
from sympy.series.limits import Limit
|
||||
from sympy import Matrix, MatAdd, MatMul, Transpose, Trace
|
||||
from sympy import I
|
||||
|
||||
from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge
|
||||
from sympy.physics.quantum import Bra, Ket, InnerProduct
|
||||
from sympy.abc import x, y, z, a, b, c, d, t, k, n
|
||||
|
||||
from .test_latex import theta, f, _Add, _Mul, _Pow, _Sqrt, _Conjugate, _Abs, _factorial, _exp, _binomial
|
||||
|
||||
lark = import_module("lark")
|
||||
|
||||
# disable tests if lark is not present
|
||||
disabled = lark is None
|
||||
|
||||
# shorthand definitions that are only needed for the Lark LaTeX parser
|
||||
def _Min(*args):
|
||||
return Min(*args, evaluate=False)
|
||||
|
||||
|
||||
def _Max(*args):
|
||||
return Max(*args, evaluate=False)
|
||||
|
||||
|
||||
def _log(a, b=E):
|
||||
if b == E:
|
||||
return log(a, evaluate=False)
|
||||
else:
|
||||
return log(a, b, evaluate=False)
|
||||
|
||||
|
||||
def _MatAdd(a, b):
|
||||
return MatAdd(a, b, evaluate=False)
|
||||
|
||||
|
||||
def _MatMul(a, b):
|
||||
return MatMul(a, b, evaluate=False)
|
||||
|
||||
|
||||
# These LaTeX strings should parse to the corresponding SymPy expression
|
||||
SYMBOL_EXPRESSION_PAIRS = [
|
||||
(r"x_0", Symbol('x_{0}')),
|
||||
(r"x_{1}", Symbol('x_{1}')),
|
||||
(r"x_a", Symbol('x_{a}')),
|
||||
(r"x_{b}", Symbol('x_{b}')),
|
||||
(r"h_\theta", Symbol('h_{theta}')),
|
||||
(r"h_{\theta}", Symbol('h_{theta}')),
|
||||
(r"y''_1", Symbol("y''_{1}")),
|
||||
(r"y_1''", Symbol("y_{1}''")),
|
||||
(r"\mathit{x}", Symbol('x')),
|
||||
(r"\mathit{test}", Symbol('test')),
|
||||
(r"\mathit{TEST}", Symbol('TEST')),
|
||||
(r"\mathit{HELLO world}", Symbol('HELLO world')),
|
||||
(r"a'", Symbol("a'")),
|
||||
(r"a''", Symbol("a''")),
|
||||
(r"\alpha'", Symbol("alpha'")),
|
||||
(r"\alpha''", Symbol("alpha''")),
|
||||
(r"a_b", Symbol("a_{b}")),
|
||||
(r"a_b'", Symbol("a_{b}'")),
|
||||
(r"a'_b", Symbol("a'_{b}")),
|
||||
(r"a'_b'", Symbol("a'_{b}'")),
|
||||
(r"a_{b'}", Symbol("a_{b'}")),
|
||||
(r"a_{b'}'", Symbol("a_{b'}'")),
|
||||
(r"a'_{b'}", Symbol("a'_{b'}")),
|
||||
(r"a'_{b'}'", Symbol("a'_{b'}'")),
|
||||
(r"\mathit{foo}'", Symbol("foo'")),
|
||||
(r"\mathit{foo'}", Symbol("foo'")),
|
||||
(r"\mathit{foo'}'", Symbol("foo''")),
|
||||
(r"a_b''", Symbol("a_{b}''")),
|
||||
(r"a''_b", Symbol("a''_{b}")),
|
||||
(r"a''_b'''", Symbol("a''_{b}'''")),
|
||||
(r"a_{b''}", Symbol("a_{b''}")),
|
||||
(r"a_{b''}''", Symbol("a_{b''}''")),
|
||||
(r"a''_{b''}", Symbol("a''_{b''}")),
|
||||
(r"a''_{b''}'''", Symbol("a''_{b''}'''")),
|
||||
(r"\mathit{foo}''", Symbol("foo''")),
|
||||
(r"\mathit{foo''}", Symbol("foo''")),
|
||||
(r"\mathit{foo''}'''", Symbol("foo'''''")),
|
||||
(r"a_\alpha", Symbol("a_{alpha}")),
|
||||
(r"a_\alpha'", Symbol("a_{alpha}'")),
|
||||
(r"a'_\alpha", Symbol("a'_{alpha}")),
|
||||
(r"a'_\alpha'", Symbol("a'_{alpha}'")),
|
||||
(r"a_{\alpha'}", Symbol("a_{alpha'}")),
|
||||
(r"a_{\alpha'}'", Symbol("a_{alpha'}'")),
|
||||
(r"a'_{\alpha'}", Symbol("a'_{alpha'}")),
|
||||
(r"a'_{\alpha'}'", Symbol("a'_{alpha'}'")),
|
||||
(r"a_\alpha''", Symbol("a_{alpha}''")),
|
||||
(r"a''_\alpha", Symbol("a''_{alpha}")),
|
||||
(r"a''_\alpha'''", Symbol("a''_{alpha}'''")),
|
||||
(r"a_{\alpha''}", Symbol("a_{alpha''}")),
|
||||
(r"a_{\alpha''}''", Symbol("a_{alpha''}''")),
|
||||
(r"a''_{\alpha''}", Symbol("a''_{alpha''}")),
|
||||
(r"a''_{\alpha''}'''", Symbol("a''_{alpha''}'''")),
|
||||
(r"\alpha_b", Symbol("alpha_{b}")),
|
||||
(r"\alpha_b'", Symbol("alpha_{b}'")),
|
||||
(r"\alpha'_b", Symbol("alpha'_{b}")),
|
||||
(r"\alpha'_b'", Symbol("alpha'_{b}'")),
|
||||
(r"\alpha_{b'}", Symbol("alpha_{b'}")),
|
||||
(r"\alpha_{b'}'", Symbol("alpha_{b'}'")),
|
||||
(r"\alpha'_{b'}", Symbol("alpha'_{b'}")),
|
||||
(r"\alpha'_{b'}'", Symbol("alpha'_{b'}'")),
|
||||
(r"\alpha_b''", Symbol("alpha_{b}''")),
|
||||
(r"\alpha''_b", Symbol("alpha''_{b}")),
|
||||
(r"\alpha''_b'''", Symbol("alpha''_{b}'''")),
|
||||
(r"\alpha_{b''}", Symbol("alpha_{b''}")),
|
||||
(r"\alpha_{b''}''", Symbol("alpha_{b''}''")),
|
||||
(r"\alpha''_{b''}", Symbol("alpha''_{b''}")),
|
||||
(r"\alpha''_{b''}'''", Symbol("alpha''_{b''}'''")),
|
||||
(r"\alpha_\beta", Symbol("alpha_{beta}")),
|
||||
(r"\alpha_{\beta}", Symbol("alpha_{beta}")),
|
||||
(r"\alpha_{\beta'}", Symbol("alpha_{beta'}")),
|
||||
(r"\alpha_{\beta''}", Symbol("alpha_{beta''}")),
|
||||
(r"\alpha'_\beta", Symbol("alpha'_{beta}")),
|
||||
(r"\alpha'_{\beta}", Symbol("alpha'_{beta}")),
|
||||
(r"\alpha'_{\beta'}", Symbol("alpha'_{beta'}")),
|
||||
(r"\alpha'_{\beta''}", Symbol("alpha'_{beta''}")),
|
||||
(r"\alpha''_\beta", Symbol("alpha''_{beta}")),
|
||||
(r"\alpha''_{\beta}", Symbol("alpha''_{beta}")),
|
||||
(r"\alpha''_{\beta'}", Symbol("alpha''_{beta'}")),
|
||||
(r"\alpha''_{\beta''}", Symbol("alpha''_{beta''}")),
|
||||
(r"\alpha_\beta'", Symbol("alpha_{beta}'")),
|
||||
(r"\alpha_{\beta}'", Symbol("alpha_{beta}'")),
|
||||
(r"\alpha_{\beta'}'", Symbol("alpha_{beta'}'")),
|
||||
(r"\alpha_{\beta''}'", Symbol("alpha_{beta''}'")),
|
||||
(r"\alpha'_\beta'", Symbol("alpha'_{beta}'")),
|
||||
(r"\alpha'_{\beta}'", Symbol("alpha'_{beta}'")),
|
||||
(r"\alpha'_{\beta'}'", Symbol("alpha'_{beta'}'")),
|
||||
(r"\alpha'_{\beta''}'", Symbol("alpha'_{beta''}'")),
|
||||
(r"\alpha''_\beta'", Symbol("alpha''_{beta}'")),
|
||||
(r"\alpha''_{\beta}'", Symbol("alpha''_{beta}'")),
|
||||
(r"\alpha''_{\beta'}'", Symbol("alpha''_{beta'}'")),
|
||||
(r"\alpha''_{\beta''}'", Symbol("alpha''_{beta''}'")),
|
||||
(r"\alpha_\beta''", Symbol("alpha_{beta}''")),
|
||||
(r"\alpha_{\beta}''", Symbol("alpha_{beta}''")),
|
||||
(r"\alpha_{\beta'}''", Symbol("alpha_{beta'}''")),
|
||||
(r"\alpha_{\beta''}''", Symbol("alpha_{beta''}''")),
|
||||
(r"\alpha'_\beta''", Symbol("alpha'_{beta}''")),
|
||||
(r"\alpha'_{\beta}''", Symbol("alpha'_{beta}''")),
|
||||
(r"\alpha'_{\beta'}''", Symbol("alpha'_{beta'}''")),
|
||||
(r"\alpha'_{\beta''}''", Symbol("alpha'_{beta''}''")),
|
||||
(r"\alpha''_\beta''", Symbol("alpha''_{beta}''")),
|
||||
(r"\alpha''_{\beta}''", Symbol("alpha''_{beta}''")),
|
||||
(r"\alpha''_{\beta'}''", Symbol("alpha''_{beta'}''")),
|
||||
(r"\alpha''_{\beta''}''", Symbol("alpha''_{beta''}''"))
|
||||
|
||||
]
|
||||
|
||||
UNEVALUATED_SIMPLE_EXPRESSION_PAIRS = [
|
||||
(r"0", 0),
|
||||
(r"1", 1),
|
||||
(r"-3.14", -3.14),
|
||||
(r"(-7.13)(1.5)", _Mul(-7.13, 1.5)),
|
||||
(r"1+1", _Add(1, 1)),
|
||||
(r"0+1", _Add(0, 1)),
|
||||
(r"1*2", _Mul(1, 2)),
|
||||
(r"0*1", _Mul(0, 1)),
|
||||
(r"x", x),
|
||||
(r"2x", 2 * x),
|
||||
(r"3x - 1", _Add(_Mul(3, x), -1)),
|
||||
(r"-c", -c),
|
||||
(r"\infty", oo),
|
||||
(r"a \cdot b", a * b),
|
||||
(r"1 \times 2 ", _Mul(1, 2)),
|
||||
(r"a / b", a / b),
|
||||
(r"a \div b", a / b),
|
||||
(r"a + b", a + b),
|
||||
(r"a + b - a", _Add(a + b, -a)),
|
||||
(r"(x + y) z", _Mul(_Add(x, y), z)),
|
||||
(r"a'b+ab'", _Add(_Mul(Symbol("a'"), b), _Mul(a, Symbol("b'"))))
|
||||
]
|
||||
|
||||
EVALUATED_SIMPLE_EXPRESSION_PAIRS = [
|
||||
(r"(-7.13)(1.5)", -10.695),
|
||||
(r"1+1", 2),
|
||||
(r"0+1", 1),
|
||||
(r"1*2", 2),
|
||||
(r"0*1", 0),
|
||||
(r"2x", 2 * x),
|
||||
(r"3x - 1", 3 * x - 1),
|
||||
(r"-c", -c),
|
||||
(r"a \cdot b", a * b),
|
||||
(r"1 \times 2 ", 2),
|
||||
(r"a / b", a / b),
|
||||
(r"a \div b", a / b),
|
||||
(r"a + b", a + b),
|
||||
(r"a + b - a", b),
|
||||
(r"(x + y) z", (x + y) * z),
|
||||
]
|
||||
|
||||
UNEVALUATED_FRACTION_EXPRESSION_PAIRS = [
|
||||
(r"\frac{a}{b}", a / b),
|
||||
(r"\dfrac{a}{b}", a / b),
|
||||
(r"\tfrac{a}{b}", a / b),
|
||||
(r"\frac12", _Mul(1, _Pow(2, -1))),
|
||||
(r"\frac12y", _Mul(_Mul(1, _Pow(2, -1)), y)),
|
||||
(r"\frac1234", _Mul(_Mul(1, _Pow(2, -1)), 34)),
|
||||
(r"\frac2{3}", _Mul(2, _Pow(3, -1))),
|
||||
(r"\frac{a + b}{c}", _Mul(a + b, _Pow(c, -1))),
|
||||
(r"\frac{7}{3}", _Mul(7, _Pow(3, -1)))
|
||||
]
|
||||
|
||||
EVALUATED_FRACTION_EXPRESSION_PAIRS = [
|
||||
(r"\frac{a}{b}", a / b),
|
||||
(r"\dfrac{a}{b}", a / b),
|
||||
(r"\tfrac{a}{b}", a / b),
|
||||
(r"\frac12", Rational(1, 2)),
|
||||
(r"\frac12y", y / 2),
|
||||
(r"\frac1234", 17),
|
||||
(r"\frac2{3}", Rational(2, 3)),
|
||||
(r"\frac{a + b}{c}", (a + b) / c),
|
||||
(r"\frac{7}{3}", Rational(7, 3))
|
||||
]
|
||||
|
||||
RELATION_EXPRESSION_PAIRS = [
|
||||
(r"x = y", Eq(x, y)),
|
||||
(r"x \neq y", Ne(x, y)),
|
||||
(r"x < y", Lt(x, y)),
|
||||
(r"x > y", Gt(x, y)),
|
||||
(r"x \leq y", Le(x, y)),
|
||||
(r"x \geq y", Ge(x, y)),
|
||||
(r"x \le y", Le(x, y)),
|
||||
(r"x \ge y", Ge(x, y)),
|
||||
(r"x < y", StrictLessThan(x, y)),
|
||||
(r"x \leq y", LessThan(x, y)),
|
||||
(r"x > y", StrictGreaterThan(x, y)),
|
||||
(r"x \geq y", GreaterThan(x, y)),
|
||||
(r"x \neq y", Unequality(x, y)), # same as 2nd one in the list
|
||||
(r"a^2 + b^2 = c^2", Eq(a**2 + b**2, c**2))
|
||||
]
|
||||
|
||||
UNEVALUATED_POWER_EXPRESSION_PAIRS = [
|
||||
(r"x^2", x ** 2),
|
||||
(r"x^\frac{1}{2}", _Pow(x, _Mul(1, _Pow(2, -1)))),
|
||||
(r"x^{3 + 1}", x ** _Add(3, 1)),
|
||||
(r"\pi^{|xy|}", Symbol('pi') ** _Abs(x * y)),
|
||||
(r"5^0 - 4^0", _Add(_Pow(5, 0), _Mul(-1, _Pow(4, 0))))
|
||||
]
|
||||
|
||||
EVALUATED_POWER_EXPRESSION_PAIRS = [
|
||||
(r"x^2", x ** 2),
|
||||
(r"x^\frac{1}{2}", sqrt(x)),
|
||||
(r"x^{3 + 1}", x ** 4),
|
||||
(r"\pi^{|xy|}", Symbol('pi') ** _Abs(x * y)),
|
||||
(r"5^0 - 4^0", 0)
|
||||
]
|
||||
|
||||
UNEVALUATED_INTEGRAL_EXPRESSION_PAIRS = [
|
||||
(r"\int x dx", Integral(_Mul(1, x), x)),
|
||||
(r"\int x \, dx", Integral(_Mul(1, x), x)),
|
||||
(r"\int x d\theta", Integral(_Mul(1, x), theta)),
|
||||
(r"\int (x^2 - y)dx", Integral(_Mul(1, x ** 2 - y), x)),
|
||||
(r"\int x + a dx", Integral(_Mul(1, _Add(x, a)), x)),
|
||||
(r"\int da", Integral(_Mul(1, 1), a)),
|
||||
(r"\int_0^7 dx", Integral(_Mul(1, 1), (x, 0, 7))),
|
||||
(r"\int\limits_{0}^{1} x dx", Integral(_Mul(1, x), (x, 0, 1))),
|
||||
(r"\int_a^b x dx", Integral(_Mul(1, x), (x, a, b))),
|
||||
(r"\int^b_a x dx", Integral(_Mul(1, x), (x, a, b))),
|
||||
(r"\int_{a}^b x dx", Integral(_Mul(1, x), (x, a, b))),
|
||||
(r"\int^{b}_a x dx", Integral(_Mul(1, x), (x, a, b))),
|
||||
(r"\int_{a}^{b} x dx", Integral(_Mul(1, x), (x, a, b))),
|
||||
(r"\int^{b}_{a} x dx", Integral(_Mul(1, x), (x, a, b))),
|
||||
(r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))),
|
||||
(r"\int a + b + c dx", Integral(_Mul(1, _Add(_Add(a, b), c)), x)),
|
||||
(r"\int \frac{dz}{z}", Integral(_Mul(1, _Mul(1, Pow(z, -1))), z)),
|
||||
(r"\int \frac{3 dz}{z}", Integral(_Mul(1, _Mul(3, _Pow(z, -1))), z)),
|
||||
(r"\int \frac{1}{x} dx", Integral(_Mul(1, _Mul(1, Pow(x, -1))), x)),
|
||||
(r"\int \frac{1}{a} + \frac{1}{b} dx",
|
||||
Integral(_Mul(1, _Add(_Mul(1, _Pow(a, -1)), _Mul(1, Pow(b, -1)))), x)),
|
||||
(r"\int \frac{1}{x} + 1 dx", Integral(_Mul(1, _Add(_Mul(1, _Pow(x, -1)), 1)), x))
|
||||
]
|
||||
|
||||
EVALUATED_INTEGRAL_EXPRESSION_PAIRS = [
|
||||
(r"\int x dx", Integral(x, x)),
|
||||
(r"\int x \, dx", Integral(x, x)),
|
||||
(r"\int x d\theta", Integral(x, theta)),
|
||||
(r"\int (x^2 - y)dx", Integral(x ** 2 - y, x)),
|
||||
(r"\int x + a dx", Integral(x + a, x)),
|
||||
(r"\int da", Integral(1, a)),
|
||||
(r"\int_0^7 dx", Integral(1, (x, 0, 7))),
|
||||
(r"\int\limits_{0}^{1} x dx", Integral(x, (x, 0, 1))),
|
||||
(r"\int_a^b x dx", Integral(x, (x, a, b))),
|
||||
(r"\int^b_a x dx", Integral(x, (x, a, b))),
|
||||
(r"\int_{a}^b x dx", Integral(x, (x, a, b))),
|
||||
(r"\int^{b}_a x dx", Integral(x, (x, a, b))),
|
||||
(r"\int_{a}^{b} x dx", Integral(x, (x, a, b))),
|
||||
(r"\int^{b}_{a} x dx", Integral(x, (x, a, b))),
|
||||
(r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))),
|
||||
(r"\int a + b + c dx", Integral(a + b + c, x)),
|
||||
(r"\int \frac{dz}{z}", Integral(Pow(z, -1), z)),
|
||||
(r"\int \frac{3 dz}{z}", Integral(3 * Pow(z, -1), z)),
|
||||
(r"\int \frac{1}{x} dx", Integral(1 / x, x)),
|
||||
(r"\int \frac{1}{a} + \frac{1}{b} dx", Integral(1 / a + 1 / b, x)),
|
||||
(r"\int \frac{1}{a} - \frac{1}{b} dx", Integral(1 / a - 1 / b, x)),
|
||||
(r"\int \frac{1}{x} + 1 dx", Integral(1 / x + 1, x))
|
||||
]
|
||||
|
||||
DERIVATIVE_EXPRESSION_PAIRS = [
|
||||
(r"\frac{d}{dx} x", Derivative(x, x)),
|
||||
(r"\frac{d}{dt} x", Derivative(x, t)),
|
||||
(r"\frac{d}{dx} ( \tan x )", Derivative(tan(x), x)),
|
||||
(r"\frac{d f(x)}{dx}", Derivative(f(x), x)),
|
||||
(r"\frac{d\theta(x)}{dx}", Derivative(Function('theta')(x), x))
|
||||
]
|
||||
|
||||
TRIGONOMETRIC_EXPRESSION_PAIRS = [
|
||||
(r"\sin \theta", sin(theta)),
|
||||
(r"\sin(\theta)", sin(theta)),
|
||||
(r"\sin^{-1} a", asin(a)),
|
||||
(r"\sin a \cos b", _Mul(sin(a), cos(b))),
|
||||
(r"\sin \cos \theta", sin(cos(theta))),
|
||||
(r"\sin(\cos \theta)", sin(cos(theta))),
|
||||
(r"(\csc x)(\sec y)", csc(x) * sec(y)),
|
||||
(r"\frac{\sin{x}}2", _Mul(sin(x), _Pow(2, -1)))
|
||||
]
|
||||
|
||||
UNEVALUATED_LIMIT_EXPRESSION_PAIRS = [
|
||||
(r"\lim_{x \to 3} a", Limit(a, x, 3, dir="+-")),
|
||||
(r"\lim_{x \rightarrow 3} a", Limit(a, x, 3, dir="+-")),
|
||||
(r"\lim_{x \Rightarrow 3} a", Limit(a, x, 3, dir="+-")),
|
||||
(r"\lim_{x \longrightarrow 3} a", Limit(a, x, 3, dir="+-")),
|
||||
(r"\lim_{x \Longrightarrow 3} a", Limit(a, x, 3, dir="+-")),
|
||||
(r"\lim_{x \to 3^{+}} a", Limit(a, x, 3, dir="+")),
|
||||
(r"\lim_{x \to 3^{-}} a", Limit(a, x, 3, dir="-")),
|
||||
(r"\lim_{x \to 3^+} a", Limit(a, x, 3, dir="+")),
|
||||
(r"\lim_{x \to 3^-} a", Limit(a, x, 3, dir="-")),
|
||||
(r"\lim_{x \to \infty} \frac{1}{x}", Limit(_Mul(1, _Pow(x, -1)), x, oo))
|
||||
]
|
||||
|
||||
EVALUATED_LIMIT_EXPRESSION_PAIRS = [
|
||||
(r"\lim_{x \to \infty} \frac{1}{x}", Limit(1 / x, x, oo))
|
||||
]
|
||||
|
||||
UNEVALUATED_SQRT_EXPRESSION_PAIRS = [
|
||||
(r"\sqrt{x}", sqrt(x)),
|
||||
(r"\sqrt{x + b}", sqrt(_Add(x, b))),
|
||||
(r"\sqrt[3]{\sin x}", _Pow(sin(x), _Pow(3, -1))),
|
||||
# the above test needed to be handled differently than the ones below because root
|
||||
# acts differently if its second argument is a number
|
||||
(r"\sqrt[y]{\sin x}", root(sin(x), y)),
|
||||
(r"\sqrt[\theta]{\sin x}", root(sin(x), theta)),
|
||||
(r"\sqrt{\frac{12}{6}}", _Sqrt(_Mul(12, _Pow(6, -1))))
|
||||
]
|
||||
|
||||
EVALUATED_SQRT_EXPRESSION_PAIRS = [
|
||||
(r"\sqrt{x}", sqrt(x)),
|
||||
(r"\sqrt{x + b}", sqrt(x + b)),
|
||||
(r"\sqrt[3]{\sin x}", root(sin(x), 3)),
|
||||
(r"\sqrt[y]{\sin x}", root(sin(x), y)),
|
||||
(r"\sqrt[\theta]{\sin x}", root(sin(x), theta)),
|
||||
(r"\sqrt{\frac{12}{6}}", sqrt(2))
|
||||
]
|
||||
|
||||
UNEVALUATED_FACTORIAL_EXPRESSION_PAIRS = [
|
||||
(r"x!", _factorial(x)),
|
||||
(r"100!", _factorial(100)),
|
||||
(r"\theta!", _factorial(theta)),
|
||||
(r"(x + 1)!", _factorial(_Add(x, 1))),
|
||||
(r"(x!)!", _factorial(_factorial(x))),
|
||||
(r"x!!!", _factorial(_factorial(_factorial(x)))),
|
||||
(r"5!7!", _Mul(_factorial(5), _factorial(7)))
|
||||
]
|
||||
|
||||
EVALUATED_FACTORIAL_EXPRESSION_PAIRS = [
|
||||
(r"x!", factorial(x)),
|
||||
(r"100!", factorial(100)),
|
||||
(r"\theta!", factorial(theta)),
|
||||
(r"(x + 1)!", factorial(x + 1)),
|
||||
(r"(x!)!", factorial(factorial(x))),
|
||||
(r"x!!!", factorial(factorial(factorial(x)))),
|
||||
(r"5!7!", factorial(5) * factorial(7)),
|
||||
(r"24! \times 24!", factorial(24) * factorial(24))
|
||||
]
|
||||
|
||||
UNEVALUATED_SUM_EXPRESSION_PAIRS = [
|
||||
(r"\sum_{k = 1}^{3} c", Sum(_Mul(1, c), (k, 1, 3))),
|
||||
(r"\sum_{k = 1}^3 c", Sum(_Mul(1, c), (k, 1, 3))),
|
||||
(r"\sum^{3}_{k = 1} c", Sum(_Mul(1, c), (k, 1, 3))),
|
||||
(r"\sum^3_{k = 1} c", Sum(_Mul(1, c), (k, 1, 3))),
|
||||
(r"\sum_{k = 1}^{10} k^2", Sum(_Mul(1, k ** 2), (k, 1, 10))),
|
||||
(r"\sum_{n = 0}^{\infty} \frac{1}{n!}",
|
||||
Sum(_Mul(1, _Mul(1, _Pow(_factorial(n), -1))), (n, 0, oo)))
|
||||
]
|
||||
|
||||
EVALUATED_SUM_EXPRESSION_PAIRS = [
|
||||
(r"\sum_{k = 1}^{3} c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum_{k = 1}^3 c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum^{3}_{k = 1} c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum^3_{k = 1} c", Sum(c, (k, 1, 3))),
|
||||
(r"\sum_{k = 1}^{10} k^2", Sum(k ** 2, (k, 1, 10))),
|
||||
(r"\sum_{n = 0}^{\infty} \frac{1}{n!}", Sum(1 / factorial(n), (n, 0, oo)))
|
||||
]
|
||||
|
||||
UNEVALUATED_PRODUCT_EXPRESSION_PAIRS = [
|
||||
(r"\prod_{a = b}^{c} x", Product(x, (a, b, c))),
|
||||
(r"\prod_{a = b}^c x", Product(x, (a, b, c))),
|
||||
(r"\prod^{c}_{a = b} x", Product(x, (a, b, c))),
|
||||
(r"\prod^c_{a = b} x", Product(x, (a, b, c)))
|
||||
]
|
||||
|
||||
APPLIED_FUNCTION_EXPRESSION_PAIRS = [
|
||||
(r"f(x)", f(x)),
|
||||
(r"f(x, y)", f(x, y)),
|
||||
(r"f(x, y, z)", f(x, y, z)),
|
||||
(r"f'_1(x)", Function("f_{1}'")(x)),
|
||||
(r"f_{1}''(x+y)", Function("f_{1}''")(x + y)),
|
||||
(r"h_{\theta}(x_0, x_1)",
|
||||
Function('h_{theta}')(Symbol('x_{0}'), Symbol('x_{1}')))
|
||||
]
|
||||
|
||||
UNEVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS = [
|
||||
(r"|x|", _Abs(x)),
|
||||
(r"||x||", _Abs(Abs(x))),
|
||||
(r"|x||y|", _Abs(x) * _Abs(y)),
|
||||
(r"||x||y||", _Abs(_Abs(x) * _Abs(y))),
|
||||
(r"\lfloor x \rfloor", floor(x)),
|
||||
(r"\lceil x \rceil", ceiling(x)),
|
||||
(r"\exp x", _exp(x)),
|
||||
(r"\exp(x)", _exp(x)),
|
||||
(r"\lg x", _log(x, 10)),
|
||||
(r"\ln x", _log(x)),
|
||||
(r"\ln xy", _log(x * y)),
|
||||
(r"\log x", _log(x)),
|
||||
(r"\log xy", _log(x * y)),
|
||||
(r"\log_{2} x", _log(x, 2)),
|
||||
(r"\log_{a} x", _log(x, a)),
|
||||
(r"\log_{11} x", _log(x, 11)),
|
||||
(r"\log_{a^2} x", _log(x, _Pow(a, 2))),
|
||||
(r"\log_2 x", _log(x, 2)),
|
||||
(r"\log_a x", _log(x, a)),
|
||||
(r"\overline{z}", _Conjugate(z)),
|
||||
(r"\overline{\overline{z}}", _Conjugate(_Conjugate(z))),
|
||||
(r"\overline{x + y}", _Conjugate(_Add(x, y))),
|
||||
(r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y)),
|
||||
(r"\min(a, b)", _Min(a, b)),
|
||||
(r"\min(a, b, c - d, xy)", _Min(a, b, c - d, x * y)),
|
||||
(r"\max(a, b)", _Max(a, b)),
|
||||
(r"\max(a, b, c - d, xy)", _Max(a, b, c - d, x * y)),
|
||||
# physics things don't have an `evaluate=False` variant
|
||||
(r"\langle x |", Bra('x')),
|
||||
(r"| x \rangle", Ket('x')),
|
||||
(r"\langle x | y \rangle", InnerProduct(Bra('x'), Ket('y'))),
|
||||
]
|
||||
|
||||
EVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS = [
|
||||
(r"|x|", Abs(x)),
|
||||
(r"||x||", Abs(Abs(x))),
|
||||
(r"|x||y|", Abs(x) * Abs(y)),
|
||||
(r"||x||y||", Abs(Abs(x) * Abs(y))),
|
||||
(r"\lfloor x \rfloor", floor(x)),
|
||||
(r"\lceil x \rceil", ceiling(x)),
|
||||
(r"\exp x", exp(x)),
|
||||
(r"\exp(x)", exp(x)),
|
||||
(r"\lg x", log(x, 10)),
|
||||
(r"\ln x", log(x)),
|
||||
(r"\ln xy", log(x * y)),
|
||||
(r"\log x", log(x)),
|
||||
(r"\log xy", log(x * y)),
|
||||
(r"\log_{2} x", log(x, 2)),
|
||||
(r"\log_{a} x", log(x, a)),
|
||||
(r"\log_{11} x", log(x, 11)),
|
||||
(r"\log_{a^2} x", log(x, _Pow(a, 2))),
|
||||
(r"\log_2 x", log(x, 2)),
|
||||
(r"\log_a x", log(x, a)),
|
||||
(r"\overline{z}", conjugate(z)),
|
||||
(r"\overline{\overline{z}}", conjugate(conjugate(z))),
|
||||
(r"\overline{x + y}", conjugate(x + y)),
|
||||
(r"\overline{x} + \overline{y}", conjugate(x) + conjugate(y)),
|
||||
(r"\min(a, b)", Min(a, b)),
|
||||
(r"\min(a, b, c - d, xy)", Min(a, b, c - d, x * y)),
|
||||
(r"\max(a, b)", Max(a, b)),
|
||||
(r"\max(a, b, c - d, xy)", Max(a, b, c - d, x * y)),
|
||||
(r"\langle x |", Bra('x')),
|
||||
(r"| x \rangle", Ket('x')),
|
||||
(r"\langle x | y \rangle", InnerProduct(Bra('x'), Ket('y'))),
|
||||
]
|
||||
|
||||
SPACING_RELATED_EXPRESSION_PAIRS = [
|
||||
(r"a \, b", _Mul(a, b)),
|
||||
(r"a \thinspace b", _Mul(a, b)),
|
||||
(r"a \: b", _Mul(a, b)),
|
||||
(r"a \medspace b", _Mul(a, b)),
|
||||
(r"a \; b", _Mul(a, b)),
|
||||
(r"a \thickspace b", _Mul(a, b)),
|
||||
(r"a \quad b", _Mul(a, b)),
|
||||
(r"a \qquad b", _Mul(a, b)),
|
||||
(r"a \! b", _Mul(a, b)),
|
||||
(r"a \negthinspace b", _Mul(a, b)),
|
||||
(r"a \negmedspace b", _Mul(a, b)),
|
||||
(r"a \negthickspace b", _Mul(a, b))
|
||||
]
|
||||
|
||||
UNEVALUATED_BINOMIAL_EXPRESSION_PAIRS = [
|
||||
(r"\binom{n}{k}", _binomial(n, k)),
|
||||
(r"\tbinom{n}{k}", _binomial(n, k)),
|
||||
(r"\dbinom{n}{k}", _binomial(n, k)),
|
||||
(r"\binom{n}{0}", _binomial(n, 0)),
|
||||
(r"x^\binom{n}{k}", _Pow(x, _binomial(n, k)))
|
||||
]
|
||||
|
||||
EVALUATED_BINOMIAL_EXPRESSION_PAIRS = [
|
||||
(r"\binom{n}{k}", binomial(n, k)),
|
||||
(r"\tbinom{n}{k}", binomial(n, k)),
|
||||
(r"\dbinom{n}{k}", binomial(n, k)),
|
||||
(r"\binom{n}{0}", binomial(n, 0)),
|
||||
(r"x^\binom{n}{k}", x ** binomial(n, k))
|
||||
]
|
||||
|
||||
MISCELLANEOUS_EXPRESSION_PAIRS = [
|
||||
(r"\left(x + y\right) z", _Mul(_Add(x, y), z)),
|
||||
(r"\left( x + y\right ) z", _Mul(_Add(x, y), z)),
|
||||
(r"\left( x + y\right ) z", _Mul(_Add(x, y), z)),
|
||||
]
|
||||
|
||||
UNEVALUATED_LITERAL_COMPLEX_NUMBER_EXPRESSION_PAIRS = [
|
||||
(r"\imaginaryunit^2", _Pow(I, 2)),
|
||||
(r"|\imaginaryunit|", _Abs(I)),
|
||||
(r"\overline{\imaginaryunit}", _Conjugate(I)),
|
||||
(r"\imaginaryunit+\imaginaryunit", _Add(I, I)),
|
||||
(r"\imaginaryunit-\imaginaryunit", _Add(I, -I)),
|
||||
(r"\imaginaryunit*\imaginaryunit", _Mul(I, I)),
|
||||
(r"\imaginaryunit/\imaginaryunit", _Mul(I, _Pow(I, -1))),
|
||||
(r"(1+\imaginaryunit)/|1+\imaginaryunit|", _Mul(_Add(1, I), _Pow(_Abs(_Add(1, I)), -1)))
|
||||
]
|
||||
|
||||
UNEVALUATED_MATRIX_EXPRESSION_PAIRS = [
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\begin{pmatrix}a & b \\x & y\\\end{pmatrix}",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\begin{bmatrix}a & b \\x & y\end{bmatrix}",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\left(\begin{matrix}a & b \\x & y\end{matrix}\right)",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\left[\begin{matrix}a & b \\x & y\end{matrix}\right]",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\left[\begin{array}{cc}a & b \\x & y\end{array}\right]",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\left(\begin{array}{cc}a & b \\x & y\end{array}\right)",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"\left( { \begin{array}{cc}a & b \\x & y\end{array} } \right)",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
(r"+\begin{pmatrix}a & b \\x & y\end{pmatrix}",
|
||||
Matrix([[a, b], [x, y]])),
|
||||
((r"\begin{pmatrix}x & y \\a & b\end{pmatrix}+"
|
||||
r"\begin{pmatrix}a & b \\x & y\end{pmatrix}"),
|
||||
_MatAdd(Matrix([[x, y], [a, b]]), Matrix([[a, b], [x, y]]))),
|
||||
(r"-\begin{pmatrix}a & b \\x & y\end{pmatrix}",
|
||||
_MatMul(-1, Matrix([[a, b], [x, y]]))),
|
||||
((r"\begin{pmatrix}x & y \\a & b\end{pmatrix}-"
|
||||
r"\begin{pmatrix}a & b \\x & y\end{pmatrix}"),
|
||||
_MatAdd(Matrix([[x, y], [a, b]]), _MatMul(-1, Matrix([[a, b], [x, y]])))),
|
||||
((r"\begin{pmatrix}a & b & c \\x & y & z \\a & b & c \end{pmatrix}*"
|
||||
r"\begin{pmatrix}x & y & z \\a & b & c \\a & b & c \end{pmatrix}*"
|
||||
r"\begin{pmatrix}a & b & c \\x & y & z \\x & y & z \end{pmatrix}"),
|
||||
_MatMul(_MatMul(Matrix([[a, b, c], [x, y, z], [a, b, c]]),
|
||||
Matrix([[x, y, z], [a, b, c], [a, b, c]])),
|
||||
Matrix([[a, b, c], [x, y, z], [x, y, z]]))),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}/2",
|
||||
_MatMul(Matrix([[a, b], [x, y]]), _Pow(2, -1))),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}^2",
|
||||
_Pow(Matrix([[a, b], [x, y]]), 2)),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}^{-1}",
|
||||
_Pow(Matrix([[a, b], [x, y]]), -1)),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}^T",
|
||||
Transpose(Matrix([[a, b], [x, y]]))),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}^{T}",
|
||||
Transpose(Matrix([[a, b], [x, y]]))),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}^\mathit{T}",
|
||||
Transpose(Matrix([[a, b], [x, y]]))),
|
||||
(r"\begin{pmatrix}1 & 2 \\3 & 4\end{pmatrix}^T",
|
||||
Transpose(Matrix([[1, 2], [3, 4]]))),
|
||||
((r"(\begin{pmatrix}1 & 2 \\3 & 4\end{pmatrix}+"
|
||||
r"\begin{pmatrix}1 & 2 \\3 & 4\end{pmatrix}^T)*"
|
||||
r"\begin{bmatrix}1\\0\end{bmatrix}"),
|
||||
_MatMul(_MatAdd(Matrix([[1, 2], [3, 4]]),
|
||||
Transpose(Matrix([[1, 2], [3, 4]]))),
|
||||
Matrix([[1], [0]]))),
|
||||
((r"(\begin{pmatrix}a & b \\x & y\end{pmatrix}+"
|
||||
r"\begin{pmatrix}x & y \\a & b\end{pmatrix})^2"),
|
||||
_Pow(_MatAdd(Matrix([[a, b], [x, y]]),
|
||||
Matrix([[x, y], [a, b]])), 2)),
|
||||
((r"(\begin{pmatrix}a & b \\x & y\end{pmatrix}+"
|
||||
r"\begin{pmatrix}x & y \\a & b\end{pmatrix})^T"),
|
||||
Transpose(_MatAdd(Matrix([[a, b], [x, y]]),
|
||||
Matrix([[x, y], [a, b]])))),
|
||||
(r"\overline{\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}}",
|
||||
_Conjugate(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]]))))
|
||||
]
|
||||
|
||||
EVALUATED_MATRIX_EXPRESSION_PAIRS = [
|
||||
(r"\det\left(\left[ { \begin{array}{cc}a&b\\x&y\end{array} } \right]\right)",
|
||||
Matrix([[a, b], [x, y]]).det()),
|
||||
(r"\det \begin{pmatrix}1&2\\3&4\end{pmatrix}", -2),
|
||||
(r"\det{\begin{pmatrix}1&2\\3&4\end{pmatrix}}", -2),
|
||||
(r"\det(\begin{pmatrix}1&2\\3&4\end{pmatrix})", -2),
|
||||
(r"\det\left(\begin{pmatrix}1&2\\3&4\end{pmatrix}\right)", -2),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}/\begin{vmatrix}a & b \\x & y\end{vmatrix}",
|
||||
_MatMul(Matrix([[a, b], [x, y]]), _Pow(Matrix([[a, b], [x, y]]).det(), -1))),
|
||||
(r"\begin{pmatrix}a & b \\x & y\end{pmatrix}/|\begin{matrix}a & b \\x & y\end{matrix}|",
|
||||
_MatMul(Matrix([[a, b], [x, y]]), _Pow(Matrix([[a, b], [x, y]]).det(), -1))),
|
||||
(r"\frac{\begin{pmatrix}a & b \\x & y\end{pmatrix}}{| { \begin{matrix}a & b \\x & y\end{matrix} } |}",
|
||||
_MatMul(Matrix([[a, b], [x, y]]), _Pow(Matrix([[a, b], [x, y]]).det(), -1))),
|
||||
(r"\overline{\begin{pmatrix}\imaginaryunit & 1+\imaginaryunit \\-\imaginaryunit & 4\end{pmatrix}}",
|
||||
Matrix([[-I, 1-I], [I, 4]])),
|
||||
(r"\begin{pmatrix}\imaginaryunit & 1+\imaginaryunit \\-\imaginaryunit & 4\end{pmatrix}^H",
|
||||
Matrix([[-I, I], [1-I, 4]])),
|
||||
(r"\trace(\begin{pmatrix}\imaginaryunit & 1+\imaginaryunit \\-\imaginaryunit & 4\end{pmatrix})",
|
||||
Trace(Matrix([[I, 1+I], [-I, 4]]))),
|
||||
(r"\adjugate(\begin{pmatrix}1 & 2 \\3 & 4\end{pmatrix})",
|
||||
Matrix([[4, -2], [-3, 1]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^\ast",
|
||||
Matrix([[-2*I, 6], [4, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{\ast}",
|
||||
Matrix([[-2*I, 6], [4, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{\ast\ast}",
|
||||
Matrix([[2*I, 4], [6, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{\ast\ast\ast}",
|
||||
Matrix([[-2*I, 6], [4, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{*}",
|
||||
Matrix([[-2*I, 6], [4, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{**}",
|
||||
Matrix([[2*I, 4], [6, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{***}",
|
||||
Matrix([[-2*I, 6], [4, 8]])),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^\prime",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{\prime}",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{\prime\prime}",
|
||||
_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]]))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{\prime\prime\prime}",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{'}",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{''}",
|
||||
_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]]))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^{'''}",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})'",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})''",
|
||||
_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]]))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})'''",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"\det(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})",
|
||||
(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]]))).det()),
|
||||
(r"\trace(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})",
|
||||
Trace(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"\adjugate(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})",
|
||||
(Matrix([[8, -4], [-6, 2*I]]))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^T",
|
||||
Transpose(_MatAdd(Matrix([[I, 2], [3, 4]]),
|
||||
Matrix([[I, 2], [3, 4]])))),
|
||||
(r"(\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix}+\begin{pmatrix}\imaginaryunit&2\\3&4\end{pmatrix})^H",
|
||||
(Matrix([[-2*I, 6], [4, 8]])))
|
||||
]
|
||||
|
||||
|
||||
def test_symbol_expressions():
|
||||
expected_failures = {6, 7}
|
||||
for i, (latex_str, sympy_expr) in enumerate(SYMBOL_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_simple_expressions():
|
||||
expected_failures = {20}
|
||||
for i, (latex_str, sympy_expr) in enumerate(UNEVALUATED_SIMPLE_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for i, (latex_str, sympy_expr) in enumerate(EVALUATED_SIMPLE_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_fraction_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_FRACTION_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_FRACTION_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_relation_expressions():
|
||||
for latex_str, sympy_expr in RELATION_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
def test_power_expressions():
|
||||
expected_failures = {3}
|
||||
for i, (latex_str, sympy_expr) in enumerate(UNEVALUATED_POWER_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for i, (latex_str, sympy_expr) in enumerate(EVALUATED_POWER_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_integral_expressions():
|
||||
expected_failures = {14}
|
||||
for i, (latex_str, sympy_expr) in enumerate(UNEVALUATED_INTEGRAL_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, i
|
||||
|
||||
for i, (latex_str, sympy_expr) in enumerate(EVALUATED_INTEGRAL_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_derivative_expressions():
|
||||
expected_failures = {3, 4}
|
||||
for i, (latex_str, sympy_expr) in enumerate(DERIVATIVE_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for i, (latex_str, sympy_expr) in enumerate(DERIVATIVE_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_trigonometric_expressions():
|
||||
expected_failures = {3}
|
||||
for i, (latex_str, sympy_expr) in enumerate(TRIGONOMETRIC_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_limit_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_LIMIT_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_square_root_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_SQRT_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_SQRT_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_factorial_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_FACTORIAL_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_FACTORIAL_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_sum_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_SUM_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_SUM_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_product_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_PRODUCT_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
@XFAIL
|
||||
def test_applied_function_expressions():
|
||||
expected_failures = {0, 3, 4} # 0 is ambiguous, and the others require not-yet-added features
|
||||
# not sure why 1, and 2 are failing
|
||||
for i, (latex_str, sympy_expr) in enumerate(APPLIED_FUNCTION_EXPRESSION_PAIRS):
|
||||
if i in expected_failures:
|
||||
continue
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_common_function_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_COMMON_FUNCTION_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
# unhandled bug causing these to fail
|
||||
@XFAIL
|
||||
def test_spacing():
|
||||
for latex_str, sympy_expr in SPACING_RELATED_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_binomial_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_BINOMIAL_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_BINOMIAL_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_miscellaneous_expressions():
|
||||
for latex_str, sympy_expr in MISCELLANEOUS_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_literal_complex_number_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_LITERAL_COMPLEX_NUMBER_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
|
||||
def test_matrix_expressions():
|
||||
for latex_str, sympy_expr in UNEVALUATED_MATRIX_EXPRESSION_PAIRS:
|
||||
with evaluate(False):
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
|
||||
for latex_str, sympy_expr in EVALUATED_MATRIX_EXPRESSION_PAIRS:
|
||||
assert parse_latex_lark(latex_str) == sympy_expr, latex_str
|
||||
@@ -0,0 +1,280 @@
|
||||
from sympy import sin, Function, symbols, Dummy, Lambda, cos
|
||||
from sympy.parsing.mathematica import parse_mathematica, MathematicaParser
|
||||
from sympy.core.sympify import sympify
|
||||
from sympy.abc import n, w, x, y, z
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_mathematica():
|
||||
d = {
|
||||
'- 6x': '-6*x',
|
||||
'Sin[x]^2': 'sin(x)**2',
|
||||
'2(x-1)': '2*(x-1)',
|
||||
'3y+8': '3*y+8',
|
||||
'ArcSin[2x+9(4-x)^2]/x': 'asin(2*x+9*(4-x)**2)/x',
|
||||
'x+y': 'x+y',
|
||||
'355/113': '355/113',
|
||||
'2.718281828': '2.718281828',
|
||||
'Cos(1/2 * π)': 'Cos(π/2)',
|
||||
'Sin[12]': 'sin(12)',
|
||||
'Exp[Log[4]]': 'exp(log(4))',
|
||||
'(x+1)(x+3)': '(x+1)*(x+3)',
|
||||
'Cos[ArcCos[3.6]]': 'cos(acos(3.6))',
|
||||
'Cos[x]==Sin[y]': 'Eq(cos(x), sin(y))',
|
||||
'2*Sin[x+y]': '2*sin(x+y)',
|
||||
'Sin[x]+Cos[y]': 'sin(x)+cos(y)',
|
||||
'Sin[Cos[x]]': 'sin(cos(x))',
|
||||
'2*Sqrt[x+y]': '2*sqrt(x+y)', # Test case from the issue 4259
|
||||
'+Sqrt[2]': 'sqrt(2)',
|
||||
'-Sqrt[2]': '-sqrt(2)',
|
||||
'-1/Sqrt[2]': '-1/sqrt(2)',
|
||||
'-(1/Sqrt[3])': '-(1/sqrt(3))',
|
||||
'1/(2*Sqrt[5])': '1/(2*sqrt(5))',
|
||||
'Mod[5,3]': 'Mod(5,3)',
|
||||
'-Mod[5,3]': '-Mod(5,3)',
|
||||
'(x+1)y': '(x+1)*y',
|
||||
'x(y+1)': 'x*(y+1)',
|
||||
'Sin[x]Cos[y]': 'sin(x)*cos(y)',
|
||||
'Sin[x]^2Cos[y]^2': 'sin(x)**2*cos(y)**2',
|
||||
'Cos[x]^2(1 - Cos[y]^2)': 'cos(x)**2*(1-cos(y)**2)',
|
||||
'x y': 'x*y',
|
||||
'x y': 'x*y',
|
||||
'2 x': '2*x',
|
||||
'x 8': 'x*8',
|
||||
'2 8': '2*8',
|
||||
'4.x': '4.*x',
|
||||
'4. 3': '4.*3',
|
||||
'4. 3.': '4.*3.',
|
||||
'1 2 3': '1*2*3',
|
||||
' - 2 * Sqrt[ 2 3 * ( 1 + 5 ) ] ': '-2*sqrt(2*3*(1+5))',
|
||||
'Log[2,4]': 'log(4,2)',
|
||||
'Log[Log[2,4],4]': 'log(4,log(4,2))',
|
||||
'Exp[Sqrt[2]^2Log[2, 8]]': 'exp(sqrt(2)**2*log(8,2))',
|
||||
'ArcSin[Cos[0]]': 'asin(cos(0))',
|
||||
'Log2[16]': 'log(16,2)',
|
||||
'Max[1,-2,3,-4]': 'Max(1,-2,3,-4)',
|
||||
'Min[1,-2,3]': 'Min(1,-2,3)',
|
||||
'Exp[I Pi/2]': 'exp(I*pi/2)',
|
||||
'ArcTan[x,y]': 'atan2(y,x)',
|
||||
'Pochhammer[x,y]': 'rf(x,y)',
|
||||
'ExpIntegralEi[x]': 'Ei(x)',
|
||||
'SinIntegral[x]': 'Si(x)',
|
||||
'CosIntegral[x]': 'Ci(x)',
|
||||
'AiryAi[x]': 'airyai(x)',
|
||||
'AiryAiPrime[5]': 'airyaiprime(5)',
|
||||
'AiryBi[x]': 'airybi(x)',
|
||||
'AiryBiPrime[7]': 'airybiprime(7)',
|
||||
'LogIntegral[4]': ' li(4)',
|
||||
'PrimePi[7]': 'primepi(7)',
|
||||
'Prime[5]': 'prime(5)',
|
||||
'PrimeQ[5]': 'isprime(5)',
|
||||
'Rational[2,19]': 'Rational(2,19)', # test case for issue 25716
|
||||
}
|
||||
|
||||
for e in d:
|
||||
assert parse_mathematica(e) == sympify(d[e])
|
||||
|
||||
# The parsed form of this expression should not evaluate the Lambda object:
|
||||
assert parse_mathematica("Sin[#]^2 + Cos[#]^2 &[x]") == sin(x)**2 + cos(x)**2
|
||||
|
||||
d1, d2, d3 = symbols("d1:4", cls=Dummy)
|
||||
assert parse_mathematica("Sin[#] + Cos[#3] &").dummy_eq(Lambda((d1, d2, d3), sin(d1) + cos(d3)))
|
||||
assert parse_mathematica("Sin[#^2] &").dummy_eq(Lambda(d1, sin(d1**2)))
|
||||
assert parse_mathematica("Function[x, x^3]") == Lambda(x, x**3)
|
||||
assert parse_mathematica("Function[{x, y}, x^2 + y^2]") == Lambda((x, y), x**2 + y**2)
|
||||
|
||||
|
||||
def test_parser_mathematica_tokenizer():
|
||||
parser = MathematicaParser()
|
||||
|
||||
chain = lambda expr: parser._from_tokens_to_fullformlist(parser._from_mathematica_to_tokens(expr))
|
||||
|
||||
# Basic patterns
|
||||
assert chain("x") == "x"
|
||||
assert chain("42") == "42"
|
||||
assert chain(".2") == ".2"
|
||||
assert chain("+x") == "x"
|
||||
assert chain("-1") == "-1"
|
||||
assert chain("- 3") == "-3"
|
||||
assert chain("α") == "α"
|
||||
assert chain("+Sin[x]") == ["Sin", "x"]
|
||||
assert chain("-Sin[x]") == ["Times", "-1", ["Sin", "x"]]
|
||||
assert chain("x(a+1)") == ["Times", "x", ["Plus", "a", "1"]]
|
||||
assert chain("(x)") == "x"
|
||||
assert chain("(+x)") == "x"
|
||||
assert chain("-a") == ["Times", "-1", "a"]
|
||||
assert chain("(-x)") == ["Times", "-1", "x"]
|
||||
assert chain("(x + y)") == ["Plus", "x", "y"]
|
||||
assert chain("3 + 4") == ["Plus", "3", "4"]
|
||||
assert chain("a - 3") == ["Plus", "a", "-3"]
|
||||
assert chain("a - b") == ["Plus", "a", ["Times", "-1", "b"]]
|
||||
assert chain("7 * 8") == ["Times", "7", "8"]
|
||||
assert chain("a + b*c") == ["Plus", "a", ["Times", "b", "c"]]
|
||||
assert chain("a + b* c* d + 2 * e") == ["Plus", "a", ["Times", "b", "c", "d"], ["Times", "2", "e"]]
|
||||
assert chain("a / b") == ["Times", "a", ["Power", "b", "-1"]]
|
||||
|
||||
# Missing asterisk (*) patterns:
|
||||
assert chain("x y") == ["Times", "x", "y"]
|
||||
assert chain("3 4") == ["Times", "3", "4"]
|
||||
assert chain("a[b] c") == ["Times", ["a", "b"], "c"]
|
||||
assert chain("(x) (y)") == ["Times", "x", "y"]
|
||||
assert chain("3 (a)") == ["Times", "3", "a"]
|
||||
assert chain("(a) b") == ["Times", "a", "b"]
|
||||
assert chain("4.2") == "4.2"
|
||||
assert chain("4 2") == ["Times", "4", "2"]
|
||||
assert chain("4 2") == ["Times", "4", "2"]
|
||||
assert chain("3 . 4") == ["Dot", "3", "4"]
|
||||
assert chain("4. 2") == ["Times", "4.", "2"]
|
||||
assert chain("x.y") == ["Dot", "x", "y"]
|
||||
assert chain("4.y") == ["Times", "4.", "y"]
|
||||
assert chain("4 .y") == ["Dot", "4", "y"]
|
||||
assert chain("x.4") == ["Times", "x", ".4"]
|
||||
assert chain("x0.3") == ["Times", "x0", ".3"]
|
||||
assert chain("x. 4") == ["Dot", "x", "4"]
|
||||
|
||||
# Comments
|
||||
assert chain("a (* +b *) + c") == ["Plus", "a", "c"]
|
||||
assert chain("a (* + b *) + (**)c (* +d *) + e") == ["Plus", "a", "c", "e"]
|
||||
assert chain("""a + (*
|
||||
+ b
|
||||
*) c + (* d
|
||||
*) e
|
||||
""") == ["Plus", "a", "c", "e"]
|
||||
|
||||
# Operators couples + and -, * and / are mutually associative:
|
||||
# (i.e. expression gets flattened when mixing these operators)
|
||||
assert chain("a*b/c") == ["Times", "a", "b", ["Power", "c", "-1"]]
|
||||
assert chain("a/b*c") == ["Times", "a", ["Power", "b", "-1"], "c"]
|
||||
assert chain("a+b-c") == ["Plus", "a", "b", ["Times", "-1", "c"]]
|
||||
assert chain("a-b+c") == ["Plus", "a", ["Times", "-1", "b"], "c"]
|
||||
assert chain("-a + b -c ") == ["Plus", ["Times", "-1", "a"], "b", ["Times", "-1", "c"]]
|
||||
assert chain("a/b/c*d") == ["Times", "a", ["Power", "b", "-1"], ["Power", "c", "-1"], "d"]
|
||||
assert chain("a/b/c") == ["Times", "a", ["Power", "b", "-1"], ["Power", "c", "-1"]]
|
||||
assert chain("a-b-c") == ["Plus", "a", ["Times", "-1", "b"], ["Times", "-1", "c"]]
|
||||
assert chain("1/a") == ["Times", "1", ["Power", "a", "-1"]]
|
||||
assert chain("1/a/b") == ["Times", "1", ["Power", "a", "-1"], ["Power", "b", "-1"]]
|
||||
assert chain("-1/a*b") == ["Times", "-1", ["Power", "a", "-1"], "b"]
|
||||
|
||||
# Enclosures of various kinds, i.e. ( ) [ ] [[ ]] { }
|
||||
assert chain("(a + b) + c") == ["Plus", ["Plus", "a", "b"], "c"]
|
||||
assert chain(" a + (b + c) + d ") == ["Plus", "a", ["Plus", "b", "c"], "d"]
|
||||
assert chain("a * (b + c)") == ["Times", "a", ["Plus", "b", "c"]]
|
||||
assert chain("a b (c d)") == ["Times", "a", "b", ["Times", "c", "d"]]
|
||||
assert chain("{a, b, 2, c}") == ["List", "a", "b", "2", "c"]
|
||||
assert chain("{a, {b, c}}") == ["List", "a", ["List", "b", "c"]]
|
||||
assert chain("{{a}}") == ["List", ["List", "a"]]
|
||||
assert chain("a[b, c]") == ["a", "b", "c"]
|
||||
assert chain("a[[b, c]]") == ["Part", "a", "b", "c"]
|
||||
assert chain("a[b[c]]") == ["a", ["b", "c"]]
|
||||
assert chain("a[[b, c[[d, {e,f}]]]]") == ["Part", "a", "b", ["Part", "c", "d", ["List", "e", "f"]]]
|
||||
assert chain("a[b[[c,d]]]") == ["a", ["Part", "b", "c", "d"]]
|
||||
assert chain("a[[b[c]]]") == ["Part", "a", ["b", "c"]]
|
||||
assert chain("a[[b[[c]]]]") == ["Part", "a", ["Part", "b", "c"]]
|
||||
assert chain("a[[b[c[[d]]]]]") == ["Part", "a", ["b", ["Part", "c", "d"]]]
|
||||
assert chain("a[b[[c[d]]]]") == ["a", ["Part", "b", ["c", "d"]]]
|
||||
assert chain("x[[a+1, b+2, c+3]]") == ["Part", "x", ["Plus", "a", "1"], ["Plus", "b", "2"], ["Plus", "c", "3"]]
|
||||
assert chain("x[a+1, b+2, c+3]") == ["x", ["Plus", "a", "1"], ["Plus", "b", "2"], ["Plus", "c", "3"]]
|
||||
assert chain("{a+1, b+2, c+3}") == ["List", ["Plus", "a", "1"], ["Plus", "b", "2"], ["Plus", "c", "3"]]
|
||||
|
||||
# Flat operator:
|
||||
assert chain("a*b*c*d*e") == ["Times", "a", "b", "c", "d", "e"]
|
||||
assert chain("a +b + c+ d+e") == ["Plus", "a", "b", "c", "d", "e"]
|
||||
|
||||
# Right priority operator:
|
||||
assert chain("a^b") == ["Power", "a", "b"]
|
||||
assert chain("a^b^c") == ["Power", "a", ["Power", "b", "c"]]
|
||||
assert chain("a^b^c^d") == ["Power", "a", ["Power", "b", ["Power", "c", "d"]]]
|
||||
|
||||
# Left priority operator:
|
||||
assert chain("a/.b") == ["ReplaceAll", "a", "b"]
|
||||
assert chain("a/.b/.c/.d") == ["ReplaceAll", ["ReplaceAll", ["ReplaceAll", "a", "b"], "c"], "d"]
|
||||
|
||||
assert chain("a//b") == ["a", "b"]
|
||||
assert chain("a//b//c") == [["a", "b"], "c"]
|
||||
assert chain("a//b//c//d") == [[["a", "b"], "c"], "d"]
|
||||
|
||||
# Compound expressions
|
||||
assert chain("a;b") == ["CompoundExpression", "a", "b"]
|
||||
assert chain("a;") == ["CompoundExpression", "a", "Null"]
|
||||
assert chain("a;b;") == ["CompoundExpression", "a", "b", "Null"]
|
||||
assert chain("a[b;c]") == ["a", ["CompoundExpression", "b", "c"]]
|
||||
assert chain("a[b,c;d,e]") == ["a", "b", ["CompoundExpression", "c", "d"], "e"]
|
||||
assert chain("a[b,c;,d]") == ["a", "b", ["CompoundExpression", "c", "Null"], "d"]
|
||||
|
||||
# New lines
|
||||
assert chain("a\nb\n") == ["CompoundExpression", "a", "b"]
|
||||
assert chain("a\n\nb\n (c \nd) \n") == ["CompoundExpression", "a", "b", ["Times", "c", "d"]]
|
||||
assert chain("\na; b\nc") == ["CompoundExpression", "a", "b", "c"]
|
||||
assert chain("a + \nb\n") == ["Plus", "a", "b"]
|
||||
assert chain("a\nb; c; d\n e; (f \n g); h + \n i") == ["CompoundExpression", "a", "b", "c", "d", "e", ["Times", "f", "g"], ["Plus", "h", "i"]]
|
||||
assert chain("\n{\na\nb; c; d\n e (f \n g); h + \n i\n\n}\n") == ["List", ["CompoundExpression", ["Times", "a", "b"], "c", ["Times", "d", "e", ["Times", "f", "g"]], ["Plus", "h", "i"]]]
|
||||
|
||||
# Patterns
|
||||
assert chain("y_") == ["Pattern", "y", ["Blank"]]
|
||||
assert chain("y_.") == ["Optional", ["Pattern", "y", ["Blank"]]]
|
||||
assert chain("y__") == ["Pattern", "y", ["BlankSequence"]]
|
||||
assert chain("y___") == ["Pattern", "y", ["BlankNullSequence"]]
|
||||
assert chain("a[b_.,c_]") == ["a", ["Optional", ["Pattern", "b", ["Blank"]]], ["Pattern", "c", ["Blank"]]]
|
||||
assert chain("b_. c") == ["Times", ["Optional", ["Pattern", "b", ["Blank"]]], "c"]
|
||||
|
||||
# Slots for lambda functions
|
||||
assert chain("#") == ["Slot", "1"]
|
||||
assert chain("#3") == ["Slot", "3"]
|
||||
assert chain("#n") == ["Slot", "n"]
|
||||
assert chain("##") == ["SlotSequence", "1"]
|
||||
assert chain("##a") == ["SlotSequence", "a"]
|
||||
|
||||
# Lambda functions
|
||||
assert chain("x&") == ["Function", "x"]
|
||||
assert chain("#&") == ["Function", ["Slot", "1"]]
|
||||
assert chain("#+3&") == ["Function", ["Plus", ["Slot", "1"], "3"]]
|
||||
assert chain("#1 + #2&") == ["Function", ["Plus", ["Slot", "1"], ["Slot", "2"]]]
|
||||
assert chain("# + #&") == ["Function", ["Plus", ["Slot", "1"], ["Slot", "1"]]]
|
||||
assert chain("#&[x]") == [["Function", ["Slot", "1"]], "x"]
|
||||
assert chain("#1 + #2 & [x, y]") == [["Function", ["Plus", ["Slot", "1"], ["Slot", "2"]]], "x", "y"]
|
||||
assert chain("#1^2#2^3&") == ["Function", ["Times", ["Power", ["Slot", "1"], "2"], ["Power", ["Slot", "2"], "3"]]]
|
||||
|
||||
# Strings inside Mathematica expressions:
|
||||
assert chain('"abc"') == ["_Str", "abc"]
|
||||
assert chain('"a\\"b"') == ["_Str", 'a"b']
|
||||
# This expression does not make sense mathematically, it's just testing the parser:
|
||||
assert chain('x + "abc" ^ 3') == ["Plus", "x", ["Power", ["_Str", "abc"], "3"]]
|
||||
assert chain('"a (* b *) c"') == ["_Str", "a (* b *) c"]
|
||||
assert chain('"a" (* b *) ') == ["_Str", "a"]
|
||||
assert chain('"a [ b] "') == ["_Str", "a [ b] "]
|
||||
raises(SyntaxError, lambda: chain('"'))
|
||||
raises(SyntaxError, lambda: chain('"\\"'))
|
||||
raises(SyntaxError, lambda: chain('"abc'))
|
||||
raises(SyntaxError, lambda: chain('"abc\\"def'))
|
||||
|
||||
# Invalid expressions:
|
||||
raises(SyntaxError, lambda: chain("(,"))
|
||||
raises(SyntaxError, lambda: chain("()"))
|
||||
raises(SyntaxError, lambda: chain("a (* b"))
|
||||
|
||||
|
||||
def test_parser_mathematica_exp_alt():
|
||||
parser = MathematicaParser()
|
||||
|
||||
convert_chain2 = lambda expr: parser._from_fullformlist_to_fullformsympy(parser._from_fullform_to_fullformlist(expr))
|
||||
convert_chain3 = lambda expr: parser._from_fullformsympy_to_sympy(convert_chain2(expr))
|
||||
|
||||
Sin, Times, Plus, Power = symbols("Sin Times Plus Power", cls=Function)
|
||||
|
||||
full_form1 = "Sin[Times[x, y]]"
|
||||
full_form2 = "Plus[Times[x, y], z]"
|
||||
full_form3 = "Sin[Times[x, Plus[y, z], Power[w, n]]]]"
|
||||
full_form4 = "Rational[Rational[x, y], z]"
|
||||
|
||||
assert parser._from_fullform_to_fullformlist(full_form1) == ["Sin", ["Times", "x", "y"]]
|
||||
assert parser._from_fullform_to_fullformlist(full_form2) == ["Plus", ["Times", "x", "y"], "z"]
|
||||
assert parser._from_fullform_to_fullformlist(full_form3) == ["Sin", ["Times", "x", ["Plus", "y", "z"], ["Power", "w", "n"]]]
|
||||
assert parser._from_fullform_to_fullformlist(full_form4) == ["Rational", ["Rational", "x", "y"], "z"]
|
||||
|
||||
assert convert_chain2(full_form1) == Sin(Times(x, y))
|
||||
assert convert_chain2(full_form2) == Plus(Times(x, y), z)
|
||||
assert convert_chain2(full_form3) == Sin(Times(x, Plus(y, z), Power(w, n)))
|
||||
|
||||
assert convert_chain3(full_form1) == sin(x*y)
|
||||
assert convert_chain3(full_form2) == x*y + z
|
||||
assert convert_chain3(full_form3) == sin(x*(y + z)*w**n)
|
||||
@@ -0,0 +1,50 @@
|
||||
from sympy.parsing.maxima import parse_maxima
|
||||
from sympy.core.numbers import (E, Rational, oo)
|
||||
from sympy.core.symbol import Symbol
|
||||
from sympy.functions.combinatorial.factorials import factorial
|
||||
from sympy.functions.elementary.complexes import Abs
|
||||
from sympy.functions.elementary.exponential import log
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin)
|
||||
from sympy.abc import x
|
||||
|
||||
n = Symbol('n', integer=True)
|
||||
|
||||
|
||||
def test_parser():
|
||||
assert Abs(parse_maxima('float(1/3)') - 0.333333333) < 10**(-5)
|
||||
assert parse_maxima('13^26') == 91733330193268616658399616009
|
||||
assert parse_maxima('sin(%pi/2) + cos(%pi/3)') == Rational(3, 2)
|
||||
assert parse_maxima('log(%e)') == 1
|
||||
|
||||
|
||||
def test_injection():
|
||||
parse_maxima('c: x+1', globals=globals())
|
||||
# c created by parse_maxima
|
||||
assert c == x + 1 # noqa:F821
|
||||
|
||||
parse_maxima('g: sqrt(81)', globals=globals())
|
||||
# g created by parse_maxima
|
||||
assert g == 9 # noqa:F821
|
||||
|
||||
|
||||
def test_maxima_functions():
|
||||
assert parse_maxima('expand( (x+1)^2)') == x**2 + 2*x + 1
|
||||
assert parse_maxima('factor( x**2 + 2*x + 1)') == (x + 1)**2
|
||||
assert parse_maxima('2*cos(x)^2 + sin(x)^2') == 2*cos(x)**2 + sin(x)**2
|
||||
assert parse_maxima('trigexpand(sin(2*x)+cos(2*x))') == \
|
||||
-1 + 2*cos(x)**2 + 2*cos(x)*sin(x)
|
||||
assert parse_maxima('solve(x^2-4,x)') == [-2, 2]
|
||||
assert parse_maxima('limit((1+1/x)^x,x,inf)') == E
|
||||
assert parse_maxima('limit(sqrt(-x)/x,x,0,minus)') is -oo
|
||||
assert parse_maxima('diff(x^x, x)') == x**x*(1 + log(x))
|
||||
assert parse_maxima('sum(k, k, 1, n)', name_dict={
|
||||
"n": Symbol('n', integer=True),
|
||||
"k": Symbol('k', integer=True)
|
||||
}) == (n**2 + n)/2
|
||||
assert parse_maxima('product(k, k, 1, n)', name_dict={
|
||||
"n": Symbol('n', integer=True),
|
||||
"k": Symbol('k', integer=True)
|
||||
}) == factorial(n)
|
||||
assert parse_maxima('ratsimp((x^2-1)/(x+1))') == x - 1
|
||||
assert Abs( parse_maxima(
|
||||
'float(sec(%pi/3) + csc(%pi/3))') - 3.154700538379252) < 10**(-5)
|
||||
@@ -0,0 +1,209 @@
|
||||
from sympy.parsing.sym_expr import SymPyExpression
|
||||
from sympy.testing.pytest import raises
|
||||
from sympy.external import import_module
|
||||
|
||||
lfortran = import_module('lfortran')
|
||||
cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']})
|
||||
|
||||
if lfortran and cin:
|
||||
from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String,
|
||||
Declaration, FloatType)
|
||||
from sympy.core import Integer, Float
|
||||
from sympy.core.symbol import Symbol
|
||||
|
||||
expr1 = SymPyExpression()
|
||||
src = """\
|
||||
integer :: a, b, c, d
|
||||
real :: p, q, r, s
|
||||
"""
|
||||
|
||||
def test_c_parse():
|
||||
src1 = """\
|
||||
int a, b = 4;
|
||||
float c, d = 2.4;
|
||||
"""
|
||||
expr1.convert_to_expr(src1, 'c')
|
||||
ls = expr1.return_expr()
|
||||
|
||||
assert ls[0] == Declaration(
|
||||
Variable(
|
||||
Symbol('a'),
|
||||
type=IntBaseType(String('intc'))
|
||||
)
|
||||
)
|
||||
assert ls[1] == Declaration(
|
||||
Variable(
|
||||
Symbol('b'),
|
||||
type=IntBaseType(String('intc')),
|
||||
value=Integer(4)
|
||||
)
|
||||
)
|
||||
assert ls[2] == Declaration(
|
||||
Variable(
|
||||
Symbol('c'),
|
||||
type=FloatType(
|
||||
String('float32'),
|
||||
nbits=Integer(32),
|
||||
nmant=Integer(23),
|
||||
nexp=Integer(8)
|
||||
)
|
||||
)
|
||||
)
|
||||
assert ls[3] == Declaration(
|
||||
Variable(
|
||||
Symbol('d'),
|
||||
type=FloatType(
|
||||
String('float32'),
|
||||
nbits=Integer(32),
|
||||
nmant=Integer(23),
|
||||
nexp=Integer(8)
|
||||
),
|
||||
value=Float('2.3999999999999999', precision=53)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_fortran_parse():
|
||||
expr = SymPyExpression(src, 'f')
|
||||
ls = expr.return_expr()
|
||||
|
||||
assert ls[0] == Declaration(
|
||||
Variable(
|
||||
Symbol('a'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[1] == Declaration(
|
||||
Variable(
|
||||
Symbol('b'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[2] == Declaration(
|
||||
Variable(
|
||||
Symbol('c'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[3] == Declaration(
|
||||
Variable(
|
||||
Symbol('d'),
|
||||
type=IntBaseType(String('integer')),
|
||||
value=Integer(0)
|
||||
)
|
||||
)
|
||||
assert ls[4] == Declaration(
|
||||
Variable(
|
||||
Symbol('p'),
|
||||
type=FloatBaseType(String('real')),
|
||||
value=Float('0.0', precision=53)
|
||||
)
|
||||
)
|
||||
assert ls[5] == Declaration(
|
||||
Variable(
|
||||
Symbol('q'),
|
||||
type=FloatBaseType(String('real')),
|
||||
value=Float('0.0', precision=53)
|
||||
)
|
||||
)
|
||||
assert ls[6] == Declaration(
|
||||
Variable(
|
||||
Symbol('r'),
|
||||
type=FloatBaseType(String('real')),
|
||||
value=Float('0.0', precision=53)
|
||||
)
|
||||
)
|
||||
assert ls[7] == Declaration(
|
||||
Variable(
|
||||
Symbol('s'),
|
||||
type=FloatBaseType(String('real')),
|
||||
value=Float('0.0', precision=53)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_convert_py():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
a = b + c
|
||||
s = p * q / r
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
exp_py = expr1.convert_to_python()
|
||||
assert exp_py == [
|
||||
'a = 0',
|
||||
'b = 0',
|
||||
'c = 0',
|
||||
'd = 0',
|
||||
'p = 0.0',
|
||||
'q = 0.0',
|
||||
'r = 0.0',
|
||||
's = 0.0',
|
||||
'a = b + c',
|
||||
's = p*q/r'
|
||||
]
|
||||
|
||||
|
||||
def test_convert_fort():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
a = b + c
|
||||
s = p * q / r
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
exp_fort = expr1.convert_to_fortran()
|
||||
assert exp_fort == [
|
||||
' integer*4 a',
|
||||
' integer*4 b',
|
||||
' integer*4 c',
|
||||
' integer*4 d',
|
||||
' real*8 p',
|
||||
' real*8 q',
|
||||
' real*8 r',
|
||||
' real*8 s',
|
||||
' a = b + c',
|
||||
' s = p*q/r'
|
||||
]
|
||||
|
||||
|
||||
def test_convert_c():
|
||||
src1 = (
|
||||
src +
|
||||
"""\
|
||||
a = b + c
|
||||
s = p * q / r
|
||||
"""
|
||||
)
|
||||
expr1.convert_to_expr(src1, 'f')
|
||||
exp_c = expr1.convert_to_c()
|
||||
assert exp_c == [
|
||||
'int a = 0',
|
||||
'int b = 0',
|
||||
'int c = 0',
|
||||
'int d = 0',
|
||||
'double p = 0.0',
|
||||
'double q = 0.0',
|
||||
'double r = 0.0',
|
||||
'double s = 0.0',
|
||||
'a = b + c;',
|
||||
's = p*q/r;'
|
||||
]
|
||||
|
||||
|
||||
def test_exceptions():
|
||||
src = 'int a;'
|
||||
raises(ValueError, lambda: SymPyExpression(src))
|
||||
raises(ValueError, lambda: SymPyExpression(mode = 'c'))
|
||||
raises(NotImplementedError, lambda: SymPyExpression(src, mode = 'd'))
|
||||
|
||||
elif not lfortran and not cin:
|
||||
def test_raise():
|
||||
raises(ImportError, lambda: SymPyExpression('int a;', 'c'))
|
||||
raises(ImportError, lambda: SymPyExpression('integer :: a', 'f'))
|
||||
@@ -0,0 +1,371 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import builtins
|
||||
import types
|
||||
|
||||
from sympy.assumptions import Q
|
||||
from sympy.core import Symbol, Function, Float, Rational, Integer, I, Mul, Pow, Eq, Lt, Le, Gt, Ge, Ne
|
||||
from sympy.functions import exp, factorial, factorial2, sin, Min, Max
|
||||
from sympy.logic import And
|
||||
from sympy.series import Limit
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.parsing.sympy_parser import (
|
||||
parse_expr, standard_transformations, rationalize, TokenError,
|
||||
split_symbols, implicit_multiplication, convert_equals_signs,
|
||||
convert_xor, function_exponentiation, lambda_notation, auto_symbol,
|
||||
repeated_decimals, implicit_multiplication_application,
|
||||
auto_number, factorial_notation, implicit_application,
|
||||
_transformation, T
|
||||
)
|
||||
|
||||
|
||||
def test_sympy_parser():
|
||||
x = Symbol('x')
|
||||
inputs = {
|
||||
'2*x': 2 * x,
|
||||
'3.00': Float(3),
|
||||
'22/7': Rational(22, 7),
|
||||
'2+3j': 2 + 3*I,
|
||||
'exp(x)': exp(x),
|
||||
'x!': factorial(x),
|
||||
'x!!': factorial2(x),
|
||||
'(x + 1)! - 1': factorial(x + 1) - 1,
|
||||
'3.[3]': Rational(10, 3),
|
||||
'.0[3]': Rational(1, 30),
|
||||
'3.2[3]': Rational(97, 30),
|
||||
'1.3[12]': Rational(433, 330),
|
||||
'1 + 3.[3]': Rational(13, 3),
|
||||
'1 + .0[3]': Rational(31, 30),
|
||||
'1 + 3.2[3]': Rational(127, 30),
|
||||
'.[0011]': Rational(1, 909),
|
||||
'0.1[00102] + 1': Rational(366697, 333330),
|
||||
'1.[0191]': Rational(10190, 9999),
|
||||
'10!': 3628800,
|
||||
'-(2)': -Integer(2),
|
||||
'[-1, -2, 3]': [Integer(-1), Integer(-2), Integer(3)],
|
||||
'Symbol("x").free_symbols': x.free_symbols,
|
||||
"S('S(3).n(n=3)')": Float(3, 3),
|
||||
'factorint(12, visual=True)': Mul(
|
||||
Pow(2, 2, evaluate=False),
|
||||
Pow(3, 1, evaluate=False),
|
||||
evaluate=False),
|
||||
'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir='-'),
|
||||
'Q.even(x)': Q.even(x),
|
||||
|
||||
|
||||
}
|
||||
for text, result in inputs.items():
|
||||
assert parse_expr(text) == result
|
||||
|
||||
raises(TypeError, lambda:
|
||||
parse_expr('x', standard_transformations))
|
||||
raises(TypeError, lambda:
|
||||
parse_expr('x', transformations=lambda x,y: 1))
|
||||
raises(TypeError, lambda:
|
||||
parse_expr('x', transformations=(lambda x,y: 1,)))
|
||||
raises(TypeError, lambda: parse_expr('x', transformations=((),)))
|
||||
raises(TypeError, lambda: parse_expr('x', {}, [], []))
|
||||
raises(TypeError, lambda: parse_expr('x', [], [], {}))
|
||||
raises(TypeError, lambda: parse_expr('x', [], [], {}))
|
||||
|
||||
|
||||
def test_rationalize():
|
||||
inputs = {
|
||||
'0.123': Rational(123, 1000)
|
||||
}
|
||||
transformations = standard_transformations + (rationalize,)
|
||||
for text, result in inputs.items():
|
||||
assert parse_expr(text, transformations=transformations) == result
|
||||
|
||||
|
||||
def test_factorial_fail():
|
||||
inputs = ['x!!!', 'x!!!!', '(!)']
|
||||
|
||||
|
||||
for text in inputs:
|
||||
try:
|
||||
parse_expr(text)
|
||||
assert False
|
||||
except TokenError:
|
||||
assert True
|
||||
|
||||
|
||||
def test_repeated_fail():
|
||||
inputs = ['1[1]', '.1e1[1]', '0x1[1]', '1.1j[1]', '1.1[1 + 1]',
|
||||
'0.1[[1]]', '0x1.1[1]']
|
||||
|
||||
|
||||
# All are valid Python, so only raise TypeError for invalid indexing
|
||||
for text in inputs:
|
||||
raises(TypeError, lambda: parse_expr(text))
|
||||
|
||||
|
||||
inputs = ['0.1[', '0.1[1', '0.1[]']
|
||||
for text in inputs:
|
||||
raises((TokenError, SyntaxError), lambda: parse_expr(text))
|
||||
|
||||
|
||||
def test_repeated_dot_only():
|
||||
assert parse_expr('.[1]') == Rational(1, 9)
|
||||
assert parse_expr('1 + .[1]') == Rational(10, 9)
|
||||
|
||||
|
||||
def test_local_dict():
|
||||
local_dict = {
|
||||
'my_function': lambda x: x + 2
|
||||
}
|
||||
inputs = {
|
||||
'my_function(2)': Integer(4)
|
||||
}
|
||||
for text, result in inputs.items():
|
||||
assert parse_expr(text, local_dict=local_dict) == result
|
||||
|
||||
|
||||
def test_local_dict_split_implmult():
|
||||
t = standard_transformations + (split_symbols, implicit_multiplication,)
|
||||
w = Symbol('w', real=True)
|
||||
y = Symbol('y')
|
||||
assert parse_expr('yx', local_dict={'x':w}, transformations=t) == y*w
|
||||
|
||||
|
||||
def test_local_dict_symbol_to_fcn():
|
||||
x = Symbol('x')
|
||||
d = {'foo': Function('bar')}
|
||||
assert parse_expr('foo(x)', local_dict=d) == d['foo'](x)
|
||||
d = {'foo': Symbol('baz')}
|
||||
raises(TypeError, lambda: parse_expr('foo(x)', local_dict=d))
|
||||
|
||||
|
||||
def test_global_dict():
|
||||
global_dict = {
|
||||
'Symbol': Symbol
|
||||
}
|
||||
inputs = {
|
||||
'Q & S': And(Symbol('Q'), Symbol('S'))
|
||||
}
|
||||
for text, result in inputs.items():
|
||||
assert parse_expr(text, global_dict=global_dict) == result
|
||||
|
||||
|
||||
def test_no_globals():
|
||||
|
||||
# Replicate creating the default global_dict:
|
||||
default_globals = {}
|
||||
exec('from sympy import *', default_globals)
|
||||
builtins_dict = vars(builtins)
|
||||
for name, obj in builtins_dict.items():
|
||||
if isinstance(obj, types.BuiltinFunctionType):
|
||||
default_globals[name] = obj
|
||||
default_globals['max'] = Max
|
||||
default_globals['min'] = Min
|
||||
|
||||
# Need to include Symbol or parse_expr will not work:
|
||||
default_globals.pop('Symbol')
|
||||
global_dict = {'Symbol':Symbol}
|
||||
|
||||
for name in default_globals:
|
||||
obj = parse_expr(name, global_dict=global_dict)
|
||||
assert obj == Symbol(name)
|
||||
|
||||
|
||||
def test_issue_2515():
|
||||
raises(TokenError, lambda: parse_expr('(()'))
|
||||
raises(TokenError, lambda: parse_expr('"""'))
|
||||
|
||||
|
||||
def test_issue_7663():
|
||||
x = Symbol('x')
|
||||
e = '2*(x+1)'
|
||||
assert parse_expr(e, evaluate=False) == parse_expr(e, evaluate=False)
|
||||
assert parse_expr(e, evaluate=False).equals(2*(x+1))
|
||||
|
||||
def test_recursive_evaluate_false_10560():
|
||||
inputs = {
|
||||
'4*-3' : '4*-3',
|
||||
'-4*3' : '(-4)*3',
|
||||
"-2*x*y": '(-2)*x*y',
|
||||
"x*-4*x": "x*(-4)*x"
|
||||
}
|
||||
for text, result in inputs.items():
|
||||
assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False)
|
||||
|
||||
|
||||
def test_function_evaluate_false():
|
||||
inputs = [
|
||||
'Abs(0)', 'im(0)', 're(0)', 'sign(0)', 'arg(0)', 'conjugate(0)',
|
||||
'acos(0)', 'acot(0)', 'acsc(0)', 'asec(0)', 'asin(0)', 'atan(0)',
|
||||
'acosh(0)', 'acoth(0)', 'acsch(0)', 'asech(0)', 'asinh(0)', 'atanh(0)',
|
||||
'cos(0)', 'cot(0)', 'csc(0)', 'sec(0)', 'sin(0)', 'tan(0)',
|
||||
'cosh(0)', 'coth(0)', 'csch(0)', 'sech(0)', 'sinh(0)', 'tanh(0)',
|
||||
'exp(0)', 'log(0)', 'sqrt(0)',
|
||||
]
|
||||
for case in inputs:
|
||||
expr = parse_expr(case, evaluate=False)
|
||||
assert case == str(expr) != str(expr.doit())
|
||||
assert str(parse_expr('ln(0)', evaluate=False)) == 'log(0)'
|
||||
assert str(parse_expr('cbrt(0)', evaluate=False)) == '0**(1/3)'
|
||||
|
||||
|
||||
def test_issue_10773():
|
||||
inputs = {
|
||||
'-10/5': '(-10)/5',
|
||||
'-10/-5' : '(-10)/(-5)',
|
||||
}
|
||||
for text, result in inputs.items():
|
||||
assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False)
|
||||
|
||||
|
||||
def test_split_symbols():
|
||||
transformations = standard_transformations + \
|
||||
(split_symbols, implicit_multiplication,)
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
xy = Symbol('xy')
|
||||
|
||||
|
||||
assert parse_expr("xy") == xy
|
||||
assert parse_expr("xy", transformations=transformations) == x*y
|
||||
|
||||
|
||||
def test_split_symbols_function():
|
||||
transformations = standard_transformations + \
|
||||
(split_symbols, implicit_multiplication,)
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
a = Symbol('a')
|
||||
f = Function('f')
|
||||
|
||||
|
||||
assert parse_expr("ay(x+1)", transformations=transformations) == a*y*(x+1)
|
||||
assert parse_expr("af(x+1)", transformations=transformations,
|
||||
local_dict={'f':f}) == a*f(x+1)
|
||||
|
||||
|
||||
def test_functional_exponent():
|
||||
t = standard_transformations + (convert_xor, function_exponentiation)
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
a = Symbol('a')
|
||||
yfcn = Function('y')
|
||||
assert parse_expr("sin^2(x)", transformations=t) == (sin(x))**2
|
||||
assert parse_expr("sin^y(x)", transformations=t) == (sin(x))**y
|
||||
assert parse_expr("exp^y(x)", transformations=t) == (exp(x))**y
|
||||
assert parse_expr("E^y(x)", transformations=t) == exp(yfcn(x))
|
||||
assert parse_expr("a^y(x)", transformations=t) == a**(yfcn(x))
|
||||
|
||||
|
||||
def test_match_parentheses_implicit_multiplication():
|
||||
transformations = standard_transformations + \
|
||||
(implicit_multiplication,)
|
||||
raises(TokenError, lambda: parse_expr('(1,2),(3,4]',transformations=transformations))
|
||||
|
||||
|
||||
def test_convert_equals_signs():
|
||||
transformations = standard_transformations + \
|
||||
(convert_equals_signs, )
|
||||
x = Symbol('x')
|
||||
y = Symbol('y')
|
||||
assert parse_expr("1*2=x", transformations=transformations) == Eq(2, x)
|
||||
assert parse_expr("y = x", transformations=transformations) == Eq(y, x)
|
||||
assert parse_expr("(2*y = x) = False",
|
||||
transformations=transformations) == Eq(Eq(2*y, x), False)
|
||||
|
||||
|
||||
def test_parse_function_issue_3539():
|
||||
x = Symbol('x')
|
||||
f = Function('f')
|
||||
assert parse_expr('f(x)') == f(x)
|
||||
|
||||
def test_issue_24288():
|
||||
assert parse_expr("1 < 2", evaluate=False) == Lt(1, 2, evaluate=False)
|
||||
assert parse_expr("1 <= 2", evaluate=False) == Le(1, 2, evaluate=False)
|
||||
assert parse_expr("1 > 2", evaluate=False) == Gt(1, 2, evaluate=False)
|
||||
assert parse_expr("1 >= 2", evaluate=False) == Ge(1, 2, evaluate=False)
|
||||
assert parse_expr("1 != 2", evaluate=False) == Ne(1, 2, evaluate=False)
|
||||
assert parse_expr("1 == 2", evaluate=False) == Eq(1, 2, evaluate=False)
|
||||
assert parse_expr("1 < 2 < 3", evaluate=False) == And(Lt(1, 2, evaluate=False), Lt(2, 3, evaluate=False), evaluate=False)
|
||||
assert parse_expr("1 <= 2 <= 3", evaluate=False) == And(Le(1, 2, evaluate=False), Le(2, 3, evaluate=False), evaluate=False)
|
||||
assert parse_expr("1 < 2 <= 3 < 4", evaluate=False) == \
|
||||
And(Lt(1, 2, evaluate=False), Le(2, 3, evaluate=False), Lt(3, 4, evaluate=False), evaluate=False)
|
||||
# Valid Python relational operators that SymPy does not decide how to handle them yet
|
||||
raises(ValueError, lambda: parse_expr("1 in 2", evaluate=False))
|
||||
raises(ValueError, lambda: parse_expr("1 is 2", evaluate=False))
|
||||
raises(ValueError, lambda: parse_expr("1 not in 2", evaluate=False))
|
||||
raises(ValueError, lambda: parse_expr("1 is not 2", evaluate=False))
|
||||
|
||||
def test_split_symbols_numeric():
|
||||
transformations = (
|
||||
standard_transformations +
|
||||
(implicit_multiplication_application,))
|
||||
|
||||
n = Symbol('n')
|
||||
expr1 = parse_expr('2**n * 3**n')
|
||||
expr2 = parse_expr('2**n3**n', transformations=transformations)
|
||||
assert expr1 == expr2 == 2**n*3**n
|
||||
|
||||
expr1 = parse_expr('n12n34', transformations=transformations)
|
||||
assert expr1 == n*12*n*34
|
||||
|
||||
|
||||
def test_unicode_names():
|
||||
assert parse_expr('α') == Symbol('α')
|
||||
|
||||
|
||||
def test_python3_features():
|
||||
assert parse_expr("123_456") == 123456
|
||||
assert parse_expr("1.2[3_4]") == parse_expr("1.2[34]") == Rational(611, 495)
|
||||
assert parse_expr("1.2[012_012]") == parse_expr("1.2[012012]") == Rational(400, 333)
|
||||
assert parse_expr('.[3_4]') == parse_expr('.[34]') == Rational(34, 99)
|
||||
assert parse_expr('.1[3_4]') == parse_expr('.1[34]') == Rational(133, 990)
|
||||
assert parse_expr('123_123.123_123[3_4]') == parse_expr('123123.123123[34]') == Rational(12189189189211, 99000000)
|
||||
|
||||
|
||||
def test_issue_19501():
|
||||
x = Symbol('x')
|
||||
eq = parse_expr('E**x(1+x)', local_dict={'x': x}, transformations=(
|
||||
standard_transformations +
|
||||
(implicit_multiplication_application,)))
|
||||
assert eq.free_symbols == {x}
|
||||
|
||||
|
||||
def test_parsing_definitions():
|
||||
from sympy.abc import x
|
||||
assert len(_transformation) == 12 # if this changes, extend below
|
||||
assert _transformation[0] == lambda_notation
|
||||
assert _transformation[1] == auto_symbol
|
||||
assert _transformation[2] == repeated_decimals
|
||||
assert _transformation[3] == auto_number
|
||||
assert _transformation[4] == factorial_notation
|
||||
assert _transformation[5] == implicit_multiplication_application
|
||||
assert _transformation[6] == convert_xor
|
||||
assert _transformation[7] == implicit_application
|
||||
assert _transformation[8] == implicit_multiplication
|
||||
assert _transformation[9] == convert_equals_signs
|
||||
assert _transformation[10] == function_exponentiation
|
||||
assert _transformation[11] == rationalize
|
||||
assert T[:5] == T[0,1,2,3,4] == standard_transformations
|
||||
t = _transformation
|
||||
assert T[-1, 0] == (t[len(t) - 1], t[0])
|
||||
assert T[:5, 8] == standard_transformations + (t[8],)
|
||||
assert parse_expr('0.3x^2', transformations='all') == 3*x**2/10
|
||||
assert parse_expr('sin 3x', transformations='implicit') == sin(3*x)
|
||||
|
||||
|
||||
def test_builtins():
|
||||
cases = [
|
||||
('abs(x)', 'Abs(x)'),
|
||||
('max(x, y)', 'Max(x, y)'),
|
||||
('min(x, y)', 'Min(x, y)'),
|
||||
('pow(x, y)', 'Pow(x, y)'),
|
||||
]
|
||||
for built_in_func_call, sympy_func_call in cases:
|
||||
assert parse_expr(built_in_func_call) == parse_expr(sympy_func_call)
|
||||
assert str(parse_expr('pow(38, -1, 97)')) == '23'
|
||||
|
||||
|
||||
def test_issue_22822():
|
||||
raises(ValueError, lambda: parse_expr('x', {'': 1}))
|
||||
data = {'some_parameter': None}
|
||||
assert parse_expr('some_parameter is None', data) is True
|
||||
Reference in New Issue
Block a user