strategy.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. from node import OP_NEG
  2. from rules import RULES
  3. from rules.precedences import HIGH, LOW, RELATIVE
  4. def compare_possibilities(a, b):
  5. """
  6. Comparable function for (possibility, depth) pairs.
  7. Returns a positive number if A has a lower priority than B, a negative
  8. number for the reverse case, and 0 if the possibilities have equal
  9. priorities.
  10. """
  11. (pa, da), (pb, db) = a, b
  12. ha, hb = pa.handler, pb.handler
  13. # Check if A and B have a precedence relative to eachother
  14. if (ha, hb) in RELATIVE:
  15. return -1
  16. if (hb, ha) in RELATIVE:
  17. return 1
  18. # If A has a high priority, it might be moved to the start of the list
  19. if ha in HIGH:
  20. # Id B has a high priority too, compare the positions in the list
  21. if hb in HIGH:
  22. return HIGH[ha] - HIGH[hb]
  23. # Move A towards the beginning of the list
  24. return -1
  25. # If only B has a high priority, move it up with respect to A
  26. if hb in HIGH:
  27. return 1
  28. # If A has a low priority, it might be moved to the end of the list
  29. if ha in LOW:
  30. # Id B has a low priority too, compare the positions in the list
  31. if hb in LOW:
  32. return LOW[ha] - LOW[hb]
  33. # Move A towards the end of the list
  34. return 1
  35. # If only B has a high priority, move it down with respect to A
  36. if hb in LOW:
  37. return -1
  38. # default: use order that was generated implicitely by leftmost-innermost
  39. # expression traversal
  40. return 0
  41. def depth_possibilities(node, depth=0, parent_op=None):
  42. p = []
  43. handlers = []
  44. # Add operator-specific handlers
  45. if not node.is_leaf:
  46. # Traverse through child nodes first using postorder traversal
  47. for child in node:
  48. # FIXME: "depth + 1" is disabled for the purpose of
  49. # leftmost-innermost traversal
  50. p += depth_possibilities(child, depth, node.op)
  51. # Add operator-specific handlers. Prevent duplicate possibilities in
  52. # n-ary nodes by only executing the handlers on the outermost node of
  53. # related nodes with the same operator
  54. if node.op != parent_op and node.op in RULES:
  55. handlers += RULES[node.op]
  56. # Add negation handlers after operator-specific handlers to obtain an
  57. # outermost effect for negations
  58. if node.negated:
  59. handlers += RULES[OP_NEG]
  60. # Run handlers
  61. for handler in handlers:
  62. p += [(pos, depth) for pos in handler(node)]
  63. #print node, p
  64. return p
  65. def find_possibilities(node):
  66. """
  67. Find all possibilities inside a node and return them in a list.
  68. """
  69. possibilities = depth_possibilities(node)
  70. #import copy
  71. #old_possibilities = copy.deepcopy(possibilities)
  72. possibilities.sort(compare_possibilities)
  73. #get_handler = lambda (p, d): str(p.handler)
  74. #if old_possibilities != possibilities:
  75. # print 'before:', '\n '.join(map(get_handler, old_possibilities))
  76. # print 'after:', '\n '.join(map(get_handler, possibilities))
  77. return [p for p, depth in possibilities]
  78. # 2x ^ 2 = 3x ^ (1 + 1)