I know this pattern and it’s worth saying it’s one to avoid if you can as it doesn’t scale well. That is due to the collect_if(all,$StringAttribute.contains($Name(that)),$Name)
bit. Done as a rule, don’t forget the rule runs not only in the original but in every alias as well. If you’re not careful everything in the doc is constantly investigating every other thing.
So, it seems sensible to ask, if B knows (or can query that) A links to it, why does it need an explicit record in a different attribute of that fact? If we can extract the underlying need there may be a different way to achieve the aim.
Going back to the original point. The apparent mis-performance and out come of the code is likely to be a mix of:
- interacting rules taking several cycles to flush data around all the code
- possible unintended loops (A acts on B, which acts on A, etc…)
- rules/actions running when not needed
In my research, I’m often looking to link items to others based on shared values, but as stated above this can hit performance as .contains()
calls are the most computationally expensive actions. So some things to try…
-
Run rules via a prototype. In your prototype put the code within this structure:
if($RuleDisabled($Prototype)==false & ($IsPrototype==false) ){
…rule code here…
}
If the prototype rule is disabled, inheriting notes still evaluate the rule but bail due to the if condition (i.e. because ). Turning the rule on in the prototype lets the rule rule run. That way you can stop all those .contains()
calls running when not needed.
- Scope. Do you really need to test “all”. In your model you’re looking at a map of aliases in an agent. Looking at your TBX, A links to B and C but B only to A and C only to A. So, if investigating A->B relationships you want to test only aliases of type A items in the map of interest. If thats in a map called “Map” and ‘A’ type items use prototype “pTypeA” then do something like:
$relatedToB=collect_if(find(inside("Map") & $Prototype=="TypeA" & $IsAlias),$relatedToA.contains($Name(that)),$Name);
Note how the find() call will check far fewer items than “all”. I also note this code completely replaces the contents of relatedToB.
When briefly looking at your TBX last night a was surprised to find ‘plan’ type links appearing in the map, which I think were due to an agent action (the map is in an agent). I assume those links are building on the logic of the $relatedToX
data. Anyway, I thin this exercise shows that whilst we may build code to automate and annotate relationships, we need to do so with care. For instance, I’d work on the primary relationships. Then, turn on the rules in my prototypes one by one, let the cycle run (use the Agents & Rules Inspector tab) then turn off the rule. Only then enable the agent action to build links based on that info and turn that off when done. Most of these actions only need one cycle and are background noise the rest of the time.
If you’ve code that needs to run once when used and only used when needed, consider a stamp. A stamp is always ‘off’ until you the user deliberately apply it.
Please don’t read this as running down Tinderbox’s capabilities. Rather, I see it as a useful example of where we step across from the simple (e.g. set colour of all past-due events to red) to the more complex and where an always-on approach can be intrusive to other aspects of use.