Skip to content

Commit 6f996fd

Browse files
Merge pull request #90 from JuliaComputing/as/operator-arg-clocks
feat: track clocks of clock operator arguments in clock inference
2 parents 47e80d0 + 7d4c169 commit 6f996fd

2 files changed

Lines changed: 33 additions & 3 deletions

File tree

lib/ModelingToolkitTearing/src/clock_inference/clock_inference.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
@data ClockVertex begin
2+
# A variable identified by its index in `fullvars`
23
Variable(Int)
4+
# An equation identified by its index in `equations(state)`
35
Equation(Int)
6+
# An initialization equation identified by its index in `initialization_equations(state.sys)`
47
InitEquation(Int)
8+
# A concrete, known clock
59
Clock(SciMLBase.AbstractClock)
10+
# An unnamed, unnknown clock identified by some UUID stored in `ShiftIndex`
611
InferredClock(UUID)
12+
# An arbitrary expression for which we want to preserve clocking information
13+
Expression(SymbolicT)
14+
# Compatibility for ModelingToolkit's `DiscreteSystem` semantics.
715
IntegerSequence
816
end
917

@@ -21,6 +29,10 @@ struct ClockInference{S <: StateSelection.TransformationState}
2129
inference_graph::HyperGraph{ClockVertex.Type}
2230
"""The set of variables with concrete domains."""
2331
inferred::BitSet
32+
"""A mapping from every argument of every clock operator to the clock it is on. More \
33+
generally extensible to any expression for which it is deemed necessary to preserve \
34+
clock information."""
35+
expression_clocks::Dict{SymbolicT, TimeDomain}
2436
end
2537

2638
function ClockInference(ts::StateSelection.TransformationState)
@@ -73,7 +85,7 @@ function ClockInference(ts::StateSelection.TransformationState)
7385
add_edge!(inference_graph, (varvert, dvert))
7486
end
7587
ClockInference{typeof(ts)}(ts, eq_domain, init_eq_domain, var_domain, inference_graph,
76-
inferred)
88+
inferred, Dict{SymbolicT, TimeDomain}())
7789
end
7890

7991
struct NotInferredTimeDomain end
@@ -262,6 +274,7 @@ function (ivc::InferVariableClosure)(var::SymbolicT)
262274
nested_ivc(v)
263275
end
264276

277+
push!(arg_hyperedge, ClockVertex.Expression(arg))
265278
# NOTE: Ensure all branches here add `arg_hyperedge` to the inference graph. It
266279
# is the parent hyperedge for `nested_ivc`, so this closure is responsible for
267280
# adding it to the graph.
@@ -422,6 +435,7 @@ function infer_clocks!(ci::ClockInference)
422435
ClockVertex.Clock(_) => nothing
423436
ClockVertex.InferredClock(_) => nothing
424437
ClockVertex.IntegerSequence() => nothing
438+
ClockVertex.Expression(expr) => (ci.expression_clocks[expr] = clock)
425439
end
426440
end
427441
end

lib/ModelingToolkitTearing/test/runtests.jl

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,10 @@ MTKTearing.is_timevarying_operator(::Op3) = true
265265

266266
@testset "Clock inference handles nested clock operators correctly" begin
267267
@variables x(t) y(t) z(t) w(t)
268-
k1 = ShiftIndex(Clock(0.1))
269-
k2 = ShiftIndex(Clock(0.2))
268+
clk1 = Clock(0.1)
269+
clk2 = Clock(0.2)
270+
k1 = ShiftIndex(clk1)
271+
k2 = ShiftIndex(clk2)
270272

271273
# From `Op1`, we should infer that `clock_of(z) == clock_of(y)`
272274
# From `Op2`, we should infer that `clock_of(w) == clock_of(Op3(x))`
@@ -281,6 +283,20 @@ MTKTearing.is_timevarying_operator(::Op3) = true
281283
@test issetequal(ts.fullvars, [x, x(k2-1), y, z, w, Op3(x), Op2(Op3(x), w), Op1(Op2(Op3(x), w) + x, 3sin(y))])
282284
ci = MTKTearing.ClockInference(ts)
283285
MTKTearing.infer_clocks!(ci)
286+
idx = findfirst(isequal(w), ts.fullvars)
287+
@test ci.var_domain[idx] == clk2
288+
idx = findfirst(isequal(Op3(x)), ts.fullvars)
289+
@test ci.var_domain[idx] == clk2
290+
idx = findfirst(isequal(Op2(Op3(x), w)), ts.fullvars)
291+
@test ci.var_domain[idx] == clk2
292+
idx = findfirst(isequal(Op1(Op2(Op3(x), w) + x, 3sin(y))), ts.fullvars)
293+
@test ci.var_domain[idx] == clk1
294+
295+
@test ci.expression_clocks[x] == clk2
296+
@test ci.expression_clocks[Op3(x)] == clk2
297+
@test ci.expression_clocks[w] == clk2
298+
@test ci.expression_clocks[Op2(Op3(x), w) + x] == clk2
299+
@test ci.expression_clocks[3sin(y)] == clk1
284300

285301
# Check that this errors if `+ x` is not present.
286302
eqs = [

0 commit comments

Comments
 (0)