3 Commits

Author SHA1 Message Date
forbes-0023
92ae57751f feat(solver): graph decomposition for cluster-by-cluster solving (phase 3)
Add a Python decomposition layer using NetworkX that partitions the
constraint graph into biconnected components (rigid clusters), orders
them via a block-cut tree, and solves each cluster independently.
Articulation-point bodies propagate as boundary conditions between
clusters.

New module kindred_solver/decompose.py:
- DOF table mapping BaseJointKind to residual counts
- Constraint graph construction (nx.MultiGraph)
- Biconnected component detection + articulation points
- Block-cut tree solve ordering (root-first from grounded cluster)
- Cluster-by-cluster solver with boundary body fix/unfix cycling
- Pebble game integration for per-cluster rigidity classification

Changes to existing modules:
- params.py: add unfix() for boundary body cycling
- solver.py: extract _monolithic_solve(), add decomposition branch
  for assemblies with >= 8 free bodies

Performance: for k clusters of ~n/k params each, total cost drops
from O(n^3) to O(n^3/k^2).

220 tests passing (up from 207).
2026-02-20 22:19:35 -06:00
forbes-0023
533ca91774 feat(solver): full constraint vocabulary — all 24 BaseJointKind types (phase 2)
Add 18 new constraint classes covering all BaseJointKind types from Types.h:
- Point: PointOnLine (2r), PointInPlane (1r)
- Orientation: Parallel (2r), Perpendicular (1r), Angle (1r)
- Surface: Concentric (4r), Tangent (1r), Planar (3r), LineInPlane (2r)
- Kinematic: Ball (3r), Revolute (5r), Cylindrical (4r), Slider (5r),
  Screw (5r), Universal (4r)
- Mechanical: Gear (1r), RackPinion (1r)
- Stubs: Cam, Slot, DistanceCylSph

New modules:
- geometry.py: marker axis extraction, vector ops (dot3, cross3, sub3),
  geometric primitives (point_plane_distance, point_line_perp_components)
- bfgs.py: L-BFGS-B fallback solver via scipy for when Newton fails

solver.py changes:
- Wire all 20 supported types in _build_constraint()
- BFGS fallback after Newton-Raphson in solve()

183 tests passing (up from 82), including:
- DOF counting for every joint type
- Solve convergence from displaced initial conditions
- Multi-body mechanisms (four-bar linkage, slider-crank, revolute chain)
2026-02-20 21:15:15 -06:00
forbes-0023
98051ba0c9 feat: add Phase 1 constraint solver addon, move prior content to GNN/
- Move existing OndselSolver, GNN ML layer, and tooling into GNN/
  directory for integration in later phases
- Add Create addon scaffold: package.xml, Init.py
- Add expression DAG with eval, symbolic diff, simplification
- Add parameter table with fixed/free variable tracking
- Add quaternion rotation as polynomial Expr trees
- Add RigidBody entity (7 DOF: position + unit quaternion)
- Add constraint classes: Coincident, DistancePointPoint, Fixed
- Add Newton-Raphson solver with symbolic Jacobian + numpy lstsq
- Add pre-solve passes: substitution + single-equation
- Add DOF counting via Jacobian SVD rank
- Add KindredSolver IKCSolver bridge for kcsolve integration
- Add 82 unit tests covering all modules

Registers as 'kindred' solver via kcsolve.register_solver() when
loaded by Create's addon_loader.
2026-02-20 20:35:47 -06:00
820 changed files with 6636 additions and 108 deletions

View File

