feat (report): progress
This commit is contained in:
parent
5d40900390
commit
ba5db5bd99
1 changed files with 199 additions and 116 deletions
309
doc/rep.typ
309
doc/rep.typ
|
|
@ -4,19 +4,20 @@
|
||||||
|
|
||||||
#set text(size: 11pt)
|
#set text(size: 11pt)
|
||||||
#set page(paper: "a4", numbering: "1")
|
#set page(paper: "a4", numbering: "1")
|
||||||
#set par(
|
|
||||||
justify: true,
|
|
||||||
// first-line-indent: 10pt
|
|
||||||
)
|
|
||||||
#set raw(
|
|
||||||
syntaxes: "zelus.sublime-syntax",
|
|
||||||
// theme: none,
|
|
||||||
)
|
|
||||||
// #show raw: set text(font: "CaskaydiaCove NF")
|
|
||||||
#set cite(style: "alphanumeric.csl")
|
|
||||||
#set heading(numbering: "1.1")
|
|
||||||
|
|
||||||
#set figure(gap: 20pt, placement: top)
|
#set cite(style: "alphanumeric.csl")
|
||||||
|
|
||||||
|
#set par(justify: true)
|
||||||
|
#set par.line(numbering: "1")
|
||||||
|
|
||||||
|
#set raw(syntaxes: "zelus.sublime-syntax")
|
||||||
|
#show raw: set par.line(numbering: none)
|
||||||
|
|
||||||
|
#set heading(numbering: "1.1")
|
||||||
|
#show heading: set par.line(numbering: none)
|
||||||
|
|
||||||
|
#set figure(placement: top)
|
||||||
|
#show figure: set par.line(numbering: none)
|
||||||
|
|
||||||
#let zelus = smallcaps[Zélus]
|
#let zelus = smallcaps[Zélus]
|
||||||
#let lustre = smallcaps[Lustre]
|
#let lustre = smallcaps[Lustre]
|
||||||
|
|
@ -33,7 +34,8 @@
|
||||||
#let DNodeC = math.italic[DNodeC]
|
#let DNodeC = math.italic[DNodeC]
|
||||||
#let CNode = math.italic[CNode]
|
#let CNode = math.italic[CNode]
|
||||||
#let HNode = math.italic[HNode]
|
#let HNode = math.italic[HNode]
|
||||||
#let HNodeA = math.italic[HNodeA]
|
#let ANode = math.italic[ANode]
|
||||||
|
#let ASNode = math.italic[ASNode]
|
||||||
#let Dense = math.italic[Dense]
|
#let Dense = math.italic[Dense]
|
||||||
#let IVP = math.italic[IVP]
|
#let IVP = math.italic[IVP]
|
||||||
#let ZCP = math.italic[ZCP]
|
#let ZCP = math.italic[ZCP]
|
||||||
|
|
@ -61,6 +63,7 @@
|
||||||
} else []
|
} else []
|
||||||
#let todo(body) = note(color: rgb(255, 0, 0, 50), prefix: "TODO: ")[#body]
|
#let todo(body) = note(color: rgb(255, 0, 0, 50), prefix: "TODO: ")[#body]
|
||||||
|
|
||||||
|
#set par.line(numbering: none)
|
||||||
#align(center)[
|
#align(center)[
|
||||||
#text(16pt)[
|
#text(16pt)[
|
||||||
*Internship Report --- MPRI M2 \
|
*Internship Report --- MPRI M2 \
|
||||||
|
|
@ -69,6 +72,7 @@
|
||||||
|
|
||||||
Henri Saudubray, supervised by Marc Pouzet, Inria PARKAS
|
Henri Saudubray, supervised by Marc Pouzet, Inria PARKAS
|
||||||
]\
|
]\
|
||||||
|
#set par.line(numbering: "1")
|
||||||
|
|
||||||
// #heading(outlined: false, numbering: none)[General Context]
|
// #heading(outlined: false, numbering: none)[General Context]
|
||||||
// What is the report about? Where does the problem come from? What is the state
|
// What is the report about? Where does the problem come from? What is the state
|
||||||
|
|
@ -152,7 +156,10 @@ _à la_ #haskell, but the addition of typeclasses into the type system of #zelus
|
||||||
is a problem of its own.
|
is a problem of its own.
|
||||||
|
|
||||||
#pagebreak()
|
#pagebreak()
|
||||||
|
#pagebreak()
|
||||||
|
#set par.line(numbering: none)
|
||||||
#outline()
|
#outline()
|
||||||
|
#set par.line(numbering: "1")
|
||||||
|
|
||||||
= Introduction <sec:introduction>
|
= Introduction <sec:introduction>
|
||||||
|
|
||||||
|
|
@ -199,8 +206,6 @@ program written in the synchronous kernel to be considered independently of its
|
||||||
physical implementation. Nothing in this representation tells us anything about
|
physical implementation. Nothing in this representation tells us anything about
|
||||||
how much physical time passes between successive instants.
|
how much physical time passes between successive instants.
|
||||||
|
|
||||||
#note[Should we give a precise definition of the kernel?]
|
|
||||||
|
|
||||||
The programs expressed in this kernel, called _discrete nodes_, are functions on
|
The programs expressed in this kernel, called _discrete nodes_, are functions on
|
||||||
streams. At each time instant, given inputs $I$, they produce outputs $O$.
|
streams. At each time instant, given inputs $I$, they produce outputs $O$.
|
||||||
Producing these outputs may also depend on previously computed values through
|
Producing these outputs may also depend on previously computed values through
|
||||||
|
|
@ -223,18 +228,17 @@ instant.
|
||||||
]
|
]
|
||||||
|
|
||||||
Since programs may wish to reset the state of a node (for instance, when writing
|
Since programs may wish to reset the state of a node (for instance, when writing
|
||||||
automata), nodes also define a reset function $f_"reset" : S -> R -> S$. Since
|
automata; further motivation will be given in the following sections), nodes
|
||||||
nodes may be parameterized by a value, this reset function takes in an
|
also define a reset function $f_"reset" : S -> R -> S$. Since nodes may be
|
||||||
additional reset parameter $R$ and the previous state, and returns an updated
|
parameterized by a value, this reset function takes in an additional reset
|
||||||
state. A discrete model with input $I$ and output $O$ is then a triple of an
|
parameter $R$ and the previous state, and returns an updated state. A discrete
|
||||||
initial state, and a step and reset function:
|
model with input $I$ and output $O$ is then a triple of an initial state, and a
|
||||||
|
step and reset function:
|
||||||
#todo[Justify resets. Why not $R$ in $f_"step"$?]
|
|
||||||
|
|
||||||
$ DNode(I, O, R, S) eq.def {
|
$ DNode(I, O, R, S) eq.def {
|
||||||
s_0 : S;
|
s_0 : S;
|
||||||
f_"step" : S -> I -> O times S;
|
f_"step" : S -> I -> O times S;
|
||||||
f_"reset" : S -> R -> S;
|
f_"reset" : S -> R -> S
|
||||||
} $
|
} $
|
||||||
|
|
||||||
The simulation of such a model then defines two streams: the inner state $s$ and
|
The simulation of such a model then defines two streams: the inner state $s$ and
|
||||||
|
|
@ -244,16 +248,15 @@ $ DSim(M)(i_n) = o_n "where"
|
||||||
(o_n, s_(n+1)) = M.f_"step" (i_n, s_n), s_0 = M.s_0 $
|
(o_n, s_(n+1)) = M.f_"step" (i_n, s_n), s_0 = M.s_0 $
|
||||||
|
|
||||||
A possible implementation of this simulation in #ocaml, where streams are
|
A possible implementation of this simulation in #ocaml, where streams are
|
||||||
represented by lists of values, is given in @lst:discrete_sim.
|
represented by lists of values, is given in @lst:discrete_sim #footnote[
|
||||||
|
Due to space concerns, #ocaml type definitions are ommitted from the main body
|
||||||
#todo[Make figures stand out more.]
|
of the report, and are instead given in @sec:appendix, @lst:ocaml_typedefs.
|
||||||
|
These type definitions are direct translations of the mathematical definitions
|
||||||
|
into #ocaml.
|
||||||
|
].
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
```ocaml
|
```ocaml
|
||||||
(** Discrete model representation. *)
|
|
||||||
type ('a, 'b, 'r, 's) dnode =
|
|
||||||
DNode of { s0 : 's; step : 's -> 'a -> 'b * 's; reset : 's -> 'r -> 's }
|
|
||||||
|
|
||||||
(** Run a model on a list of inputs. *)
|
(** Run a model on a list of inputs. *)
|
||||||
let dsim (DNode model) input =
|
let dsim (DNode model) input =
|
||||||
let rec run s = function
|
let rec run s = function
|
||||||
|
|
@ -369,7 +372,7 @@ two functions:
|
||||||
]
|
]
|
||||||
|
|
||||||
$ CNode(I, O, S, S') eq.def
|
$ CNode(I, O, S, S') eq.def
|
||||||
{ s_0: S; f_"der": I -> S -> S'; f_"out": I -> S -> O; } $
|
{ s_0: S; f_"der": I -> S -> S'; f_"out": I -> S -> O } $
|
||||||
|
|
||||||
For instance, the model of @lst:sincos_discrete can be expressed in continuous
|
For instance, the model of @lst:sincos_discrete can be expressed in continuous
|
||||||
time as seen in @lst:sincos_continuous. Here, `sin` and `cos` are expressed
|
time as seen in @lst:sincos_continuous. Here, `sin` and `cos` are expressed
|
||||||
|
|
@ -562,16 +565,6 @@ implementation in #ocaml is given in @lst:continuous_sim.
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
```ocaml
|
```ocaml
|
||||||
(** Continuous model. *)
|
|
||||||
type ('i, 'o, 's, 'sder) cnode =
|
|
||||||
CNode of { s0: 's; fder: 'i -> 's -> 'sder; fout: 'i -> 's -> 'o }
|
|
||||||
(** Dense values. *)
|
|
||||||
type 'a dense = { h : time; u : time -> 'a }
|
|
||||||
(** Initial value problem. *)
|
|
||||||
type ('y, 'yder) ivp = { y0 : 'y; f : time -> 'y -> 'yder; h : time }
|
|
||||||
(** ODE solver. *)
|
|
||||||
type ('y, 'yder, 's) csolver = (time, 'y dense, ('y, 'yder) ivp, 's) dnode
|
|
||||||
|
|
||||||
(** Simulation of a continuous model, as a discrete node. *)
|
(** Simulation of a continuous model, as a discrete node. *)
|
||||||
let csim (CNode model) (DNode solver) =
|
let csim (CNode model) (DNode solver) =
|
||||||
let s0 = (None, model.s0, solver.s0) in
|
let s0 = (None, model.s0, solver.s0) in
|
||||||
|
|
@ -724,7 +717,6 @@ $ HNode(I, O, R, S, Y, Y', Zi, Zo) eq.def {
|
||||||
f_"horizon" : S -> Time;
|
f_"horizon" : S -> Time;
|
||||||
f_"jump" : S -> BB
|
f_"jump" : S -> BB
|
||||||
} $
|
} $
|
||||||
#todo[This definition is ugly.]
|
|
||||||
|
|
||||||
#zelus provides several ways to specify zero-crossing events, of which the
|
#zelus provides several ways to specify zero-crossing events, of which the
|
||||||
```zelus up(e)``` construct is the most common. It monitors its subexpression
|
```zelus up(e)``` construct is the most common. It monitors its subexpression
|
||||||
|
|
@ -903,38 +895,19 @@ A possible implementation of the discrete step in #ocaml is given in
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
```ocaml
|
```ocaml
|
||||||
(** Simulation mode. *)
|
|
||||||
type mode = Discrete | Continuous | Idle
|
|
||||||
(** Simulation state. *)
|
|
||||||
type ('i, 'sm, 'ss) sim_state =
|
|
||||||
{ sm: 'sm; ss: 'ss; mode: mode; r : bool; i: 'i dense option; now: time }
|
|
||||||
(** Zero-crossing problem. *)
|
|
||||||
type ('y, 'zo) zcp = { f : time -> 'y -> 'zo; y0 : 'y }
|
|
||||||
(** Hybrid model. *)
|
|
||||||
type ('i, 'o, 'r, 's, 'y, 'yd, 'zi, 'zo) hnode = HNode of {
|
|
||||||
s0 : 's; cget : 's -> 'y; cset : 's -> 'y -> 's; zset : 's -> 'zi -> 's;
|
|
||||||
horizon : 's -> time; jump : 's -> bool; step : 's -> 'i -> 'o * 's;
|
|
||||||
fder : 's -> 'i -> 'y -> 'yd; fzer : 's -> 'i -> 'y -> 'zo;
|
|
||||||
fout : 's -> 'i -> 'y -> 'o; reset : 's -> 'r -> 's;
|
|
||||||
}
|
|
||||||
|
|
||||||
let dstep (HNode model) (DNode solver) state =
|
let dstep (HNode model) (DNode solver) state =
|
||||||
let i = Option.get state.i in
|
let i = Option.get state.i in
|
||||||
let (o, sm) = model.step state.sm (i.u state.now) in
|
let (o, sm) = model.step state.sm (i.u state.now) in
|
||||||
let out = { u=(fun _ -> out); h=0.0 } in
|
|
||||||
let state =
|
let state =
|
||||||
let h = model.horizon sm in
|
if model.horizon sm <= 0 then { state with sm }
|
||||||
if h <= 0 then { state with sm }
|
|
||||||
else if state.now >= i.h then { state with mode=Idle; i=None; sm }
|
else if state.now >= i.h then { state with mode=Idle; i=None; sm }
|
||||||
else if model.jump sm || state.r then (* Reset solver. *)
|
else if model.jump sm || state.r then (* Reset solver. *)
|
||||||
let fder t y = model.fder sm (i.u t) y in
|
let ivp = { h=i.h; y0=model.cget sm; f=fun t y -> model.fder sm (i.u t) y } in
|
||||||
let fzer t y = model.fzer sm (i.u t) y in
|
let zcp = { y0=model.cget sm; f=fun t y -> model.fzer sm (i.u t) y } in
|
||||||
let ivp = { f=fder; h=i.h; y0=model.cget sm } in
|
|
||||||
let zcp = { f=fzer; y0=model.cget sm } in
|
|
||||||
let ss = solver.reset (ivp, zcp) state.ss in
|
let ss = solver.reset (ivp, zcp) state.ss in
|
||||||
{ state with mode=Continuous; sm; ss; r=false }
|
{ state with mode=Continuous; sm; ss; r=false }
|
||||||
else { state with mode=Continuous; sm } in
|
else { state with mode=Continuous; sm } in
|
||||||
(Some out, state)
|
(Some { h=0.0; u=fun _ -> o }, state)
|
||||||
```,
|
```,
|
||||||
caption: [Discrete simulation step in #ocaml]
|
caption: [Discrete simulation step in #ocaml]
|
||||||
) <lst:sim_step_discrete>
|
) <lst:sim_step_discrete>
|
||||||
|
|
@ -1014,16 +987,16 @@ Its implementation in #ocaml is given in @lst:sim_algorithm.
|
||||||
#figure(
|
#figure(
|
||||||
```ocaml
|
```ocaml
|
||||||
let hsim (HNode model) (DNode solver) =
|
let hsim (HNode model) (DNode solver) =
|
||||||
let s0 = { mode=Idle; i=None; now=0.0; ss=model.s0; ss=solver.s0; r=true } in
|
let s0 = { mode=Idle; i=None; now=0.0; sm=model.s0; ss=solver.s0; r=true } in
|
||||||
let step state i = match (i, state.mode) with
|
let step state i = match (i, state.mode) with
|
||||||
| Some _, Idle ->
|
| Some _, Idle ->
|
||||||
let state = { state with mode=Discrete; i; now=0.0; r=true } in
|
let state = { state with mode=Discrete; i; now=0.0; r=true } in
|
||||||
dstep (HNode model) (DNode solver) state
|
dstep (HNode model) (DNode solver) state
|
||||||
| None, Discrete -> dstep (HNode model) (DNode solver) state
|
| None, Discrete -> dstep (HNode model) (DNode solver) state
|
||||||
| None, Continuous -> cstep (HNode model) (DNode solver) state
|
| None, Continuous -> cstep (HNode model) (DNode solver) state
|
||||||
| None, Idle -> (None, state) in
|
| None, Idle -> (None, state)
|
||||||
| Some _, _ -> assert false
|
| Some _, _ -> assert false in
|
||||||
let reset r state =
|
let reset state r =
|
||||||
{ state with mode=Idle; sm=model.reset r state.sm; r=true } in
|
{ state with mode=Idle; sm=model.reset r state.sm; r=true } in
|
||||||
DNode { s0; step; reset }
|
DNode { s0; step; reset }
|
||||||
```,
|
```,
|
||||||
|
|
@ -1162,16 +1135,6 @@ instanciate and call a solver, this seems entirely feasible.
|
||||||
|
|
||||||
= Hybrid Observers and Assertions <sec:hybrid_observers>
|
= Hybrid Observers and Assertions <sec:hybrid_observers>
|
||||||
|
|
||||||
#todo[
|
|
||||||
Describe assertions as a run-time defensive construct (as in #ocaml), and
|
|
||||||
their equivalent in #lustre: synchronous observers. Emphasize that the
|
|
||||||
synchronous subset does not cause any problem, since the observer has no
|
|
||||||
impact on its underlying model. Describe their naïve extension to continuous
|
|
||||||
time, and their unexpected impact on the behaviour of the continuous model:
|
|
||||||
recall the examples of Section 1.1. Conclusion: we need to simulate continuous
|
|
||||||
observers with their own solver.
|
|
||||||
]
|
|
||||||
|
|
||||||
During the design and implementation of software, programmers often use
|
During the design and implementation of software, programmers often use
|
||||||
assertions in order to check certain properties, both before and during
|
assertions in order to check certain properties, both before and during
|
||||||
execution. In #ocaml, for instance, the ```ocaml assert``` instruction checks
|
execution. In #ocaml, for instance, the ```ocaml assert``` instruction checks
|
||||||
|
|
@ -1252,9 +1215,7 @@ simulation, as described in @sec:sim_algorithm.
|
||||||
|
|
||||||
let hybrid f (*...*) =
|
let hybrid f (*...*) =
|
||||||
let v = (*...*) in
|
let v = (*...*) in
|
||||||
(present(assertion_f(v)) ->
|
(present(assertion_f(v)) -> print_endline "ERROR" else ());
|
||||||
print_endline "ERROR"
|
|
||||||
else ());
|
|
||||||
(*...*)
|
(*...*)
|
||||||
```,
|
```,
|
||||||
caption: [A naïve implementation of a continuous observer.]
|
caption: [A naïve implementation of a continuous observer.]
|
||||||
|
|
@ -1274,26 +1235,18 @@ with its own ODE solver.
|
||||||
|
|
||||||
== Models With Assertions <sec:models_with_assertions>
|
== Models With Assertions <sec:models_with_assertions>
|
||||||
|
|
||||||
#todo[
|
|
||||||
Since we are able to transform a hybrid model into a discrete one (albeit with
|
|
||||||
a complicated type), we can isolate parts of a model in order to simulate them
|
|
||||||
with a dedicated solver, and provide the obtained stream as input to another
|
|
||||||
hybrid model simulation, which performs the assertion on this precomputed
|
|
||||||
solution. This gives rise to a new datatype for a model together with its
|
|
||||||
assertions.
|
|
||||||
]
|
|
||||||
|
|
||||||
Since an assertion can be considered as a separate model operating on the inner
|
Since an assertion can be considered as a separate model operating on the inner
|
||||||
state of its parent model, we can represent a model with assertions as a pair
|
state of its parent model, we can represent a model with assertions as a pair
|
||||||
of the parent model $m$, operating on its inner state $S_M$, and a list of
|
of the parent model $m$, operating on its inner state $S_M$, and a list of
|
||||||
assertion models. All assertions operate on the same input datatype $S_M$ (the
|
assertion models. All assertions operate on the same input datatype $S_M$ (the
|
||||||
state of the parent model) and return Boolean output signals $BB$.
|
state of the parent model) and return Boolean output signals $BB$.
|
||||||
|
|
||||||
$ HNodeA(I, O, R, S_M, Y, Y', Zi, Zo) eq.def {
|
$ ANode(I, O, R, S_M, Y, Y', Zi, Zo) eq.def {
|
||||||
& m : HNode(I, O, R, S_M, Y, Y', Zi, Zo); \
|
& m : HNode(I, O, R, S_M, Y, Y', Zi, Zo); \
|
||||||
& a : List(HNodeA(S_M, BB, R_A, S_A, Y_A, Y'_A, Zi_A, Zo_A)) } $
|
& a : List(ANode(S_M, BB, R_A, S_A, Y_A, Y'_A, Zi_A, Zo_A))
|
||||||
|
} $
|
||||||
|
|
||||||
Note that the output signal is Boolean even in continuous time. There are
|
Note <t> that the output signal is Boolean even in continuous time. There are
|
||||||
two possible interpretations of this: either assertions benefit from relaxed
|
two possible interpretations of this: either assertions benefit from relaxed
|
||||||
typing rules for their output, and are allowed a limited subset of discrete
|
typing rules for their output, and are allowed a limited subset of discrete
|
||||||
behaviours in continuous time; or assertions in continuous time are defined in
|
behaviours in continuous time; or assertions in continuous time are defined in
|
||||||
|
|
@ -1301,23 +1254,92 @@ terms of zero-crossing events, and as such the output of the assertion will be
|
||||||
constant during continuous phases (in fact, the output will be constantly true,
|
constant during continuous phases (in fact, the output will be constantly true,
|
||||||
as the simulation would not have entered a continuous step otherwise). Both
|
as the simulation would not have entered a continuous step otherwise). Both
|
||||||
interpretations lead to the same updated simulation algorithm, as we will see in
|
interpretations lead to the same updated simulation algorithm, as we will see in
|
||||||
@sec:updated_sim.
|
@sec:updated_sim. The $ANode$ datatype is recursive: indeed, nothing prevents
|
||||||
|
assertions from containing their own assertions, and so on and so forth.
|
||||||
|
|
||||||
The $HNodeA$ datatype is recursive: indeed, nothing prevents assertions from
|
#todo[Clarify why Boolean values as output is surprising.]
|
||||||
containing their own assertions, and so on and so forth.
|
|
||||||
|
While this representation allows for a lot of expressivity, in most cases, a
|
||||||
|
model with a single assertion suffices. Multiple assertions may be combined as
|
||||||
|
a single one by simply taking the conjunction of their outputs, and nested
|
||||||
|
assertions (assertions within assertions) can be checked as part of the
|
||||||
|
simulation of their parents. We can then define a simpler datatype
|
||||||
|
|
||||||
|
$ ASNode(I, O, R, S_M, Y, Y', Zi, Zo) eq.def {
|
||||||
|
& m : HNode(I, O, R, S_M, Y, Y', Zi, Zo); \
|
||||||
|
& a : DNode(Signal(S_M), BB, R, S_A)
|
||||||
|
} $
|
||||||
|
|
||||||
|
where the assertion is a single, discrete node operating on dense functions of
|
||||||
|
the model state and returning Boolean values. During compilation, assertions are
|
||||||
|
compiled down to hybrid models, and turned into discrete simulations using a
|
||||||
|
variant of the `solve` function of @sec:lifting_runtime. This is the current
|
||||||
|
target model of the #zelus compiler; however, simulations of both $ANode$ and
|
||||||
|
$ASNode$ are implemented in the runtime.
|
||||||
|
|
||||||
== Updated Simulation <sec:updated_sim>
|
== Updated Simulation <sec:updated_sim>
|
||||||
|
|
||||||
#todo[
|
The simulation of a system with assertions requires little adjustments from the
|
||||||
Present a version of the simulation with assertions (probably the simple
|
original simulation algorithm. The main difficulty resides in the fact that we
|
||||||
version with a single assertion, rather than the complex one with polymorphic
|
need to construct a dense function of the entire parent model's state. For
|
||||||
recursion and such).
|
discrete steps, this is simple: we build a constant function on the model's
|
||||||
]
|
state defined on the interval $[0, 0]$. For continuous steps, the ODE solver
|
||||||
|
provides us with a dense function of the continuous part of the state. Since the
|
||||||
|
discrete part of the state is constant during integration, we can use the
|
||||||
|
approximation returned by the solver, combined with the model's $c_"set"$
|
||||||
|
function, to build a dense function of the entire state. We need to be careful,
|
||||||
|
however: if the $c_"set"$ function rewrites the model's state in-place (this is
|
||||||
|
the case in the code produced by the #zelus compiler), we must update the state
|
||||||
|
back to its value at the horizon reached by the ODE solver before starting the
|
||||||
|
next simulation step.
|
||||||
|
|
||||||
#todo[
|
The simulation state then stores a copy of the model's continuous state at the
|
||||||
Maybe present a high-level overview of the compilation passes? This seems a
|
reached horizon after every continuous step. Before every step, we update the
|
||||||
little out of scope.
|
model's state to ensure its correctness. Continuous steps now produce an
|
||||||
]
|
additional dense function of the state, which is used as input to the assertion.
|
||||||
|
A step of the simulation then performs a step of the parent model, as seen in
|
||||||
|
@sec:sim_algorithm, and uses the additional output to step the simulation of
|
||||||
|
the assertion as often as needed for it to reach the model's reached time,
|
||||||
|
checking the assertion's output at each step.
|
||||||
|
|
||||||
|
The updated #ocaml implementation is given in @lst:sim_assert.
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
```ocaml
|
||||||
|
let acstep (HNode model) (DNode solver) state =
|
||||||
|
let i = (*...*) in let stop = (*...*) in
|
||||||
|
let (({ h=now; u=dky }, z), ss) = solver.step state.ss stop in
|
||||||
|
let out = { h=now; u=fun t -> model.fout state.sm (i.u t) (dky t) } in
|
||||||
|
let dst = { h=now; u=fun t -> model.cset state.sm (dky t) } in
|
||||||
|
let state = (*...*) in
|
||||||
|
(Some out, state, Some dst)
|
||||||
|
|
||||||
|
let asim (ASNode { m=HNode model; a=DNode assertion }) (DNode solver) =
|
||||||
|
let s0 = { (*...*); y=None; sa=a.state } in
|
||||||
|
let dstep state =
|
||||||
|
let state = { state with sm=model.cset state.sm state.y } in
|
||||||
|
let o, state = dstep (HNode model) (DNode solver) state in
|
||||||
|
let y = model.cget state.sm in
|
||||||
|
let b, sa = assertion.step state.sa (Some { h=0.0; u=fun _ -> state.sm }) in
|
||||||
|
assert b; (o, { state with sa; y }) in
|
||||||
|
let cstep state =
|
||||||
|
let state = { state with sm=model.cset state.sm state.y } in
|
||||||
|
let o, state, st = acstep (HNode model) (DNode solver) state in
|
||||||
|
let y = model.cget state.sm in
|
||||||
|
let b, sa = assertion.step state.sa st in
|
||||||
|
assert b; (o, { state with sa; y }) in
|
||||||
|
let step state i = match (i, state.mode) with
|
||||||
|
| (*...*)
|
||||||
|
| None, Discrete -> dstep state
|
||||||
|
| None, Continuous -> cstep state
|
||||||
|
| (*...*) in
|
||||||
|
let reset state r =
|
||||||
|
let sm = model.reset r state.sm and sa = assertion.reset r state.sa in
|
||||||
|
{ state with mode=Idle; sm; sa; r=true } in
|
||||||
|
DNode { s0; step; reset }
|
||||||
|
```,
|
||||||
|
caption: [Simulation of a model with assertions in #ocaml]
|
||||||
|
) <lst:sim_assert>
|
||||||
|
|
||||||
= Future Work <sec:future_work>
|
= Future Work <sec:future_work>
|
||||||
|
|
||||||
|
|
@ -1336,20 +1358,64 @@ containing their own assertions, and so on and so forth.
|
||||||
|
|
||||||
#pagebreak()
|
#pagebreak()
|
||||||
|
|
||||||
|
= Bibliography <sec:bibliography>
|
||||||
|
|
||||||
#bibliography(
|
#bibliography(
|
||||||
"sources.bib",
|
"sources.bib",
|
||||||
// full: true,
|
// full: true,
|
||||||
style: "alphanumeric.csl",
|
style: "alphanumeric.csl",
|
||||||
title: [Bibliography]
|
title: none
|
||||||
)
|
)
|
||||||
|
#todo[Find a proper bibliographic style.]
|
||||||
|
|
||||||
= Appendix <sec:appendix>
|
= Appendix <sec:appendix>
|
||||||
|
|
||||||
#todo[Find a proper bibliographic style.]
|
|
||||||
|
|
||||||
== Additional Code <sec:additional_code>
|
== Additional Code <sec:additional_code>
|
||||||
|
|
||||||
#set figure(placement: none)
|
#set figure(placement: none)
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
```ocaml
|
||||||
|
(** Discrete-time model. *)
|
||||||
|
type ('i, 'o, 'r, 's) dnode =
|
||||||
|
DNode of { s0 : 's; step : 's -> 'i -> 'o * 's; reset : 's -> 'r -> 's }
|
||||||
|
(** Continuous-time model. *)
|
||||||
|
type ('i, 'o, 's, 'sd) cnode =
|
||||||
|
CNode of { s0 : 's; fder : 'i -> 's -> 'sd; fout : 'i -> 's -> 'o }
|
||||||
|
(** Dense values. *)
|
||||||
|
type 'a dense = { h : time; u : time -> 'a }
|
||||||
|
(** Initial value problem. *)
|
||||||
|
type ('y, 'yd) ivp = { y0 : 'y; stop : time; f : time -> 'y -> 'yd }
|
||||||
|
(** ODE solver. *)
|
||||||
|
type ('y, 'yd, 's) csolver = (time, 'y dense, ('y, 'yd) ivp, 's) dnode
|
||||||
|
(** Hybrid simulation mode. *)
|
||||||
|
type mode = Discrete | Continuous | Idle
|
||||||
|
(** Hybrid simulation state. *)
|
||||||
|
type ('i, 'sm, 'ss) state =
|
||||||
|
{ sm : 'sm; ss : 'ss; mode : mode; r : bool; i : 'i dense option; now : time }
|
||||||
|
(** Zero-crossing problem. *)
|
||||||
|
type ('y, 'zo) zcp = { y0 : 'y; f : time -> 'y -> 'zo }
|
||||||
|
(** Zero-crossing solver. *)
|
||||||
|
type ('y, 'zi, 'zo, 's) zsolver =
|
||||||
|
('y dense, time * 'zi option, ('y, 'zo) zcp, 's) dnode
|
||||||
|
(** Hybrid model. *)
|
||||||
|
type ('i, 'o, 'r, 's, 'y, 'yd, 'zi, 'zo) hnode =
|
||||||
|
HNode of { s0 : 's;
|
||||||
|
cget : 's -> 'y; cset : 's -> 'y -> 's; zset : 's -> 'zi -> 's;
|
||||||
|
horizon : 's -> time; jump : 's -> bool; reset : 's -> 'r -> 's;
|
||||||
|
step : 's -> 'i -> 'o * 's; fder : 's -> 'i -> 'y -> 'yd;
|
||||||
|
fzero : 's -> 'i -> 'y -> 'zo; fout : 's -> 'i -> 'y -> 'o }
|
||||||
|
(** Full solver. *)
|
||||||
|
type ('y, 'yd, 'zi, 'zo, 's) solver =
|
||||||
|
(time, 'y dense * 'zi option, ('y, 'yd) ivp * ('y, 'zo) zcp, 's) dnode
|
||||||
|
(** Hybrid model with a single assertion. *)
|
||||||
|
type ('i, 'o, 'r, 'sm, 'sa, 'y, 'yd, 'zi, 'zo) asnode =
|
||||||
|
ASNode of { m : ('i, 'o, 'r, 'sm, 'y, 'yd, 'zi, 'zo) hnode;
|
||||||
|
a : ('sm signal, bool, 'sa) dnode }
|
||||||
|
```,
|
||||||
|
caption: [#ocaml type definitions]
|
||||||
|
) <lst:ocaml_typedefs>
|
||||||
|
|
||||||
#figure(
|
#figure(
|
||||||
```ocaml
|
```ocaml
|
||||||
let compose (DNode f) (DNode g) =
|
let compose (DNode f) (DNode g) =
|
||||||
|
|
@ -1361,14 +1427,31 @@ containing their own assertions, and so on and so forth.
|
||||||
(o, (sf, sg))
|
(o, (sf, sg))
|
||||||
| None ->
|
| None ->
|
||||||
let (o, sf) = f.step sf None in
|
let (o, sf) = f.step sf None in
|
||||||
match o with Some _ -> (o, (sf, sg)) | None ->
|
match o with
|
||||||
let (o, sg) = g.step sg None in
|
| Some _ -> (o, (sf, sg))
|
||||||
match o with None -> (None, (sf, sg)) | Some _ ->
|
| None ->
|
||||||
|
let (v, sg) = g.step sg None in
|
||||||
|
match v with
|
||||||
|
| None -> (None, (sf, sg))
|
||||||
|
| Some _ ->
|
||||||
let (o, sf) = f.step sf o in
|
let (o, sf) = f.step sf o in
|
||||||
(o, (sf, sg)) in
|
(o, (sf, sg)) in
|
||||||
let reset (sf, sg) (rf, rg) = (f.reset sf rf, g.reset sg rg) in
|
let reset (sf, sg) (rf, rg) = (f.reset sf rf, g.reset sg rg) in
|
||||||
DNode { s0; step; reset }
|
DNode { s0; step; reset }
|
||||||
```,
|
```,
|
||||||
caption: [Composition of simulations in #ocaml]
|
caption: [Composition of simulations in #ocaml]
|
||||||
)
|
) <lst:compose>
|
||||||
|
|
||||||
|
#figure(
|
||||||
|
```ocaml
|
||||||
|
let synchr (DNode f) (DNode g) =
|
||||||
|
```,
|
||||||
|
caption: [Synchronization of simulations in #ocaml]
|
||||||
|
) <lst:synchr>
|
||||||
|
|
||||||
|
#todo[Complete @lst:synchr.]
|
||||||
|
|
||||||
|
#note[
|
||||||
|
Ideas:
|
||||||
|
- Detailed synchronous kernel of #zelus
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue