node.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. # vim: set fileencoding=utf-8 :
  2. import os.path
  3. import sys
  4. import copy
  5. import re
  6. sys.path.insert(0, os.path.realpath('external'))
  7. from graph_drawing.graph import generate_graph
  8. from graph_drawing.line import generate_line
  9. from graph_drawing.node import Node, Leaf
  10. TYPE_OPERATOR = 1
  11. TYPE_IDENTIFIER = 2
  12. TYPE_INTEGER = 4
  13. TYPE_FLOAT = 8
  14. # Unary
  15. OP_NEG = 1
  16. OP_ABS = 2
  17. # Binary
  18. OP_ADD = 3
  19. OP_SUB = 4
  20. OP_MUL = 5
  21. OP_DIV = 6
  22. OP_POW = 7
  23. OP_SUBSCRIPT = 8
  24. OP_AND = 9
  25. OP_OR = 10
  26. # N-ary (functions)
  27. OP_INT = 11
  28. OP_INT_INDEF = 12
  29. OP_COMMA = 13
  30. OP_SQRT = 14
  31. OP_DER = 15
  32. OP_LOG = 16
  33. # Goniometry
  34. OP_SIN = 17
  35. OP_COS = 18
  36. OP_TAN = 19
  37. OP_SOLVE = 20
  38. OP_EQ = 21
  39. OP_POSSIBILITIES = 22
  40. OP_HINT = 23
  41. OP_REWRITE_ALL = 24
  42. OP_REWRITE = 25
  43. # Special identifiers
  44. PI = 'pi'
  45. E = 'e'
  46. INFINITY = 'oo'
  47. SPECIAL_TOKENS = [PI, E, INFINITY]
  48. # Default base to use in parsing 'log(...)'
  49. DEFAULT_LOGARITHM_BASE = 10
  50. TYPE_MAP = {
  51. int: TYPE_INTEGER,
  52. float: TYPE_FLOAT,
  53. str: TYPE_IDENTIFIER,
  54. }
  55. OP_MAP = {
  56. ',': OP_COMMA,
  57. '+': OP_ADD,
  58. '-': OP_SUB,
  59. '*': OP_MUL,
  60. '/': OP_DIV,
  61. '^': OP_POW,
  62. '_': OP_SUBSCRIPT,
  63. '^^': OP_AND,
  64. 'vv': OP_OR,
  65. 'sin': OP_SIN,
  66. 'cos': OP_COS,
  67. 'tan': OP_TAN,
  68. 'sqrt': OP_SQRT,
  69. 'int': OP_INT,
  70. 'der': OP_DER,
  71. 'solve': OP_SOLVE,
  72. 'log': OP_LOG,
  73. '=': OP_EQ,
  74. '??': OP_POSSIBILITIES,
  75. '?': OP_HINT,
  76. '@@': OP_REWRITE_ALL,
  77. '@': OP_REWRITE,
  78. }
  79. OP_VALUE_MAP = dict([(v, k) for k, v in OP_MAP.iteritems()])
  80. OP_MAP['ln'] = OP_LOG
  81. OP_VALUE_MAP[OP_INT_INDEF] = 'indef'
  82. OP_VALUE_MAP[OP_ABS] = 'abs'
  83. TOKEN_MAP = {
  84. OP_COMMA: 'COMMA',
  85. OP_ADD: 'PLUS',
  86. OP_SUB: 'MINUS',
  87. OP_MUL: 'TIMES',
  88. OP_DIV: 'DIVIDE',
  89. OP_POW: 'POW',
  90. OP_SUBSCRIPT: 'SUB',
  91. OP_AND: 'AND',
  92. OP_OR: 'OR',
  93. OP_SQRT: 'FUNCTION',
  94. OP_SIN: 'FUNCTION',
  95. OP_COS: 'FUNCTION',
  96. OP_TAN: 'FUNCTION',
  97. OP_INT: 'INTEGRAL',
  98. OP_DER: 'FUNCTION',
  99. OP_SOLVE: 'FUNCTION',
  100. OP_LOG: 'FUNCTION',
  101. OP_EQ: 'EQ',
  102. OP_POSSIBILITIES: 'POSSIBILITIES',
  103. OP_HINT: 'HINT',
  104. OP_REWRITE_ALL: 'REWRITE_ALL',
  105. OP_REWRITE: 'REWRITE',
  106. }
  107. def to_expression(obj):
  108. return obj if isinstance(obj, ExpressionBase) else ExpressionLeaf(obj)
  109. class ExpressionBase(object):
  110. def __init__(self, *args, **kwargs):
  111. self.negated = 0
  112. def clone(self):
  113. return copy.deepcopy(self)
  114. def __lt__(self, other):
  115. """
  116. Comparison between this expression{node,leaf} and another
  117. expression{node,leaf}. This comparison will return True if this
  118. instance has less value than the other expression{node,leaf}.
  119. Otherwise, False is returned.
  120. The comparison is based on the following conditions:
  121. 1. Both are leafs. String comparison of the value is used.
  122. 2. This is a leaf and other is a node. This leaf has less value, thus
  123. True is returned.
  124. 3. This is a node and other is a leaf. This leaf has more value, thus
  125. False is returned.
  126. 4. Both are nodes. Compare the polynome properties of the nodes. True
  127. is returned if this node's root property is less than other's root
  128. property, or this node's exponent property is less than other's
  129. exponent property, or this node's coefficient property is less than
  130. other's coefficient property. Otherwise, False is returned.
  131. """
  132. if self.is_leaf:
  133. if other.is_leaf:
  134. # Both are leafs, string compare the value.
  135. self_value = '-' * (self.negated & 1) + str(self.value)
  136. other_value = '-' * (other.negated & 1) + str(other.value)
  137. return self_value < other_value
  138. # Self is a leaf, thus has less value than an expression node.
  139. return True
  140. if other.is_leaf:
  141. # Self is an expression node, and the other is a leaf. Thus, other
  142. # is greater than self.
  143. return False
  144. # Both are nodes, compare the polynome properties.
  145. s_coeff, s_root, s_exp = self.extract_polynome_properties()
  146. o_coeff, o_root, o_exp = other.extract_polynome_properties()
  147. return s_root < o_root or s_exp < o_exp or s_coeff < o_coeff
  148. def __ne__(self, other):
  149. """
  150. Check strict inequivalence, using the strict equivalence operator.
  151. """
  152. return not (self == other)
  153. def is_op(self, *ops):
  154. return not self.is_leaf and self.op in ops
  155. def is_power(self, exponent=None):
  156. if self.is_leaf or self.op != OP_POW:
  157. return False
  158. return exponent == None or self[1] == exponent
  159. def is_nary(self):
  160. return not self.is_leaf and self.op in [OP_ADD, OP_SUB, OP_MUL]
  161. def is_identifier(self, identifier=None):
  162. return self.type == TYPE_IDENTIFIER \
  163. and (identifier == None or self.value == identifier)
  164. def is_variable(self):
  165. return self.type == TYPE_IDENTIFIER and self.value not in (PI, E)
  166. def is_int(self):
  167. return self.type == TYPE_INTEGER
  168. def is_float(self):
  169. return self.type == TYPE_FLOAT
  170. def is_numeric(self):
  171. return self.type & (TYPE_FLOAT | TYPE_INTEGER)
  172. def __add__(self, other):
  173. return ExpressionNode(OP_ADD, self, to_expression(other))
  174. def __sub__(self, other):
  175. return ExpressionNode(OP_ADD, self, -to_expression(other))
  176. #FIXME: return ExpressionNode(OP_SUB, self, to_expression(other))
  177. def __mul__(self, other):
  178. return ExpressionNode(OP_MUL, self, to_expression(other))
  179. def __div__(self, other):
  180. return ExpressionNode(OP_DIV, self, to_expression(other))
  181. def __pow__(self, other):
  182. return ExpressionNode(OP_POW, self, to_expression(other))
  183. def __pos__(self):
  184. return self.reduce_negation()
  185. def __and__(self, other):
  186. return ExpressionNode(OP_AND, self, to_expression(other))
  187. def __or__(self, other):
  188. return ExpressionNode(OP_OR, self, to_expression(other))
  189. def reduce_negation(self, n=1):
  190. """Remove n negation flags from the node."""
  191. assert self.negated
  192. return self.negate(-n)
  193. def negate(self, n=1):
  194. """Negate the node n times."""
  195. return negate(self, self.negated + n)
  196. def contains(self, node, include_self=True):
  197. """
  198. Check if a node equal to the specified one exists within this node.
  199. """
  200. if include_self and negate(self, 0) == node:
  201. return True
  202. if not self.is_leaf:
  203. for child in self:
  204. if child.contains(node, include_self=True):
  205. return True
  206. return False
  207. class ExpressionNode(Node, ExpressionBase):
  208. def __init__(self, *args, **kwargs):
  209. super(ExpressionNode, self).__init__(*args, **kwargs)
  210. self.type = TYPE_OPERATOR
  211. op = args[0]
  212. if isinstance(op, str):
  213. self.value = op
  214. self.op = OP_MAP[op]
  215. else:
  216. self.value = OP_VALUE_MAP[op]
  217. self.op = op
  218. def construct_function(self, children):
  219. if self.op == OP_DER:
  220. f = children[0]
  221. if len(children) < 2:
  222. # der(der(x ^ 2)) -> [x ^ 2]''
  223. if self[0].is_op(OP_DER) and len(self[0]) < 2:
  224. return f + '\''
  225. # der(x ^ 2) -> [x ^ 2]'
  226. return '[' + f + ']\''
  227. # der(x ^ 2, x) -> d/dx (x ^ 2)
  228. return 'd/d%s (%s)' % (children[1], f)
  229. if self.op == OP_LOG:
  230. if self[0].is_op(OP_ABS):
  231. content = children[0]
  232. else:
  233. content = '(' + children[0] + ')'
  234. # log(a, e) -> ln(a)
  235. if self[1].is_identifier(E):
  236. return 'ln%s' % content
  237. # log(a, 10) -> log(a)
  238. if self[1] == 10:
  239. return 'log%s' % content
  240. # log(a, 2) -> log_2(a)
  241. if children[1].isdigit():
  242. return 'log_%s%s' % (children[1], content)
  243. if self.op == OP_INT:
  244. # Make sure that any needed parentheses around f(x) are generated,
  245. # and append ' dx' to it (result 'f(x) dx')
  246. fx, x = self[:2]
  247. operand = re.sub(r'(\s*\*)?\s*d$', ' d' + x.value, str(fx * 'd'))
  248. op = 'int'
  249. # Add bounds
  250. if len(self) > 2:
  251. lbnd, ubnd = self[2:]
  252. lbnd = str(ExpressionNode(OP_SUBSCRIPT, lbnd))
  253. ubnd = str(ExpressionNode(OP_POW, ubnd))
  254. op += lbnd + ubnd
  255. # int x ^ 2 -> int x ^ 2 dx
  256. # int x + 1 -> int (x + 1) dx
  257. # int_a^b x ^ 2 -> int_a^b x ^ 2 dx
  258. return op + ' ' + operand
  259. if self.op == OP_INT_INDEF:
  260. # [x ^ 2]_a^b
  261. F, lbnd, ubnd = self
  262. lbnd = str(ExpressionNode(OP_SUBSCRIPT, lbnd))
  263. ubnd = str(ExpressionNode(OP_POW, ubnd))
  264. return '[%s]%s%s' % (F, lbnd, ubnd)
  265. if self.op == OP_ABS:
  266. return '|%s|' % children[0]
  267. # Function with absolute value as only parameter does not need
  268. # parentheses
  269. if self.op in TOKEN_MAP and TOKEN_MAP[self.op] == 'FUNCTION' \
  270. and len(self) == 1 and self[0].is_op(OP_ABS):
  271. return self.title() + children[0]
  272. def __str__(self): # pragma: nocover
  273. return generate_line(self)
  274. def __eq__(self, other):
  275. """
  276. Check strict equivalence.
  277. """
  278. return isinstance(other, ExpressionNode) and self.op == other.op \
  279. and self.negated == other.negated and self.nodes == other.nodes
  280. def substitute(self, old_child, new_child):
  281. self.nodes[self.nodes.index(old_child)] = new_child
  282. def graph(self): # pragma: nocover
  283. return generate_graph(negation_to_node(self))
  284. def extract_polynome_properties(self):
  285. """
  286. Extract polynome properties into tuple format: (coefficient, root,
  287. exponent). Thus: c * r ^ e will be extracted into the tuple (c, r, e).
  288. This function will normalize the expression before extracting the
  289. properties. Therefore, the expression r ^ e * c results the same tuple
  290. (c, r, e) as the expression c * r ^ e.
  291. >>> from src.node import ExpressionNode as N, ExpressionLeaf as L
  292. >>> c, r, e = L('c'), L('r'), L('e')
  293. >>> n1 = N(OP_MUL), c, N('^', r, e))
  294. >>> n1.extract_polynome()
  295. (c, r, e)
  296. >>> n2 = N(OP_MUL, N('^', r, e), c)
  297. >>> n2.extract_polynome()
  298. (c, r, e)
  299. >>> n3 = -r
  300. >>> n3.extract_polynome()
  301. (1, -r, 1)
  302. """
  303. # TODO: change "get_polynome" -> "extract_polynome".
  304. # TODO: change retval of c * r ^ e to (c, r, e).
  305. # was: (root, exponent, coefficient, literal_exponent)
  306. # rule: r ^ e -> (1, r, e)
  307. if self.is_power():
  308. return (ExpressionLeaf(1), self[0], self[1])
  309. # rule: -r -> (1, r, 1)
  310. # rule: --r -> (1, r, 1)
  311. # rule: ---r -> (1, r, 1)
  312. if self.negated:
  313. return (ExpressionLeaf(1), self, ExpressionLeaf(1))
  314. if self.op != OP_MUL:
  315. return
  316. # rule: 3 * 7 ^ e | 'a' * 'b' ^ e
  317. # expression: c * r ^ e ; tree:
  318. #
  319. # *
  320. # ╭┴───╮
  321. # c ^
  322. # ╭─┴╮
  323. # r e
  324. #
  325. # rule: c * r ^ e | (r ^ e) * c
  326. for i, j in ((0, 1), (1, 0)):
  327. if self[j].is_power():
  328. return (self[i], self[j][0], self[j][1])
  329. # Normalize c * r and r * c -> c * r. Otherwise, the tuple will not
  330. # match if the order of the expression is different. Example:
  331. # r ^ e * c == c * r ^ e
  332. # without normalization, those expressions will not match.
  333. #
  334. # rule: c * r | r * c
  335. if self[0] < self[1]:
  336. return (self[0], self[1], ExpressionLeaf(1))
  337. return (self[1], self[0], ExpressionLeaf(1))
  338. def equals(self, other, ignore_negation=False):
  339. """
  340. Perform a non-strict equivalence check between two nodes:
  341. - If the other node is a leaf, it cannot be equal to this node.
  342. - If their operators differ, the nodes are not equal.
  343. - If both nodes are additions or both are multiplications, match each
  344. node in one scope to one in the other (an injective relationship).
  345. Any difference in order of the scopes is irrelevant.
  346. - If both nodes are divisions, the nominator and denominator have to be
  347. non-strictly equal.
  348. """
  349. if not isinstance(other, ExpressionNode) or other.op != self.op:
  350. return False
  351. if self.op in (OP_ADD, OP_MUL):
  352. s0 = Scope(self)
  353. s1 = set(Scope(other))
  354. # Scopes should be of equal size
  355. if len(s0) != len(s1):
  356. return False
  357. # Each node in one scope should have an image node in the other
  358. matched = set()
  359. for n0 in s0:
  360. found = False
  361. for n1 in s1 - matched:
  362. if n0.equals(n1):
  363. found = True
  364. matched.add(n1)
  365. break
  366. if not found:
  367. return False
  368. else:
  369. # Check if all children are non-strictly equal, preserving order
  370. for i, child in enumerate(self):
  371. if not child.equals(other[i]):
  372. return False
  373. if ignore_negation:
  374. return True
  375. return self.negated == other.negated
  376. class ExpressionLeaf(Leaf, ExpressionBase):
  377. def __init__(self, *args, **kwargs):
  378. super(ExpressionLeaf, self).__init__(*args, **kwargs)
  379. self.type = TYPE_MAP[type(args[0])]
  380. def __eq__(self, other):
  381. """
  382. Check strict equivalence.
  383. """
  384. other_type = type(other)
  385. if other_type in TYPE_MAP:
  386. return self.type == TYPE_MAP[other_type] \
  387. and self.actual_value() == other
  388. return self.negated == other.negated and self.type == other.type \
  389. and self.value == other.value
  390. def __repr__(self):
  391. return str(self)
  392. def equals(self, other, ignore_negation=False):
  393. """
  394. Check non-strict equivalence.
  395. Between leaves, this is the same as strict equivalence, except when
  396. negations must be ignored.
  397. """
  398. if ignore_negation:
  399. other_type = type(other)
  400. if other_type in (int, float):
  401. return TYPE_MAP[other_type] == self.type \
  402. and self.value == abs(other)
  403. elif other_type == str:
  404. return self.type == TYPE_IDENTIFIER and self.value == other
  405. return self.type == other.type and self.value == other.value
  406. else:
  407. return self == other
  408. def extract_polynome_properties(self):
  409. """
  410. An expression leaf will return the polynome tuple (1, r, 1), where r is
  411. the leaf itself. See also the method extract_polynome_properties in
  412. ExpressionBase.
  413. """
  414. # rule: 1 * r ^ 1 -> (1, r, 1)
  415. return (ExpressionLeaf(1), self, ExpressionLeaf(1))
  416. def actual_value(self):
  417. if self.type == TYPE_IDENTIFIER:
  418. return self.value
  419. return (1 - 2 * (self.negated & 1)) * self.value
  420. class Scope(object):
  421. def __init__(self, node):
  422. self.node = node
  423. self.nodes = get_scope(node)
  424. def __getitem__(self, key):
  425. return self.nodes[key]
  426. def __setitem__(self, key, value):
  427. self.nodes[key] = value
  428. def __len__(self):
  429. return len(self.nodes)
  430. def __iter__(self):
  431. return iter(self.nodes)
  432. def __eq__(self, other):
  433. return isinstance(other, Scope) and self.node == other.node \
  434. and self.nodes == other.nodes
  435. def __repr__(self):
  436. return '<Scope of "%s">' % repr(self.node)
  437. def remove(self, node, **kwargs):
  438. if node.is_leaf:
  439. node_cmp = hash(node)
  440. else:
  441. node_cmp = node
  442. for i, n in enumerate(self.nodes):
  443. if n.is_leaf:
  444. n_cmp = hash(n)
  445. else:
  446. n_cmp = n
  447. if n_cmp == node_cmp:
  448. if 'replacement' in kwargs:
  449. self[i] = kwargs['replacement']
  450. else:
  451. del self.nodes[i]
  452. return
  453. raise ValueError('Node "%s" is not in the scope of "%s".'
  454. % (node, self.node))
  455. def replace(self, node, replacement):
  456. self.remove(node, replacement=replacement)
  457. def as_nary_node(self):
  458. return nary_node(self.node.op, self.nodes).negate(self.node.negated)
  459. def nary_node(operator, scope):
  460. """
  461. Create a binary expression tree for an n-ary operator. Takes the operator
  462. and a list of expression nodes as arguments.
  463. """
  464. if len(scope) == 1:
  465. return scope[0]
  466. return ExpressionNode(operator, nary_node(operator, scope[:-1]), scope[-1])
  467. def get_scope(node):
  468. """
  469. Find all n nodes within the n-ary scope of an operator node.
  470. """
  471. scope = []
  472. for child in node:
  473. if child.is_op(node.op) and not child.negated:
  474. scope += get_scope(child)
  475. else:
  476. scope.append(child)
  477. return scope
  478. def negate(node, n=1):
  479. """Negate the given node n times."""
  480. assert n >= 0
  481. new_node = node.clone()
  482. new_node.negated = n
  483. return new_node
  484. def infinity():
  485. """
  486. Return an infinity leaf node.
  487. """
  488. return ExpressionLeaf(INFINITY)
  489. def absolute(exp):
  490. """
  491. Put an 'absolute value' operator on top of the given expression.
  492. """
  493. return ExpressionNode(OP_ABS, exp)
  494. def sin(*args):
  495. """
  496. Create a sinus function node.
  497. """
  498. return ExpressionNode(OP_SIN, *args)
  499. def cos(*args):
  500. """
  501. Create a cosinus function node.
  502. """
  503. return ExpressionNode(OP_COS, *args)
  504. def tan(*args):
  505. """
  506. Create a tangens function node.
  507. """
  508. return ExpressionNode(OP_TAN, *args)
  509. def log(exponent, base=10):
  510. """
  511. Create a logarithm function node (default base is 10).
  512. """
  513. if not isinstance(base, ExpressionLeaf):
  514. base = ExpressionLeaf(base)
  515. return ExpressionNode(OP_LOG, exponent, base)
  516. def ln(exponent):
  517. """
  518. Create a natural logarithm node.
  519. """
  520. return log(exponent, base=E)
  521. def der(f, x=None):
  522. """
  523. Create a derivative node.
  524. """
  525. return ExpressionNode(OP_DER, f, x) if x else ExpressionNode(OP_DER, f)
  526. def integral(*args):
  527. """
  528. Create an integral node.
  529. """
  530. return ExpressionNode(OP_INT, *args)
  531. def indef(*args):
  532. """
  533. Create an indefinite integral node.
  534. """
  535. return ExpressionNode(OP_INT_INDEF, *args)
  536. def eq(left, right):
  537. """
  538. Create an equality operator node.
  539. """
  540. return ExpressionNode(OP_EQ, left, right)
  541. def sqrt(exp):
  542. """
  543. Create a square root node.
  544. """
  545. return ExpressionNode(OP_SQRT, exp)
  546. def negation_to_node(node):
  547. """
  548. Recursively replace negation flags inside a node by explicit unary negation
  549. nodes.
  550. """
  551. if node.negated:
  552. negations = node.negated
  553. node = negate(node, 0)
  554. for i in range(negations):
  555. node = ExpressionNode('-', node)
  556. if node.is_leaf:
  557. return node
  558. return ExpressionNode(node.op, *map(negation_to_node, node))