@@ -36,17 +36,69 @@ function parse_expression(::Model, ::Expression, x::Any, ::Int)
3636 )
3737end
3838
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+
3982function parse_expression (
4083 data:: Model ,
4184 expr:: Expression ,
4285 x:: MOI.ScalarNonlinearFunction ,
4386 parent_index:: Int ,
4487)
45- stack = Tuple{Int,Any }[(parent_index, x)]
88+ stack = Tuple{Int,MOI . ScalarNonlinearFunction }[(parent_index, x)]
4689 while ! isempty (stack)
4790 parent_node, arg = pop! (stack)
4891 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
50102 else
51103 # We can use recursion here, because ScalarNonlinearFunction only
52104 # occur in other ScalarNonlinearFunction.
@@ -82,7 +134,7 @@ function _parse_without_recursion_inner(stack, data, expr, x, parent)
82134 parent = length (expr. nodes)
83135 # Args need to be pushed onto the stack in reverse because the stack is a
84136 # first-in last-out datastructure.
85- for arg in reverse (x. args)
137+ for arg in Iterators . Reverse (x. args)
86138 push! (stack, (parent, arg))
87139 end
88140 return
0 commit comments