Changelog
All notable changes to pylinkage are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Added
Dual Annealing optimizer:
dual_annealing_optimization()wraps scipy’s generalized simulated annealing — a single-trajectory global optimizer effective for problems with many local minima and expensive evaluations.Optimizer chaining:
chain_optimizers()runs multiple optimizers in sequence, automatically feeding each result as the starting point for the next stage. Common pattern: global search (DE/PSO) → local refinement (Nelder-Mead).Co-optimization of topology + dimensions:
Mixed-variable evolutionary optimizer (
co_optimize()) jointly searching discrete topology space and continuous dimensional space using NSGA-II/III via pymoo with custom genetic operators.Topology neighborhood graph (
build_neighborhood_graph(),topology_neighbors(),topology_distance()) defining adjacency between all 19 catalog topologies via add_dyad, remove_dyad, swap_variant, and restructure operations.Custom pymoo operators:
MixedCrossover(BLX-alpha blend + topology swap),MixedMutation(Gaussian perturbation + topology neighbor mutation),warm_start_sampling()(seed population from Phase 3 synthesis results).Virtual edge encoding: expands hyperedges (ternary links) into pairwise distances and adds implicit ground-link virtual edges for chromosome representation.
Simultaneous triad placement via
scipy.optimize.least_squaresfor topologies with circular dependencies (e.g., Stephenson six-bar).Warm-start pipeline:
warm_start_co_optimization()converts Phase 3TopologySolutionresults toMixedChromosomeseeds for NSGA-II.New types:
MixedChromosome,CoOptimizationConfig,CoOptSolution,CoOptimizationResult.TopologyCatalog.topology_index()andtopology_by_index()for integer-indexed topology lookup.
Triad solving in mechanism simulation:
Mechanism.step()now uses Assur group decomposition internally, solving dyads and triads viasolve_group()dispatch. Six-bar linkages (Watt and Stephenson types) can be simulated end-to-end.graph_to_mechanism()handles triad groups (2 internal nodes, 4+ edges), creating the appropriate joints and links.Topology enumeration:
Graph isomorphism detection via WL-1 color refinement + backtracking verification:
canonical_form(),canonical_hash(),are_isomorphic().Systematic enumeration of all non-isomorphic 1-DOF planar linkage topologies up to 8 links:
enumerate_topologies(),enumerate_all(). Validated against Mruthyunjaya 1984: 1 four-bar + 2 six-bars + 16 eight-bars = 19.Built-in topology catalog (
TopologyCatalog,CatalogEntry,load_catalog()) with JSON-serializedHypergraphLinkagegraphs and metadata (link assortment, family, joint count).All new symbols exported from
pylinkage.topology.
Fixed
compute_dofhyperedge counting:compute_mobility()counted each hyperedge with k nodes as (k−1) links instead of 1 rigid body, giving wrong DOF for any mechanism with ternary or higher links (all six-bars and eight-bars).
Changed
PSO is now pure NumPy:
particle_swarm_optimization()no longer depends on pyswarms (unmaintained since 2021). Replaced with a built-in local-best ring-topology PSO. Thepsooptional extra is kept but empty for backwards compatibility. The API is unchanged.
Removed
pyswarms dependency removed from all extras (
pso,full, dev group).
[0.8.0] - 2026-03-28
Added
Multi-objective optimization:
New
multi_objective_optimization()function using NSGA-II/NSGA-III algorithms via pymoo.ParetoFrontclass for storing and analyzing non-dominated solutions.ParetoSolutiondataclass for individual Pareto-optimal solutions.Pareto front visualization with
pareto.plot().Hypervolume indicator computation with
pareto.hypervolume().Best compromise solution selection with
pareto.best_compromise().Crowding distance-based filtering with
pareto.filter().New optional dependency group:
pip install pylinkage[moo].
Cam-follower mechanisms:
New
pylinkage.cammodule with motion laws and profile definitions.Motion laws:
HarmonicMotionLaw,CycloidalMotionLaw,ModifiedTrapezoidalMotionLaw,PolynomialMotionLaw(withpolynomial_345()andpolynomial_4567()factory functions).Profile types:
FunctionProfile(motion law-based) andPointArrayProfile(spline interpolation).TranslatingCamFollowerdyad for linear follower motion driven by cam rotation.OscillatingCamFollowerdyad for rocker arm motion driven by cam rotation.Both knife-edge (roller_radius=0) and roller followers supported.
Numba-compiled profile evaluation for high-performance simulation.
Triad (Class II) Assur groups:
New
DyadandTriadclasses parameterized by signature string, replacing the per-type classes (DyadRRR,DyadRRP, etc.) which are kept as aliases.signature_to_hypergraph()now generates triad topologies (6-joint signatures).decompose_assur_groups()detects triads when no dyad can be formed, enabling decomposition of six-bar mechanisms (Watt and Stephenson types).Solver dispatches by
solver_category(circle-circle, circle-line, line-line) instead ofisinstance(), automatically supporting new group signatures.
Topology analysis:
New
pylinkage.topologymodule withcompute_dof()implementing Grübler’s formula (DOF = 3(n−1) − 2j₁ − j₂) onHypergraphLinkage.compute_mobility()returns fullMobilityInfo(DOF, link count, joint counts).
SymPy for analytical optimization.
Native computation of velocity and acceleration with visualizations.
Linkage synthesis with Burgmester’s theory, function, path and motion generation.
Adds scipy.
Exact optimization solving (better than numpy) + support constraints.
Adds a new optimization: differential evolution.
High-level velocity/acceleration API:
Component.velocityandComponent.accelerationproperties on all components.simulation.Linkage.set_input_velocity(actuator, omega, alpha)to set crank angular velocity.simulation.Linkage.step_with_derivatives()generator yielding (positions, velocities, accelerations).simulation.Linkage.get_velocities()andget_accelerations()batch query methods.solver.step_single_acceleration()numba-compiled acceleration solver.Exported acceleration solvers:
solve_crank_acceleration,solve_revolute_acceleration,solve_fixed_acceleration,solve_prismatic_acceleration.
Fixed
PSO score sign:
particle_swarm_optimization()returned the negated pyswarms cost whenorder_relation=max, producing incorrect (often negative) scores.Mechanism builder branch selection:
MechanismBuilder.set_branch()produced inconsistent assembly configurations because circle-circle constraints arrived in non-deterministic order depending on which connected port was solved first. Constraints are now sorted by center position before intersection, making branch 0/1 deterministic.
Changed
Breaking: Dropped Python 3.9 support. Minimum version is now Python 3.10.
Added Python 3.14 to CI test matrix.
Breaking:
Linkage.step_fast_with_kinematics()now returns a 3-tuple(positions, velocities, accelerations)instead of 2-tuple.Breaking:
LinearActuator.velocityattribute renamed toLinearActuator.speedto avoid conflict with the newComponent.velocityproperty.simulate_with_kinematics()now computes accelerations in addition to velocities.
[0.7.0] - 2025-12-13
Added in 0.7.0
Serialization: adds linkage serialization features.
Typing: adds typing.
Test: adds complete testing coverage.
Adds support for Python 3.14.
Hypergraph as the base theory for linkages.
Changed in 0.7.0
Switches to
uv.Renames
HypostaticErrortoUnderconstrainedErrorandhyperstaticity()toindeterminacy(). Old names kept as deprecated aliases.Separate linkage definition from actual solving:
The internal solver is now numba + NumPy, almost 100x faster!
The user-facing code is now based on Assur groups, that is more formal.
Fixed in 0.7.0
__find_solving_order__()is now properly tested and implemented (#16).
Deprecated in 0.7.0
Linearjoint term is now deprecated in favor ofPrismatic.
Removed in 0.7.0
Removed support for Python 3.9.
[0.6.0] - 2024-10-02
Added in 0.6.0
New joint: the
Linearjoint!New sub-package: optimization.collections.
optimization.collections.Agentandoptimization.collections.MutableAgentare two new classes that should standardize the format of optimization, related to (#5).Agentis immutable and inherits from a namedtuple. It is recommended to use it, as it is a bit faster.MutableAgentis mutable. It may be deprecated/removed ifAgentis satisfactory.
New sub-package: geometry.
It introduces two new functions
line_from_pointsandcircle_line_intersection.
New examples:
examples/strider.pyfrom leggedsnake, based on the Strider Linkage.examples/inverted_stroke_engine.pyis a demo of a four-stroke engine featuring a Linear joint.
Linkage.set_completelyis a new method combining bothLinkage.set_num_constraintsandLinkage.set_coords.New exception
NotCompletelyDefinedError, when a joint is reloading but its anchor coordinates are set to None.Some run configuration files added for users of PyCharm:
Run all tests with “All Tests”.
Regenerate documentation with “Sphinx Documentation”.
Changed in 0.6.0
Optimization return type changed (#5):
trials_and_error_optimizationreturn an array ofMutableAgent.particle_swarm_optimizationreturn an array of oneAgent.It should not be a breaking change for most users.
Changes to the “history” style.
It is no longer a global variable in example scripts.
It was in format iterations[dimensions, score], now it is a standard iterations[score, dimensions, initial pos].
repr_polar_swarm(in example scripts) changed to follow the new format.swarm_tiled_reprtakes (index, swarm) as input argument. swarm is (score, dim, pos) for each agent for this iteration.
repr_polar_swarmreload frame only when a new buildable linkage is generated.This makes the display much faster.
For each iteration, you may see linkages that do not exist anymore.
Folders reorganization:
The
geometrymodule is now a package (pylinkage/geometry)New package
pylinkage/linkage:pylinkage/linkage.pyseparated and inserted in this package.
New package:
pylinkage/jointsJoints definition are in respective files.
New package
pylinkage/optimization/pylinkage/optimizer.pysplit and inserted in.Trials-and-errors related functions goes to
grid_search.py.Particle swarm optimization is at
particle_swarm.py.New file
utils.pyforgenerate_bounds.
Tests follow the same renaming.
From the user perspective, no change (execution may be a bit faster)
source/renamed tosphinx/because it was confusing and only for Sphinx configuration.
Transition from Numpydoc to reST for docstrings (#12).
__secant_circles_intersections__renamed tosecant_circles_intersections(inpylinkage/geometry/secants.py).
Fixed in 0.6.0
swarm_tiled_reprinvisualizer.pywas wrongly assigning dimensions.Setting
locus_highlightinplot_static_linkagewould result in an error.Pivot.reloadwas returning arbitrary point when we had an infinity of solutions.The highlighted locus was sometimes buggy in
plot_static_linkageinvisualizer.py.
Deprecated in 0.6.0
Using
tqdm_verbosityis deprecated in favor of usingdisable=Truein a tqdm object.The
Pivotclass is deprecated in favor of theRevoluteclass. The name “Pivot joint” is not standard. Related to #13.The
hyperstaticitymethod is renamedindeterminacyinLinkage(linkage.py)
Removed in 0.6.0
Drops support for Python 3.7 and 3.8 as both versions reached end-of-life.
movement_bounding_bowis replaced bymovement_bounding_box(typo in function name).
[0.5.3] - 2023-06-23
Added in 0.5.3
We now checked compatibility with Python 3.10 and 3.11.
pyproject.tomlis now the official definition of the package.Linkage.hyperstaticitynow clearly outputs a warning when used.
Changed in 0.5.3
masterbranch is nowmain.docs/example/fourbar_linkage.pycan now be used as a module (not the target but anyway).docs/examplesmoved toexamples/(main folder).Now
docs/only contains sphinx documentation.
docs/examples/imagesmoved toimages/.
Fixed in 0.5.3
Setting a motor with a negative rotation angle do no longer break
get_rotation_period(#7).Pivot.reloadandLinkage.__find_solving_order__were raising Warnings (stopping the code), when they should only print a message (intended behavior).Fixed many typos in documentation as well as in code.
The
TestPSO.test_convergenceis now faster on average, and when it fails in the first time, it launches a bigger test.Minor linting in the demo file
docs/example/fourbar_linkage.py.
Deprecated in 0.5.3
Using Python 3.7 is officially deprecated (end of life by 2023-06-27). It will no longer be tested, use it at your own risks!
[0.5.2] - 2021-07-21
Added in 0.5.2
You can see the best score and best dimensions updating in
trials_and_errors_optimization.
Changed in 0.5.2
The optimizer tests are 5 times quicker (~1 second now) and raise less false positive.
The sidebar in the documentation makes navigation easier.
A bit of reorganization in optimizers, it should not affect users.
[0.5.1] - 2021-07-14
Added in 0.5.1
The trial and errors optimization now have a progress bar (same kind of the one in particle swarm optimization), using tqdm.
Changed in 0.5.1
matplotlib and tqdm now required.
[0.5.0] - 2021-07-12
End of alpha development! The package is now robust enough to be used by a mere human. This version introduces a lot of changes and simplifications, so everything is not perfect yet, but it is complete enough to be considered a beta version.
Git tags will no longer receive an “-alpha” mention.
Added in 0.5.0
It is now possible and advised to import useful functions from pylinkage.{object}, without full path. For instance, use
from pylinkage import Linkageinstead offrom pylinkage.linkage import Linkage.Each module had his header improved.
The
generate_boundsfunctions is a simple way to generate bounds before optimization.The
order_relationarguments ofparticle_swarm_optimizationandtrials_and_errors_optimizationlet you choose between maximization and minimization problem.You can specify a custom order relation with
trials_and_errors_optimization.The
verboseargument in optimizers can disable verbosity.Staticjoints can now be defined implicitly.The
utilitymodule provides two useful decoratorskinematic_minimizationandkinematic_optimizatino. They greatly simplify the workflow of defining fitness functions.Versioning is now done thanks to bump2version.
Changed in 0.5.0
The
particle_swarm_optimizationeval_funcsignature is now similar to the one ottrials_and_errorsoptimization. Wrappers are no longer needed!The
trials_and_errors_optimizationfunction now asks for bounds instead of dilatation and compression factors.In
trials_and_errors_optimizationabsolute stepdelta_dimis now replaced by number of subdivisionsdivisions.
Fixed in 0.5.0
After many hours of computations, default parameters in
particle_swarm_optimizationare much more efficient. With the demofourbar_linkage, the output wasn’t even convergent sometimes. Now we have a high convergence rate (~100%), and results equivalent to thetrials_and_errors_optimization(in the example).variatorfunction ofoptimizermodule was poorly working.The docstrings were not displayed properly in documentation, this is fixed.
[0.4.1] - 2021-07-11
Added in 0.4.1
The legend in
visualizer.pyis back!Documentation published to GitHub pages! It is contained in the
docs/folder.setup.cfgnow include links to the website.
Changed in 0.4.1
Examples moved from
pylinkage/examples/todocs/examples/.Tests moved from
pylinkage/tests/totests/.
[0.4.0] - 2021-07-06
Added in 0.4.0
The
bounding_boxmethod of geometry allows computing the bounding box of a 2D points finite set.You can now customize colors of linkage’s bars with the
COLOR_SWITCHERvariable ofvisualizer.py.movement_bounding_boxinvisualizer.pyto get the bounding box of multiple loci.parametersis optional intrials_and_errors_optimization(formerexhaustive_optimization)pylinkage/tests/test_optimizer.pyfor testing the optimizers, but it is a bit ugly as for now.Flake8 validation in
tox.ini
Fixed in 0.4.0
set_num_constraintsinLinkagewas misbehaving due to update 0.3.0.Cost history is no longer plotted automatically after a PSO.
Changed in 0.4.0
exhaustive_optimizationis now known astrials_and_errors_optimizattion.Axes on linkage visualization are now named “x” and “y”. It was “Points abcsices” and “Ordinates”.
A default view of the linkage is displayed in
plot_static_linkage.Default padding in linkage representation was changed from an absolute value of 0.5 to a relative 20%.
Static view of linkage is now aligned with its kinematic one.
get_posmethod ofLinkageis now known asget_coordsfor consistency.Parameters renamed, reorganized and removed in
particle_swarm_optimizationto align to PySwarms.README.mdupdated consequently to the changes.
Removed in 0.4.0
Legacy built-in Particle Swarm Optimization, to avoid confusion.
We do no longer show a default legend on static representation.
[0.3.0] - 2021-07-05
Added in 0.3.0
Jointobjects now have aget_constraintsmethod, consistent with theirset_constraintsone.Linkagenow has aget_num_constraintsmethod as syntactic sugar.Code vulnerabilities checker
Walkthrough’s example has been expanded and now seems to be complete.
Changed in 0.3.0
Linkage’s methodset_num_constraintsbehaviour changed! You should now addflat=Falseto come back to the previous behavior.pylinkage/examples/fourbar_linkage.pyexpanded and finished.The
beginparameter ofarticle_swarm_optimizationis no longer mandatory.linkage.get_num_constraints()will be used ifbeginis not provided.More flexible package version in
environment.ymlOutput file name now is formatted as “Kinematic {linkage.name}” in
plot_kinematic_linkagefunction ofpylinkage/visualizer.pyPython 3.6 is no longer tested in
tox.ini. Python 3.9 is now tested.
Fixed in 0.3.0
When linkage animation was saved, last frames were often missing in
pylinkage/visualizer.py, functionplot_kinematic_linkage.
[0.2.2] - 2021-06-22
Added in 0.2.2
More continuous integration workflows for multiple Python versions.
Fixed in 0.2.2
README.mdcould not be seen in PyPi.Various types
[0.2.1] - 2021-06-16
Added in 0.2.1
swarm_tiled_reprfunction forpylinkage/visualizer.py, for visualization of PySwarms.EXPERIMENTAL!
hyperstaticitymethodLinkage’s hyperstaticity (over constrained) calculation.
Changed in 0.2.1
pylinkage/exception.pynow handles exceptions in another file.Documentation improvements.
Python style improvements.
.gitignorenow modified from the standard GitHub gitignore example for Python.
Fixed in 0.2.1
circlemethod ofPivotinpylinkage/linkage.py. It was causing errorstox.ininow fixed.
[0.2.0] - 2021-06-14
Added in 0.2.0
pylinkage/vizualizer.pyview your linkages using matplotlib!Issue templates in
.github/ISSUE_TEMPLATE/.github/workflows/python-package-conda.yml: conda tests with unittest workflow.CODE_OF_CONDUCT.mdMANIFEST.inREADME.mdenvironment.ymlsetup.cfgnow replacessetup.pytox.iniCHANGELOG.md
Changed in 0.2.0
.gitignorePython Package specific extensions addedMIT License→LICENSElib/→pylinkage/tests/→pylinkage/tests/Revamped package organization.
Cleared
setup.py
[0.0.1] - 2021-06-12
Added in 0.0.1
lib/geometry.pyas a mathematical basis for kinematic optimizationlib/linkage.py, linkage builderlib/optimizer.py, with Particle Swarm Optimization (built-in and PySwarms), and exhaustive optimization.MIT License.requirements.txt.setup.py.tests/__init__.py.tests/test_geometry.py.tests/test_linkage.py..gitignore.