strategy.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # This file is part of TRS (http://math.kompiler.org)
  2. #
  3. # TRS is free software: you can redistribute it and/or modify it under the
  4. # terms of the GNU Affero General Public License as published by the Free
  5. # Software Foundation, either version 3 of the License, or (at your option) any
  6. # later version.
  7. #
  8. # TRS is distributed in the hope that it will be useful, but WITHOUT ANY
  9. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  10. # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  11. # details.
  12. #
  13. # You should have received a copy of the GNU Affero General Public License
  14. # along with TRS. If not, see <http://www.gnu.org/licenses/>.
  15. from node import OP_NEG, NARY_OPERATORS
  16. from rules import RULES
  17. from rules.precedences import HIGH, LOW, RELATIVE
  18. def compare_possibilities(a, b):
  19. """
  20. Comparable function for (possibility, depth) pairs.
  21. Returns a positive number if A has a lower priority than B, a negative
  22. number for the reverse case, and 0 if the possibilities have equal
  23. priorities.
  24. """
  25. (pa, da), (pb, db) = a, b
  26. ha, hb = pa.handler, pb.handler
  27. # Equal handlers means equal precedences
  28. if ha == hb:
  29. return 0
  30. # Check if A and B have a precedence relative to eachother
  31. for rel in RELATIVE:
  32. if ha in rel and hb in rel:
  33. return cmp(rel.index(ha), rel.index(hb))
  34. # If A has a high priority, it might be moved to the start of the list
  35. if ha in HIGH:
  36. # Id B has a high priority too, compare the positions in the list
  37. if hb in HIGH:
  38. return HIGH[ha] - HIGH[hb]
  39. # Move A towards the beginning of the list
  40. return -1
  41. # If only B has a high priority, move it up with respect to A
  42. if hb in HIGH:
  43. return 1
  44. # If A has a low priority, it might be moved to the end of the list
  45. if ha in LOW:
  46. # Id B has a low priority too, compare the positions in the list
  47. if hb in LOW:
  48. return LOW[ha] - LOW[hb]
  49. # Move A towards the end of the list
  50. return 1
  51. # If only B has a high priority, move it down with respect to A
  52. if hb in LOW:
  53. return -1
  54. # default: use order that was generated implicitely by leftmost-innermost
  55. # expression traversal
  56. return 0
  57. def depth_possibilities(node, depth=0, parent_op=None):
  58. p = []
  59. handlers = []
  60. # Add operator-specific handlers
  61. if not node.is_leaf:
  62. # Traverse through child nodes first using postorder traversal
  63. for child in node:
  64. # FIXME: "depth + 1" is disabled for the purpose of
  65. # leftmost-innermost traversal
  66. p += depth_possibilities(child, depth, node.op)
  67. # Add operator-specific handlers. Prevent duplicate possibilities in
  68. # n-ary nodes by only executing the handlers on the outermost node of
  69. # related nodes with the same operator
  70. if node.op in RULES and (node.op != parent_op \
  71. or node.op not in NARY_OPERATORS):
  72. handlers += RULES[node.op]
  73. # Add negation handlers after operator-specific handlers to obtain an
  74. # outermost effect for negations
  75. if node.negated:
  76. handlers += RULES[OP_NEG]
  77. # Run handlers
  78. for handler in handlers:
  79. p += [(pos, depth) for pos in handler(node)]
  80. #print node, p
  81. return p
  82. def find_possibilities(node):
  83. """
  84. Find all possibilities inside a node and return them in a list.
  85. """
  86. possibilities = depth_possibilities(node)
  87. #import copy
  88. #old_possibilities = copy.deepcopy(possibilities)
  89. possibilities.sort(compare_possibilities)
  90. #get_handler = lambda (p, d): str(p.handler)
  91. #if old_possibilities != possibilities:
  92. # print 'before:', '\n '.join(map(get_handler, old_possibilities))
  93. # print 'after:', '\n '.join(map(get_handler, possibilities))
  94. return [p for p, depth in possibilities]
  95. # 2x ^ 2 = 3x ^ (1 + 1)