@@ -2,9 +2,9 @@ name: CI
on:
push:
branches: [main, public]
branches: [main]
pull_request:
branches: [main, public]
branches: [main]
workflow_dispatch:
inputs:
run_datagen:
@@ -37,14 +37,14 @@ jobs:
env:
PATH: /tmp/solver-venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
steps:
- name: Checkout
- name: Trust internal CA
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git clone --depth 1 --branch "${GITHUB_REF_NAME}" \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE" \
|| git clone --depth 1 "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE"
cd "$GITHUB_WORKSPACE"
git checkout "$GITHUB_SHA" 2>/dev/null || true
curl -sk https://ipa.kindred.internal/ipa/config/ca.crt \
-o /usr/local/share/ca-certificates/kindred-internal.crt
update-ca-certificates
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Set up venv
run: python3 -m venv $VIRTUAL_ENV
@@ -66,23 +66,24 @@ jobs:
env:
PATH: /tmp/solver-venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
steps:
- name: Checkout
- name: Trust internal CA
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git clone --depth 1 --branch "${GITHUB_REF_NAME}" \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE" \
|| git clone --depth 1 "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE"
cd "$GITHUB_WORKSPACE"
git checkout "$GITHUB_SHA" 2>/dev/null || true
curl -sk https://ipa.kindred.internal/ipa/config/ca.crt \
-o /usr/local/share/ca-certificates/kindred-internal.crt
update-ca-certificates
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Set up venv
run: python3 -m venv $VIRTUAL_ENV
- name: Install dependencies
run: |
pip install --cache-dir $PIP_CACHE_DIR torch --index-url $TORCH_INDEX
pip install --cache-dir $PIP_CACHE_DIR \
mypy numpy scipy \
torch --index-url $TORCH_INDEX
pip install --cache-dir $PIP_CACHE_DIR torch-geometric
pip install --cache-dir $PIP_CACHE_DIR mypy numpy scipy
pip install --cache-dir $PIP_CACHE_DIR -e ".[dev]"
- name: Mypy
@@ -96,21 +97,22 @@ jobs:
env:
PATH: /tmp/solver-venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
steps:
- name: Checkout
- name: Trust internal CA
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git clone --depth 1 --branch "${GITHUB_REF_NAME}" \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE" \
|| git clone --depth 1 "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE"
cd "$GITHUB_WORKSPACE"
git checkout "$GITHUB_SHA" 2>/dev/null || true
curl -sk https://ipa.kindred.internal/ipa/config/ca.crt \
-o /usr/local/share/ca-certificates/kindred-internal.crt
update-ca-certificates
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Set up venv
run: python3 -m venv $VIRTUAL_ENV
- name: Install dependencies
run: |
pip install --cache-dir $PIP_CACHE_DIR torch --index-url $TORCH_INDEX
pip install --cache-dir $PIP_CACHE_DIR \
torch --index-url $TORCH_INDEX
pip install --cache-dir $PIP_CACHE_DIR torch-geometric
pip install --cache-dir $PIP_CACHE_DIR -e ".[train,dev]"
@@ -118,35 +120,45 @@ jobs:
run: pytest tests/ freecad/tests/ -v --tb=short
# ---------------------------------------------------------------------------
# Dataset generation — manual trigger or on main/public push
# Dataset generation — manual trigger or on main push
# ---------------------------------------------------------------------------
datagen:
runs-on: ubuntu-latest
if: >-
(github.event_name == 'workflow_dispatch' && inputs.run_datagen == true) ||
(github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/public'))
(github.event_name == 'push' && github.ref == 'refs/heads/main')
needs: [test]
env:
PATH: /tmp/solver-venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
steps:
- name: Checkout
- name: Trust internal CA
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git clone --depth 1 --branch "${GITHUB_REF_NAME}" \
"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE" \
|| git clone --depth 1 "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" "$GITHUB_WORKSPACE"
cd "$GITHUB_WORKSPACE"
git checkout "$GITHUB_SHA" 2>/dev/null || true
curl -sk https://ipa.kindred.internal/ipa/config/ca.crt \
-o /usr/local/share/ca-certificates/kindred-internal.crt
update-ca-certificates
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Set up venv
run: python3 -m venv $VIRTUAL_ENV
- name: Install dependencies
run: |
pip install --cache-dir $PIP_CACHE_DIR torch --index-url $TORCH_INDEX
pip install --cache-dir $PIP_CACHE_DIR \
torch --index-url $TORCH_INDEX
pip install --cache-dir $PIP_CACHE_DIR torch-geometric
pip install --cache-dir $PIP_CACHE_DIR -e ".[train]"
- name: Restore datagen checkpoint
id: datagen-cache
uses: https://github.com/actions/cache/restore@v4
with:
path: data/synthetic
key: datagen-${{ github.sha }}
restore-keys: |
datagen-
- name: Generate dataset
run: |
NUM=${INPUTS_NUM_ASSEMBLIES:-100000}
@@ -160,6 +172,23 @@ jobs:
INPUTS_NUM_ASSEMBLIES: ${{ inputs.num_assemblies }}
INPUTS_NUM_WORKERS: ${{ inputs.num_workers }}
- name: Save datagen checkpoint
if: always()
uses: https://github.com/actions/cache/save@v4
with:
path: data/synthetic
key: datagen-${{ github.sha }}
- name: Upload dataset
uses: https://github.com/actions/upload-artifact@v3
with:
name: synthetic-dataset
path: |
data/synthetic/index.json
data/synthetic/stats.json
data/synthetic/shards/
retention-days: 90
- name: Print summary
if: always()
run: |

Some files were not shown because too many files have changed in this diff Show More