@@ -36,17 +36,69 @@ function parse_expression(::Model, ::Expression, x::Any, ::Int)
36
36
)
37
37
end
38
38
39
+ function _extract_subexpression! (expr:: Expression , root:: Int )
40
+ nodes_idx = [root]
41
+ values_idx = Int[]
42
+ for i in (root+ 1 ): length (expr. nodes)
43
+ node = expr. nodes[i]
44
+ j = searchsortedlast (nodes_idx, node. parent)
45
+ if j == 0
46
+ continue
47
+ end
48
+ if node. parent == nodes_idx[j]
49
+ push! (nodes_idx, i)
50
+ index = node. index
51
+ if node. type == NODE_VALUE
52
+ push! (values_idx, node. index)
53
+ index = length (values_idx)
54
+ end
55
+ expr. nodes[i] = Node (node. type, node. index, j)
56
+ else
57
+ index = node. index
58
+ if node. type == NODE_VALUE
59
+ # We use the fact that values of `node.index` are increasing
60
+ # along the nodes of `expr.nodes` for which `node.type` is `NODE_VALUE`
61
+ index -= length (values_idx)
62
+ end
63
+ expr. nodes[i] = Node (node. type, index, node. parent - j)
64
+ end
65
+ end
66
+ subexpr = Expression (expr. nodes[nodes_idx], expr. values[values_idx])
67
+ deleteat! (expr. nodes, nodes_idx)
68
+ deleteat! (expr. values, values_idx)
69
+ return subexpr
70
+ end
71
+
72
+ function _extract_subexpression! (data:: Model , expr:: Expression , root:: Int )
73
+ parent = expr. nodes[root]. parent
74
+ push! (data. expressions, _extract_subexpression! (expr, root))
75
+ index = ExpressionIndex (length (data. expressions))
76
+ if parent != 0
77
+ push! (expr. nodes, Node (NODE_SUBEXPRESSION, index. value, parent))
78
+ end
79
+ return index
80
+ end
81
+
39
82
function parse_expression (
40
83
data:: Model ,
41
84
expr:: Expression ,
42
85
x:: MOI.ScalarNonlinearFunction ,
43
86
parent_index:: Int ,
44
87
)
45
- stack = Tuple{Int,Any }[(parent_index, x)]
88
+ stack = Tuple{Int,MOI . ScalarNonlinearFunction }[(parent_index, x)]
46
89
while ! isempty (stack)
47
90
parent_node, arg = pop! (stack)
48
91
if arg isa MOI. ScalarNonlinearFunction
49
- _parse_without_recursion_inner (stack, data, expr, arg, parent_node)
92
+ if haskey (data. cache, arg)
93
+ subexpr = data. cache[arg]
94
+ if subexpr isa Tuple{Expression,Int}
95
+ subexpr = _extract_subexpression! (data, subexpr... )
96
+ end
97
+ parse_expression (data, expr, subexpr:: ExpressionIndex , parent_node)
98
+ else
99
+ _parse_without_recursion_inner (stack, data, expr, arg, parent_node)
100
+ data. cache[arg] = (expr, length (expr. nodes))
101
+ end
50
102
else
51
103
# We can use recursion here, because ScalarNonlinearFunction only
52
104
# occur in other ScalarNonlinearFunction.
@@ -82,7 +134,7 @@ function _parse_without_recursion_inner(stack, data, expr, x, parent)
82
134
parent = length (expr. nodes)
83
135
# Args need to be pushed onto the stack in reverse because the stack is a
84
136
# first-in last-out datastructure.
85
- for arg in reverse (x. args)
137
+ for arg in Iterators . Reverse (x. args)
86
138
push! (stack, (parent, arg))
87
139
end
88
140
return
0 commit comments