Progress Meter
- [WIP] Knowledge-Representation Improvements
- [X] Better syntax, cleaner API & refactoring
- [~] Meta info in slots
- [ ] Advice
- [X] Change predicates
- [ ] Multi-Methods (value-based)
- [WIP] Constraint Management Improvements
- [X] Better syntax & some refactoring
- [~] Parameterized pointer variables
- [X] Advice (for constraints)
- [X] Store constraints as KR objects
- [ ] Async execution
- 2D Graphics
- [ ] Linear Algebra and Geometry additions
- [ ] 2D API for geometry + Backend (via SDL)
- [ ] Event objects + Backend (via SDL)
- [ ] Text API + Backend (via Pango)
- [ ] Cells
- [ ] Configurations
- [ ] Some demo (after everything else)
---
Aaaand I am back. My apologies for the delays on reporting, I really
meant to be doing these regularly. A few things came up and I have just
had a couple of unexpectedly busy months, and couldn't attend to the
project properly. Most of what I am reporting here dates back to May for
the most part.
In any case, I am getting back up to speed now. And here are the changes
since the previous report:
- Constraint loop resolution.
- Static inheritance.
- Schema struct access semantics.
- Schema-like constraints.
- Constraint advice.
- Basic change predicates.
First of all, it turns out that the authors of SkyBlue (the constraint
engine) have coded in the ability to write custom solvers for cyclical
constraints. This is quite fortunate since a constraint such as the
following one
;; A constraint for a few properties of a rectangle
;; (Like Ξ is used for schemas, ζ is used for constraints.)
(ζ (left right width)
(:= left (- right width))
(:= right (+ left width))
(:= width (- right left)))
has so far been treated by SkyBlue not really as a cycle, but just as a
multi-way relation, where if a single variable were to change (say,
/width/), then only a _single_ other definition would be enforced
(depending on the order of definition, /left/ in this case). This
approach is sufficient enough for many cases, but it's usefulness is
limited to only three variables. And there's an even bigger problem in
the hiding: the engine is only able to enforce a single output variable,
whichever one runs last. Undesirable behavior ensues if you impose
additional constraints on any one of these variables.
Now with the cyclical resolution set up, it is possible to rewrite this
single constraint as an actual cycle using three distinct constraints,
one for each variable. The strengths of these constraints identify the
priorities, and all the variables stay enforced. It's not a problem
anymore to have more than three variables in a loop or to introduce
additional constraints. As a sidenote: indeed, for the particular
example above, three separate constraints will look a bit ugly for what
really is just an algebraic equation. And so, in the future, custom
cycle solvers might be used to implement linear equation solvers (and
therefore allow concise notation for such relationship) - to that end,
the original authors have even provided a few stubs. This would mean an
ability for the user to add actual algebraic constraints -- either
through equalities or inequalities. This possibility will be worth
exploring further at some point, and that could be useful for UI layout
programming.
Moving onto the next point, one of the goals was to add schema-like
constraint definitions. In fact, constraints are now schemas
_themselves_.
(ζ a-is-b-plus-1 (a b) ; name and inputs
(strength 5) ; slots
(:= a (1+ b))) ; the constraint statement
Constraints can now be named, be derived from each other in a
parameterized manner, may carry additional information about themselves,
and all the while the syntax is nothing but familiar and schema-like
(both for modification and creation). The access and write operators
require no special checks or conditions and so there's no performance
penalty.
However, this arrangement has initially proven to be an expensive
affair: a schema contains hash tables, and CL hash tables happen to be
quite slow to create. Now, since constraints are used as the primary
mechanism for inheriting slots between objects, an ensuing cost would
simply be unacceptable, since each slot would have to be associated with
a constraint (and its hash tables) for every derived object.
To resolve the matter, the schemas may now be created as "lightweight":
these omit hash-table creation altogether, and instead exclusively
expose the slots of the structure object itself. In other words, if a
struct (deriving from schema) has all the slots necessary for the
object's operation, then there's no need to be creating any hash-tables
at all. The interface to these struct slots is the same as to the
hash-table slots. These struct slots however can't be used with
constraints (not now anyway), but this limitation seems to be irrelevant
for the actual use cases involved.
To further minimize the performance impact of treating constraints as
schemas, schemas now also provide an option of "static" inheritance in
addition to the default "dynamic" kind, for the cases where speed is
more important than keeping child-parent slots dynamically
coherent. This is most useful when an object is not meant to be mutated,
and most constraints (by sheer numbers) seem to fall into that category.
So, essentially, constraint objects can still be lightweight even now
that they have acquired schema-like interface and capabilities. Still,
though, it's optional to make any particular instance have all the
regular dynamic properties such as dynamic slot creation or dynamic
inheritance, were the user to wish that.
The finer details of this are still being fleshed out, but it's pretty
much a done deal. Though, perhaps, it will also be worth the effort to
eliminate the hash-table creation overhead altogether for any schema:
simply by introducing a pool of empty hash-tables (but this is yet to be
tested).
Moving on, the change predicates prevent recomputation. These matter
only for the → (write) operator: when a value is written to a slot and
is equivalent to a value already stored in the slot, then no constraints
will be triggered. This equality-checking is assumed to be eql, but
may now be specified by the user.
---
I will begin working on parameterized pointer variables shortly, after
which I will do either async execution or value-based multi-methods. So,
that's the plan for the next 3-4 weeks. And once all these are done, and
before getting into 2D graphics, I will document KR & constraints &
their implementation properly and accessibly.
Yours,
-- DK