node.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # vim: set fileencoding=utf-8 :
  2. import os.path
  3. import sys
  4. sys.path.insert(0, os.path.realpath('external'))
  5. from graph_drawing.graph import generate_graph
  6. from graph_drawing.line import generate_line
  7. from graph_drawing.node import Node, Leaf
  8. TYPE_OPERATOR = 1
  9. TYPE_IDENTIFIER = 2
  10. TYPE_INTEGER = 4
  11. TYPE_FLOAT = 8
  12. # Unary
  13. OP_NEG = 1
  14. # Binary
  15. OP_ADD = 2
  16. OP_SUB = 3
  17. OP_MUL = 4
  18. OP_DIV = 5
  19. OP_POW = 6
  20. OP_MOD = 7
  21. # N-ary (functions)
  22. OP_INT = 8
  23. OP_EXPAND = 9
  24. TYPE_MAP = {
  25. int: TYPE_INTEGER,
  26. float: TYPE_FLOAT,
  27. str: TYPE_IDENTIFIER,
  28. }
  29. OP_MAP = {
  30. '+': OP_ADD,
  31. # Either substraction or negation. Skip the operator sign in 'x' (= 2).
  32. '-': lambda x: OP_SUB if len(x) > 2 else OP_NEG,
  33. '*': OP_MUL,
  34. '/': OP_DIV,
  35. '^': OP_POW,
  36. 'mod': OP_MOD,
  37. 'int': OP_INT,
  38. 'expand': OP_EXPAND,
  39. }
  40. class ExpressionBase(object):
  41. def is_leaf(self):
  42. return self.type != TYPE_OPERATOR
  43. def is_power(self):
  44. return not self.is_leaf() and self.op == OP_POW
  45. def is_nary(self):
  46. return not self.is_leaf() and self.op in [OP_ADD, OP_SUB, OP_MUL]
  47. def is_identifier(self):
  48. return self.is_leaf() and self.type & TYPE_IDENTIFIER
  49. def is_int(self):
  50. return self.is_leaf() and self.type & TYPE_INTEGER
  51. def is_float(self):
  52. return self.is_leaf() and self.type & TYPE_FLOAT
  53. def is_numeric(self):
  54. return self.is_leaf() and self.type & (TYPE_FLOAT | TYPE_INTEGER)
  55. class ExpressionNode(Node, ExpressionBase):
  56. def __init__(self, *args, **kwargs):
  57. super(ExpressionNode, self).__init__(*args, **kwargs)
  58. self.type = TYPE_OPERATOR
  59. self.op = OP_MAP[args[0]]
  60. if hasattr(self.op, '__call__'):
  61. self.op = self.op(args)
  62. def __str__(self): # pragma: nocover
  63. return generate_line(self)
  64. def graph(self): # pragma: nocover
  65. return generate_graph(self)
  66. def replace(self, node):
  67. pos = self.parent.nodes.index(self)
  68. self.parent.nodes[pos] = node
  69. node.parent = self.parent
  70. self.parent = None
  71. def get_polynome(self):
  72. """
  73. Identifier nodes of all polynomes, tuple format is:
  74. (root, exponent, coefficient, literal_exponent)
  75. """
  76. # TODO: change "get_polynome" -> "extract_polynome".
  77. # TODO: change retval of c * r ^ e to (c, r, e).
  78. # TODO: normalize c * r and r * c -> c * r. Otherwise, the tuple will
  79. # not match if the order of the expression is different. Example:
  80. # r ^ e * c == c * r ^ e
  81. # without normalization, those expressions will not match.
  82. # rule: r ^ e
  83. if self.is_power():
  84. return (self[0], self[1], ExpressionLeaf(1), True)
  85. if self.op != OP_MUL:
  86. return
  87. # expression: c * r ^ e ; tree:
  88. #
  89. # *
  90. # ╭┴───╮
  91. # c ^
  92. # ╭─┴╮
  93. # r e
  94. #
  95. # rule: c * r ^ e | (r ^ e) * c
  96. for i, j in [(0, 1), (1, 0)]:
  97. if self[j].is_power():
  98. return (self[j][0], self[j][1], self[i], True)
  99. # rule: c * r | r * c
  100. return (self[0], ExpressionLeaf(1), self[1], False)
  101. def get_scope(self):
  102. """"""
  103. scope = []
  104. #op = OP_ADD | OP_SUB if self.op & (OP_ADD | OP_SUB) else self.op
  105. for child in self:
  106. if not child.is_leaf() and child.op == self.op:
  107. scope += child.get_scope()
  108. else:
  109. scope.append(child)
  110. return scope
  111. class ExpressionLeaf(Leaf, ExpressionBase):
  112. def __init__(self, *args, **kwargs):
  113. super(ExpressionLeaf, self).__init__(*args, **kwargs)
  114. self.type = TYPE_MAP[type(args[0])]
  115. def get_polynome(self):
  116. """
  117. Identifier nodes of all polynomes, tuple format is:
  118. (identifier, exponent, coefficient, literal_exponent)
  119. """
  120. # a = 1 * a ^ 1
  121. return (self, ExpressionLeaf(1), ExpressionLeaf(1), False)
  122. def replace(self, node):
  123. if not hasattr(self, 'parent'):
  124. return
  125. pos = self.parent.nodes.index(self)
  126. self.parent.nodes[pos] = node
  127. node.parent = self.parent
  128. self.parent = None