I'm Hugo Gualandi, and am currently pursuing a PhD at PUC-Rio university, focusing on programming languages. For GSOC2016 I implemented experimental ASCEND parsers and syntax transformers.
GSOC 2016 Project: Improvements to the Conditional Modeling Syntax
The goal of my 2016 Summer Of Code project was to improve ASCEND's conditional modelling syntax. The first thing I did was to study the current state of ASCEND's conditional modeling and identify some ways in which the current modeling syntax and semantics could be improved. My findings are documented in the #Proposed syntax changes section.
My most significant contribution during this project was to implement an experimental alternative parser for the ASCEND modeling language that allows a faster rate of experimentation for new syntactic features compared to the existing ASCEND parser. I documented what this parser does and how to use it in its own wiki page: OcamlParser.
What is left to is leverage the new parser to experiment with the new designs for the conditional syntax and then, after verifying that they work well, implement the required changes in ASCEND's main compiler.
Proposed syntax changes
The main goal of this project was to improve the usability of dynamic and conditional modeling in ASCEND. This includes:
1) Reducing redundancy in the specification
- Right now some models break badly without redundant information (FIX and FREE in hybrid models)
- Sometimes, we have redundant information that could have been inferred by a smarter compiler
2) Make modeling less error prone
- Right now, hybrid modeling relies on calling methods that run FIX, FREE and set variables by hand. This is very error prone and violates some of the ASCEND abstractions.
- I believe that the key to improving this is a better way to specify initial conditions in models.
So far, I have identified many easy places to improve the language regarding point #1. Point #2 is something that ended up being harder than expected. Many of my proposed changes were inspired by the Modelica system and I would highly recommend checking that out for comparison.
Easy redundancy reduction
1) We could infer the PREVIOUS and DERIVATIVE OF declarations.
Modelica does this for its language. Its would be just a matter of parsing the model and checking which variables we are using the der() and pre() operators on. Right now, the only thing these declarations do is clutter the model and complain when we forget to specify a declaration.
2) We could allow conditional expressions inside equations.
For example, right now we use USE statements to turn equations on and off:
on: P = 3000; off: P = 0; ev1: EVENT (too_high) CASE TRUE: USE off; END EVENT;
I would prefer to use boolean expressions instead, similar to how it is possible in Modelica. In ASCEND it would look something like this:
P = if on then 3000 else 0;
Another good application of conditional expressions would be piecewise functions such as min(), max() and abs(). They resulting code can end up more concise than conditional equations.
x = max(y, 0)
For optimization and advanced tweaking, Modelica also has the `noEvent` and `smooth` operators to "turn off" the automatic event-handling and boundary checking of conditional expressions.
Miscelaneous Modelica features
Some Modelica features caught my eye. They wouldn't be a big priority for us, but I think its worth mentioning that they exist.
1) You can use a buit-in function to create an event that runs every X seconds. In Ascend I think you would need to abuse a periodic function such as sin() to achieve this effect.
2) The terminate() builtin lets you cleanly halt the integration from inside an event handler.
For motivation, lets look at the code for a bouncing ball in Modelica:
model BouncingBall "The 'classic' bouncing ball model" type Height=Real(unit="m"); type Velocity=Real(unit="m/s"); parameter Real e=0.8 "Coefficient of restitution"; parameter Height h0=1.0 "Initial height"; Height h; Velocity v; initial equation h = h0; equation der(h) = v der(v) = -9.81; when h<0 then reinit(v, -e*pre(v)); end when; end BouncingBall;
Some interesting things that I think of this:
- The Hybrid modeling happens via a `reinit` statement that "sets" a variable to a new value. We were asking if maybe something more general would be needed but Modelica suggests that these "assignments" are enough.
- However, `reinit` is not a plain assignment. It also recomputes the initial conditions appropriately.
- There are special equations for specifying the initial conditions. In more advanced cases, these equations can be things like `der(x) = 0`.
Now, lets compare this to how ASCEND handles EVENT statements
- Detect when a boolean variable flips from FALSE to TRUE
- Deactivate equations from OTHERWISE clause.
- Activate equations in the CASE TRUE clause.
- Run the evtname METHOD to fix/free variables.
- Run QRSlv
- Run the evtname_end METHOD to undo the changes from step 4
Step 1 can get a bit cleaner if we allow boolean expressions instead of just boolean variables. I think steps 2 and 3 should be covered by regular conditional equations (what the current WHEN syntax does) and does not have to be the responsibility of the EVENT statement.
The really tricky part are steps 4, 5 and 6. This problem of solving the system to find new initial conditions is something that we don't have a good way to express yet in ASCEND. For example, notice how some of the models in the ksenija folder have `before_integ` or `prepare_integ` that should be manually run to find initial conditions. I also needed to do something similar to find steady-state initial conditions in the Lotka-Volterra model I wrote.
Right now, I don't know how to fix this problem of specifying initial conditions but I highly suspect that if we can figure this out, the syntax for the hybrid modeling will follow very naturally.