I’m sure that you both have gone further down this road than I. Here some things I’ve noted along the way:
For the constraints-variables boxes instead of the function name ending with ‘-v’ I’ve found that adding a question mark makes it easier to visually distinguish. +v, /v, etc is presented as ?+,?/, etc.
Working with the forwards constraints variables I’ve had some success generating them applying rules and sending them to a solver (I’ve designated it FIND-ALL, but such naming might be too similar to a certain commercial Knowledge-Based System). Evaluating boxes in patches results in calls to functions and methods related to the OM visual boxes system. This confuses Screamer (as you have likely found out) and makes it impossible to use ‘either’ and other functions termed ‘non-deterministic’ within Screamer. With its reliance on a code-walker, certain optimizations it tries to perform don’t immediately seem possible from the visual environment. If you connect screamer:=v to screamer:assert! in a patch, it will work, but Screamer will not call the optimized assert-=v function because as you know the text of the code being processed includes omng box-calls. The same is true for the other optimized functions. I see that your extension uses quoting in calls involving ‘nondeterministic’ functions and forward constraints variables.
My library also tries to cache constraints variables. For instance, if you have a list of variables like: (55 [x1] [x2] [x1] [x4]), and apply some operator to them (such as modulo 2):
(mapcar #'(lambda (x) (?% x 2))
… the second time the ?% operator encounters the variable [x1] it will return the variable it generated the first time. That way, additional constraints applied elsewhere will be applied to the same variable.
I’m not sure if this is necessary from a Screamer-architecture point-of-view, and I haven’t run into any situation where it seemed necessary to do this.
I modified TEMPLATE to facilitate working with sequences of variables. If a symbol is prefixed with ? and ends with a ‘+’, a sequence number is incremented. A symbol ending with a ‘#’ maintains the previous sequence number. I find this useful for working with variables corresponding to sequences (like MIDI-note values). So for instance to generate a fourth-species counterpoint for a given theme I can enter:
((nil ?x+) (?x# ?x+) (?x# ?x+) ?x+)
(62 69 64 62))
which is translated by my om::?template function into:
((nil ?x0) (?x0 ?x1) (?x1 ?x2) ?x3)
(62 69 64 62))
and then a mixture of variables and symbols when passed to SCREAMER:TEMPLATE (((nil [?x0]) ([?x0] [?x1]) ([?x1] [?x2]) [?x3]) (62 69 64 62))
There are two notes in voice 2 for every note of the C.F. The same variable carries over in voice 2, creating suspensions. A that point, a simple rule can be defined that a dissonant vertical interval be escaped by step.
The functions defined in general.lisp under the heading ‘variables registry’ I don’t think are necessary. Every call to a boolean constraint operator caches the resulting variable if it is not already present in the registry. The combination of the function invoked and its arguments are used as the key in the map. Functions like max, min, and, or, =, /=, etc use set-equality to compare arguments. member-of functions use set-equality to compare the second argument. +, *, avg, etc compare the arguments as unordered lists. The rest of the functions use list-equality. I now leave this feature turned off (t2l::disable-variable-cache-map). If I got rid of it, the library would be substantially smaller.
My interest in finding out more about existing constraints libraries like OM-Screamer or continuing to try to develop this in connection to a visual workspace is their potential as instructional technology. Being able to read through and evaluate several hundred generated counterpoints for a given theme, or to interact with program objects and symbols to design one’s own rule-set for polyphony, can help to level the playing field in music theory classrooms. As for creative applications, I am not sure I can make any promises.
Anyway, OM-Screamer looks very promising, especially the visual score-object. I wasn’t aware of the features in OM 4 being brought into this package. Thanks for sharing!