Repository navigation
Combining systems compares the variables, and a loaded system holds the live ones - #486
Conversation
…he live ones Variables are canonical by name: Variable::Make interns, so the x made here and the x made there are one object. Two things contradicted that. An archive handed back variables that were not interned. Boost deserialization builds a node through its default constructor, never through Make, so copy.deepcopy, copy.copy, pickle and the MPI broadcast each returned a system content-equal to the original and sharing none of its nodes, which could not be concatenated with the system it was copied from. System and Slice now re-intern what they hold as the last step of loading. The repair existed (ReinternNodes, used by the records loader); it is in the load itself now, so no caller has to remember it. The operations that combine systems asked two different questions. Concatenate compared the variable orderings; MakeHomotopy, MakeMovingHomotopy and += compared counts, and evaluate their operands by position. Measured: moving rows over (y, x) blended with a fixed system over (x, y) were accepted, and y - 3 at (x, y) = (7, 11) evaluated to 4. All four now make one check, CheckVariableStructuresMatch, variable by variable, group by group, in order, and the refusal names both structures and says whether the order, the grouping or the variables differ. A system that declares no variables takes the variable structure of the one it is combined with (AdoptVariableStructure). In Python a node compares by identity: __eq__, __ne__ and __hash__ on the node wrappers compare the node. Each call across the binding makes a new wrapper, and the default == said two handles on one variable were different. Found on the way: System swap left out the auxiliary declarations, so a moved or assigned System lost them. It did not show while MakeHomotopy had a single return statement and the compiler elided the move; the adoption added a second. straight_line_homotopy accepts deep-copied operands as a result; it had refused what the builder beneath it accepted. Left alone on purpose: a function that mentions a variable no group holds, which waits for parameters. ADR-0068. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
this PR brings an imporatnt ability in Python -- x made twice, is the same x. and, systems that are loaded from pickel etc are combineable with those already in memory, when they use the same symbols. this is the hashconsing work i did in June and July coming back in winning form. I used Claude Fable to do that work, and it has made some UI issues in this library ... disappear. Verschwinden. |
ofloveandhate
left a comment
There was a problem hiding this comment.
The interning work is admittedly the part i least understand of this work. I am accepting it -- it clearly works correctly. I am doing my best to be diligent, and I accept responsibility for the correctness of this code. If it is incorrect in any way, I will do my best to promptly fix it. My dreams are big. I am reaching for them.
Stacked on #483 (
chore/housekeeping-for-4.0), so the diff shows only this work; it retargets todevelopwhen #483 merges.A loaded system holds the live variables.
Variable::Makeinterns variables by name, and the whole symbolic engine relies on that: makingxhere andxthere gives one node. Boost deserialization bypassedMake, so aSystemorSlicethat came through an archive, which is whatcopy.deepcopy,copy.copyandpickledo, held variables equal by name but distinct as objects. ASystemand aSlicenow re-intern their nodes as the last step of a load (the loader for records already did this throughReinternNodes), so a copied or unpickled system combines with its original. ADR-0068 records the decision; a new archivable class that holds nodes needs the same step.Combining systems makes one check.
Concatenatecompared variable orderings by object and refused the un-interned copies.MakeHomotopyandMakeMovingHomotopycompared counts only and accepted anything with the right number of variables, then blended block operands by position: a target over(x, y)and a start over(y, x)produced a homotopy that evaluatedy - 3at(7, 11)to 4. All four combining operations (Concatenate,MakeHomotopy,MakeMovingHomotopy,operator+=) now go throughCheckVariableStructuresMatch, which compares the ordering, the affine and projective groups, the ungrouped variables and the homogenizing variables, and says which kind of difference it found: the same variables in a different order, a different grouping, different variables, or the same names as different objects. A system that declares no variables adopts the other's structure, so building a system from functions alone and combining it still works.Python nodes compare by identity of the node.
__eq__,__ne__and__hash__on the node base compare the underlying pointer, soVariable('x') == Variable('x')holds and nodes can be dictionary keys; comparing with a non-node returnsNotImplemented.A latent bug the work exposed.
System::swapomitted the auxiliary variable groups and auxiliary coordinates. It surfaced whenMakeHomotopygained a second return value and the move stopped being elided. Fixed, with a test.Tests:
core/test/classes/system_identity_test.cpp,core/test/classes/auxiliary_coordinates_test.cpp,python/test/classes/clone_concatenate_test.py. The concatenate tutorial and the changelog describe the rule. Verified: all C++ suites, the Python suite (1160), the tutorial doctests (198), and the three lints. The cellular decomposition port, the most intensive user of the library, combines systems at dozens of sites and was refused nowhere.🤖 Generated with Claude Code