Repository navigation
fix(optimization): score the linkage from its initial position, over a full turn - #62
Conversation
…a full turn The kinematic_minimization / kinematic_maximization wrapper first sweeps one revolution in 12 long strides to reject the unbuildable early, then records the loci in a fine run — which started from wherever the coarse sweep had left the joints. A long stride can hop over a position the linkage cannot take, or onto the other assembly branch past a toggle, so the score certified a mechanism that raised UnbuildableError as soon as it was stepped from its initial position. PSO drives a design to the edge of buildability, so docs/examples/fourbar_linkage.py hit this on about half its runs and the "Executable docs" workflow with it. The fine run now restarts from the initial position. It also covers a complete revolution. It was 96 steps at dt=1 since 2021, whatever the crank speed: a quarter turn for the default crank of one degree per step, so a fitness read the locus of a quarter of the cycle. It keeps dt=1, the stride step() and the visualizers use, because which branch the solver follows past a toggle depends on the stride: a finer grid certifies a different mechanism. The example's crank now turns in a whole number of steps, so the 360-frame animation samples exactly the crank angles the fitness scored, and the example puts the linkage back in its initial position before animating the optimum, the position every particle was scored from. tests/docs/conftest.py reported a tutorial failure as a ValueError from relative_to() on the temporary script path, hiding the real traceback.
…ound Review of #62: set_coords() rewinds joint positions but not actuator state. An ArcCrank keeps _angle and _direction, a LinearActuator _extension and _direction, a Mechanism driver its current_angle, and none of them is derived from the joint's coordinates as a Crank's angle is. After the 12-stride sweep, the recorded run started with the actuator a full cycle ahead of joints put back at their start, which is neither the caller's run nor the old continuous one. There is no API to rewind an actuator, and the recorded run now covers the whole cycle, so the sweep has no job left: remove it and let the recorded run be the first thing that moves. The test now covers an ArcCrank too. The docstring and changelog state the cost of an evaluation: get_rotation_period() steps, at least 96.
|
Review turned up that Fixed by removing the 12-stride sweep altogether: the recorded run covers the whole cycle now, so the sweep had no job left, and there is no API to rewind an actuator. The test covers an Known limitation, pre-existing and unchanged here: across repeated evaluations, |
Unblocks #61, whose "Executable docs" job failed twice on
docs/examples/fourbar_linkage.py— as didmainright after the 1.2.2 merge (run 35321528470). Not a flake in the example: a bug in the fitness wrapper.kinematic_default_testscored a state the caller never gets. The wrapper sweeps one revolution in 12 long strides to reject the unbuildable early, then records the loci in a fine run — which started from wherever the coarse sweep had left the joints. A 0.5 rad stride can hop over a position the linkage cannot take, or onto the other assembly branch past a toggle, so the score certified a mechanism that raisedUnbuildableErroras soon as it was stepped from its initial position. PSO drives designs to the edge of buildability, so the example hit this on ~50% of runs. The fine run now restarts from the initial position; a new test checks its first frame is the first step frominit_pos.It also covers a complete revolution. It was
n = 96steps atdt=1since 2021 whatever the crank speed — a quarter turn for the default 1°/step crank, so a fitness read the locus of a quarter of the cycle. Nowmax(96, period)steps. It keepsdt=1, the stridestep()and the visualizers use: I tried a finer uniform grid over one turn and it certified different mechanisms (6/10 winners then failed at the natural stride), because which branch the solver follows past a toggle depends on the stride. Timings of the test suite and the docs tests are unchanged.The example gets a crank with a whole number of steps per turn (
tau / 20instead of0.31, period 20.27), so the 360-frame animation is 18 exact repeats of the phases the fitness scored, and resets the linkage to its initial position before animating the optimum. Probed over 10 PSO runs: fitness and 360-frame animation agree 10/10 (0/10 disagreed with the old code after the first fix alone, 8/10 before it). Ran the example 6× locally: 6/6.Also:
tests/docs/conftest.pyreported a tutorial failure as aValueErrorfromrelative_to()on the tmp path, hiding the real traceback.