| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- # vim: set fileencoding=utf-8 :
- import os.path
- import sys
- sys.path.insert(0, os.path.realpath('external'))
- from graph_drawing.graph import generate_graph
- from graph_drawing.line import generate_line
- from graph_drawing.node import Node, Leaf
- TYPE_OPERATOR = 1
- TYPE_IDENTIFIER = 2
- TYPE_INTEGER = 4
- TYPE_FLOAT = 8
- # Unary
- OP_NEG = 1
- # Binary
- OP_ADD = 2
- OP_SUB = 3
- OP_MUL = 4
- OP_DIV = 5
- OP_POW = 6
- OP_MOD = 7
- # N-ary (functions)
- OP_INT = 8
- OP_EXPAND = 9
- TYPE_MAP = {
- int: TYPE_INTEGER,
- float: TYPE_FLOAT,
- str: TYPE_IDENTIFIER,
- }
- OP_MAP = {
- '+': OP_ADD,
- # Either substraction or negation. Skip the operator sign in 'x' (= 2).
- '-': lambda x: OP_SUB if len(x) > 2 else OP_NEG,
- '*': OP_MUL,
- '/': OP_DIV,
- '^': OP_POW,
- 'mod': OP_MOD,
- 'int': OP_INT,
- 'expand': OP_EXPAND,
- }
- class ExpressionBase(object):
- def is_leaf(self):
- return self.type != TYPE_OPERATOR
- def is_power(self):
- return not self.is_leaf() and self.op == OP_POW
- def is_nary(self):
- return not self.is_leaf() and self.op in [OP_ADD, OP_SUB, OP_MUL]
- def is_identifier(self):
- return self.is_leaf() and self.type & TYPE_IDENTIFIER
- def is_int(self):
- return self.is_leaf() and self.type & TYPE_INTEGER
- def is_float(self):
- return self.is_leaf() and self.type & TYPE_FLOAT
- def is_numeric(self):
- return self.is_leaf() and self.type & (TYPE_FLOAT | TYPE_INTEGER)
- class ExpressionNode(Node, ExpressionBase):
- def __init__(self, *args, **kwargs):
- super(ExpressionNode, self).__init__(*args, **kwargs)
- self.type = TYPE_OPERATOR
- self.op = OP_MAP[args[0]]
- if hasattr(self.op, '__call__'):
- self.op = self.op(args)
- def __str__(self): # pragma: nocover
- return generate_line(self)
- def graph(self): # pragma: nocover
- return generate_graph(self)
- def replace(self, node):
- pos = self.parent.nodes.index(self)
- self.parent.nodes[pos] = node
- node.parent = self.parent
- self.parent = None
- def get_polynome(self):
- """
- Identifier nodes of all polynomes, tuple format is:
- (root, exponent, coefficient, literal_exponent)
- """
- # TODO: change "get_polynome" -> "extract_polynome".
- # TODO: change retval of c * r ^ e to (c, r, e).
- # TODO: normalize c * r and r * c -> c * r. Otherwise, the tuple will
- # not match if the order of the expression is different. Example:
- # r ^ e * c == c * r ^ e
- # without normalization, those expressions will not match.
- # rule: r ^ e
- if self.is_power():
- return (self[0], self[1], ExpressionLeaf(1), True)
- if self.op != OP_MUL:
- return
- # expression: c * r ^ e ; tree:
- #
- # *
- # ╭┴───╮
- # c ^
- # ╭─┴╮
- # r e
- #
- # rule: c * r ^ e | (r ^ e) * c
- for i, j in [(0, 1), (1, 0)]:
- if self[j].is_power():
- return (self[j][0], self[j][1], self[i], True)
- # rule: c * r | r * c
- return (self[0], ExpressionLeaf(1), self[1], False)
- def get_scope(self):
- """"""
- scope = []
- #op = OP_ADD | OP_SUB if self.op & (OP_ADD | OP_SUB) else self.op
- for child in self:
- if not child.is_leaf() and child.op == self.op:
- scope += child.get_scope()
- else:
- scope.append(child)
- return scope
- class ExpressionLeaf(Leaf, ExpressionBase):
- def __init__(self, *args, **kwargs):
- super(ExpressionLeaf, self).__init__(*args, **kwargs)
- self.type = TYPE_MAP[type(args[0])]
- def get_polynome(self):
- """
- Identifier nodes of all polynomes, tuple format is:
- (identifier, exponent, coefficient, literal_exponent)
- """
- # a = 1 * a ^ 1
- return (self, ExpressionLeaf(1), ExpressionLeaf(1), False)
- def replace(self, node):
- if not hasattr(self, 'parent'):
- return
- pos = self.parent.nodes.index(self)
- self.parent.nodes[pos] = node
- node.parent = self.parent
- self.parent = None
|