Skip to content

Commit 2433de5

Browse files
committedFeb 5, 2017
Multi-dimensional functions (#44)
* Parametrize Separators * Fix test * Fixes for the types of lhs and args * Multi-dimensional contractor seems to be working! * Make multidim iterated functions work * Remove debugging output for iterated functions * Move parse_comparison to separator.jl * Escape name of contractor when creating constraint so that it is available with name _C_1_ etc. * Convenience constructor for ConstraintSeparator that automatically extracts variables * Factor out content of into make_constraint function * Parametrise interval field of ConstraintSeparator
1 parent a8413b8 commit 2433de5

File tree

6 files changed

+171
-31
lines changed

6 files changed

+171
-31
lines changed
 

‎src/ast.jl

+32-9
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ end
139139
# function process_iterated_function!(flatAST::FlattenedAST, ex)
140140

141141
function process_tuple!(flatAST::FlattenedAST, ex)
142-
println("Entering process_tuple")
142+
# println("Entering process_tuple")
143143
# @show flatAST
144144
# @show ex
145145
# top_args = [flatten!(flatAST, arg) for arg in ex.args]
@@ -161,19 +161,36 @@ The name a is currently retained.
161161
TODO: It should later be made unique.
162162
"""
163163
function process_assignment!(flatAST::FlattenedAST, ex)
164-
println("process_assignment!:")
165-
# @show ex
166-
# @show ex.args[1], ex.args[2]
164+
# println("process_assignment!:")
165+
# @show ex
166+
# @show ex.args[1], ex.args[2]
167167

168168
top = flatten!(flatAST, ex.args[2])
169+
# @show top
169170

170171
var = ex.args[1]
171-
push!(flatAST.intermediate, var)
172+
# @show var
173+
174+
# TODO: Replace the following by multiple dispatch
175+
if isa(var, Expr) && var.head == :tuple
176+
vars = [var.args...]
177+
178+
elseif isa(var, Tuple)
179+
vars = [var...]
180+
181+
elseif isa(var, Vector)
182+
vars = var
183+
184+
else
185+
vars = [var]
186+
end
187+
188+
append!(flatAST.intermediate, vars)
172189

173-
top_level_code = Assignment(var, :(), top) # empty operation
190+
top_level_code = Assignment(vars, :(), top) # empty operation
174191
push!(flatAST.code, top_level_code)
175192

176-
# @show flatAST
193+
# j@show flatAST
177194

178195
return var
179196

@@ -183,17 +200,23 @@ end
183200
by rewriting it to the equivalent set of iterated functions"""
184201
function process_iterated_function!(flatAST::FlattenedAST, ex)
185202
total_function_call = ex.args[1]
186-
argument = ex.args[2]
203+
args = ex.args[2:end]
204+
205+
# @show args
187206

188207
function_name = total_function_call.args[2]
189208
power = total_function_call.args[3] # assumed integer
190209

191-
new_expr = :($function_name($argument))
210+
new_expr = :($function_name($(args...)))
211+
212+
# @show new_expr
192213

193214
for i in 2:power
194215
new_expr = :($function_name($new_expr))
195216
end
196217

218+
# @show new_expr
219+
197220
flatten!(flatAST, new_expr)
198221
end
199222

‎src/code_generation.jl

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11

22
function make_tuple(args)
3+
4+
if isa(args, Symbol)
5+
# args = [args]
6+
return args
7+
end
8+
39
length(args) == 1 && return args[1]
410

511
return Expr(:tuple, args...)
@@ -10,19 +16,24 @@ function emit_forward_code(a::Assignment)
1016

1117
args = isa(a.args, Vector) ? a.args : [a.args]
1218

19+
lhs = make_tuple(a.lhs)
20+
1321
if a.op == :() # empty
14-
:($(a.lhs) = $(args...) )
22+
args = make_tuple(args)
23+
:($lhs = $args)
1524

1625
else
17-
:($(a.lhs) = $(a.op)($(args...) ) )
26+
:($lhs = $(a.op)($(args...) ) )
1827
end
1928
end
2029

2130

2231
function emit_forward_code(a::FunctionAssignment)
2332
f = a.func
24-
args = make_tuple(a.lhs)
25-
:($args = $(esc(f)).forward($(a.args...) ) )
33+
args = isa(a.args, Vector) ? a.args : [a.args]
34+
lhs = make_tuple(a.lhs)
35+
36+
:($lhs = $(esc(f)).forward($(a.args...) ) )
2637
end
2738

2839

@@ -43,7 +54,10 @@ function emit_backward_code(a::Assignment)
4354
rev_op = rev_ops[a.op] # find reverse operation
4455

4556
if rev_op == :() # empty
46-
return :($(args...) = $(a.lhs))
57+
args = make_tuple(args)
58+
lhs = make_tuple(a.lhs)
59+
return :($args = $lhs)
60+
#return :($(args...) = $(a.lhs))
4761
else
4862
rev_code = :($(rev_op)($(return_args...)))
4963
end

‎src/contractor.jl

+14-5
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ function make_contractor(ex::Expr)
136136
# using an IntervalBox and intersection of IntervalBoxes
137137
end
138138

139+
top_args = make_tuple(top)
140+
141+
local intersect_code
142+
143+
if isa(top_args, Symbol)
144+
intersect_code = :($top_args = $top_args _A_) # check type stability
145+
else
146+
intersect_code = :($top_args = IntervalBox($top_args) _A_) # check type stability
147+
end
139148

140149

141150
code =
@@ -147,7 +156,7 @@ function make_contractor(ex::Expr)
147156

148157
$(forward_output) = forward($(forward.input_arguments...))
149158

150-
$(top) = $(top) _A_
159+
$intersect_code
151160

152161
$(backward_output) = backward($(backward.input_arguments...))
153162

@@ -157,10 +166,10 @@ function make_contractor(ex::Expr)
157166

158167
end
159168

160-
# @show forward
161-
# @show backward
162-
#
163-
# @show code
169+
# @show forward
170+
# @show backward
171+
# #
172+
# @show code
164173

165174
return :(Contractor($(augmented_input_arguments),
166175
$(Meta.quot(expr)),

‎src/functions.jl

+8-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type ConstraintFunction{F <: Function, G <: Function}
2626
output::Vector{Symbol} # output arguments for forward function
2727
forward::F
2828
backward::G
29+
forward_code::Expr
30+
backward_code::Expr
2931
end
3032

3133
type FunctionArguments
@@ -92,14 +94,19 @@ Example: `@function f(x, y) = x^2 + y^2`
9294

9395
registered_functions[f] = FunctionArguments(flatAST.variables, flatAST.intermediate, return_arguments)
9496

97+
forward_function = make_function(forward_code)
98+
backward_function = make_function(backward_code)
9599

96100
return quote
97101
#$(esc(Meta.quot(f))) = ConstraintFunction($(all_vars), $(generated), $(forward_code), $(backward_code))
98102
#$(esc(f)) =
99103
$(esc(f)) =
100104
ConstraintFunction($(flatAST.variables),
101105
$(flatAST.intermediate),
102-
$(make_function(forward_code)), $(make_function(backward_code))
106+
$(forward_function),
107+
$(backward_function),
108+
$(Meta.quot(forward_function)),
109+
$(Meta.quot(backward_function))
103110
)
104111

105112

‎src/separator.jl

+79-10
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,22 @@ ConstraintSeparator is a separator that represents a constraint defined directly
66
using `@constraint`.
77
"""
88
# CHANGE TO IMMUTABLE AND PARAMETRIZE THE FUNCTION FOR EFFICIENCY
9-
type ConstraintSeparator <: Separator
9+
type ConstraintSeparator{C, II} <: Separator
1010
variables::Vector{Symbol}
1111
#separator::Function
12-
constraint::Interval
13-
contractor::Contractor
12+
constraint::II # Interval or IntervalBox
13+
contractor::C
1414
expression::Expr
1515
end
1616

17+
ConstraintSeparator(constraint, contractor, expression) = ConstraintSeparator(contractor.variables[2:end], constraint, contractor, expression)
18+
1719
doc"""CombinationSeparator is a separator that is a combination (union, intersection,
1820
or complement) of other separators.
1921
"""
20-
type CombinationSeparator <: Separator
22+
type CombinationSeparator{F} <: Separator
2123
variables::Vector{Symbol}
22-
separator::Function
24+
separator::F
2325
expression::Expr
2426
end
2527

@@ -50,11 +52,69 @@ end
5052

5153

5254

55+
doc"""`parse_comparison` parses comparisons like `x >= 10`
56+
into the corresponding interval, expressed as `x ∈ [10,∞]`
5357
58+
Returns the expression and the constraint interval
59+
60+
TODO: Allow something like [3,4]' for the complement of [3,4]
61+
"""
62+
63+
function parse_comparison(ex)
64+
expr, limits =
65+
@match ex begin
66+
((a_ <= b_) | (a_ < b_) | (a_ b_)) => (a, (-∞, b))
67+
((a_ >= b_) | (a_ > b_) | (a_ b_)) => (a, (b, ∞))
68+
69+
((a_ == b_) | (a_ = b_)) => (a, (b, b))
70+
71+
((a_ <= b_ <= c_)
72+
| (a_ < b_ < c_)
73+
| (a_ <= b_ < c)
74+
| (a_ < b_ <= c)) => (b, (a, c))
75+
76+
((a_ >= b_ >= c_)
77+
| (a_ > b_ > c_)
78+
| (a_ >= b_ > c_)
79+
| (a_ > b_ >= c)) => (b, (c, a))
80+
81+
((a_ [b_, c_])
82+
| (a_ in [b_, c_])
83+
| (a_ b_ .. c_)
84+
| (a_ in b_ .. c_)) => (a, (b, c))
85+
86+
_ => (ex, (-∞, ∞))
87+
88+
end
89+
90+
a, b = limits
91+
92+
return (expr, a..b) # expr ∈ [a,b]
93+
94+
end
5495

55-
macro constraint(ex::Expr) # alternative name for constraint -- remove?
56-
# @show ex
57-
expr, constraint = parse_comparison(ex)
96+
97+
function new_parse_comparison(ex)
98+
@show ex
99+
if @capture ex begin
100+
(op_(a_, b_))
101+
end
102+
103+
#return (op, a, b)
104+
@show op, a, b
105+
106+
elseif ex.head == :comparison
107+
println("Comparison")
108+
symbols = ex.args[1:2:5]
109+
operators = ex.args[2:2:4]
110+
111+
@show symbols
112+
@show operators
113+
114+
end
115+
end
116+
117+
function make_constraint(expr, constraint)
58118

59119
if isa(expr, Symbol)
60120
expr = :(1 * $expr) # make into an expression!
@@ -65,15 +125,24 @@ macro constraint(ex::Expr) # alternative name for constraint -- remove?
65125
full_expr = Meta.quot(:($expr $constraint))
66126

67127
code = quote end
68-
push!(code.args, :($contractor_name = @contractor($(esc(expr)))))
69-
push!(code.args, :(ConstraintSeparator($(contractor_name).variables[2:end], $constraint, $contractor_name, $full_expr)))
128+
push!(code.args, :($(esc(contractor_name)) = @contractor($(esc(expr)))))
129+
# push!(code.args, :(ConstraintSeparator($(esc(contractor_name)).variables[2:end], $constraint, $(esc(contractor_name)), $full_expr)))
130+
131+
push!(code.args, :(ConstraintSeparator($constraint, $(esc(contractor_name)), $full_expr)))
70132

71133
# @show code
72134

73135
code
136+
end
137+
138+
macro constraint(ex::Expr) # alternative name for constraint -- remove?
139+
# @show ex
140+
expr, constraint = parse_comparison(ex)
74141

142+
make_constraint(expr, constraint)
75143
end
76144

145+
77146
# doc"""Create a separator from a given constraint expression, written as
78147
# standard Julia code.
79148
#

‎test/runtests.jl

+19-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ end
3030
X = IntervalBox(II, II)
3131
S = @constraint x^2 + y^2 <= 1
3232

33-
@test typeof(S) == IntervalConstraintProgramming.ConstraintSeparator
33+
@test typeof(S) <: IntervalConstraintProgramming.ConstraintSeparator
3434

3535
inner, outer = S(X)
3636
@test inner == (-1..1, -1..1)
@@ -158,3 +158,21 @@ end
158158

159159
@test C3(A, x) == sqrt(A / 16)
160160
end
161+
162+
@testset "Multidimensional functions" begin
163+
164+
@function g4(x, y) = (2x, 2y)
165+
166+
A = IntervalBox(0.5..1, 0.5..1)
167+
x = y = 0..1
168+
169+
C4 = @contractor g4(x, y)
170+
171+
@test IntervalBox(C4(A, x, y)) == A / 2
172+
173+
174+
C5 = @contractor (g42)(x, y)
175+
176+
@test IntervalBox(C5(A, x, y)) == A / 4
177+
178+
end

0 commit comments

Comments
 (0)
Please sign in to comment.