Compile kat script such that model elements appear in script order
The way the parser builds the model depends on the results from a NetworkX sort algorithm that is non-deterministic in its order when two nodes have the same degree*. This means that the same parsed script might yield models with components that are differently ordered in the resulting model. This hasn't so far mattered for tests (good!) but it does make plots and model info listings a bit strange in the way order changes between runs. It's particularly irritating for plots because curves change their colour when they change order.
In 7178e952 I swapped the algorithm to one that resolves degree* ambiguities in favour of the node with earlier line number. This means that at least models with the same graph topology (dependencies) will result in the same model component order.
It's still however possible that small changes to the topology, such as making a previously float value now a reference to something else in the script, can result in a completely different component order. This is simply a fact of life if we want to be able to build kat script in an order in which dependent components are already resolved (due to the declarative nature of kat script).
A simple fix for the above would be to re-order the relevant dicts (elements, spaces, etc.) in the model after compiling, by original line order. However, there is another approach that should allow us to get rid of the computation of the dependency graph, which should give a decent speed boost. The use of topological sorting was introduced in the compiler at a time when we still had some init functions performing operations that required the passed parameters to already be resolved. Since we introduced the Resolving
symbol and changed the few init functions to no longer require resolved parameters at init time, building in dependency order is probably not strictly required any more (except some edge cases like cav
and cp
, which we can continue to deal with separately). If we instead built the model in script order, the compiler would have to create a lot more Resolving
symbols to deal with references to things later in the script not yet compiled, but it should in principle work. The down side to this is that detection of unresolvable cycles becomes harder at (kat script) compile time since a dependency graph is no longer (required to be) built. For the sake of speed for the 99.9% of cases where there are no cycles, we might consider to leave this part to Python; in the case a user creates such a cycle they would probably run into a recursion error like they would if they built such a cycle using the Python API. We may wish to introduce a check while building the simulation for this, though it would require a dependency graph (though this would come for "free" if we implemented #205). We may also consider to have the default behaviour of model simulations be to compute the dependency graph just for validation purposes, throwing a useful error when unresolvable cycles are found, with the option to skip this check.
Since things are working now, and there is a workaround (re-ordering model dicts), I'm marking this with the future milestone.
*This is not strictly the correct term. What I mean here is the total number of other nodes that can be found by recursively following all outgoing edges from a single node.