Skip to main content

Coordinate-free circuit schematic engine: port-graph IR, deterministic geometry solver and router, lcapy renderer

Project description

lmschem

A coordinate-free circuit schematic engine. Authors describe a circuit as a port graph — components, electrical nets, relational placement — and a deterministic geometry engine places bodies, routes every wire, enforces hard drawing rules, and renders a PNG through lcapy/circuitikz. The same IR always yields the same drawing.

The complete authoring language reference is lmschem/rules.md — it is the only document an author needs, and it ships as package data.

Architecture (four layers)

PortGraph IR ──► geometry engine ──► renderer adapter ──► PNG
(portgraph/)     (geometry/solve,     (geometry/adapters/   
                  router, report)      lcapy.py)            
  1. Port-graph IR (portgraph/ir.py) — Pydantic models: components, nets, relational place anchors, rails/snaps, route hints, buses, decorations, blocks. No coordinates, ever.
  2. Geometry engine (geometry/) — deterministic placement (trunk-and-branch routing, channel assignment, facing-aware alignment), hard-rule checks with structured, fix-hinted issues, an ASCII occupancy grid, and solver-placed text (net labels, bus captions, decoration labels) backed by measured ink metrics.
  3. Renderer adapter (geometry/adapters/lcapy.py) — lowers the solved layout to an lcapy netlist with injected node positions (lcapy's placer is bypassed entirely) and verifies a real PNG came back. Emission is inventory-driven: bipoles, amps, chips/shapes, and the generic node-grammar path (node_pinnames slot order) cover every drawable class.
  4. Incremental edits (edit.py) — targeted IR edit operations with a flow-style YAML emitter that keeps files in the shape authors write.

Entry point:

from lmschem.author import author_circuit
result = author_circuit(ir_yaml_string, "out_dir")
# result: ok / report / grid / issues / image

The inventory contract

lmschem/inventory/*.yaml is the sole runtime authority for everything lcapy-specific: legal pin tokens, drawn subsets, pin aliases, netlist-node slot order (node_pinnames), measured body extents and pin coordinates, text metrics, decoration glyph ink, options, and the derived semantic vocabulary. Runtime never introspects lcapy.

The inventory is generated, never hand-edited (except components.yaml, schemcpts.yaml, options.yaml, placer.yaml, which are curated). Regenerate after any lcapy upgrade:

python -m lmschem.gen_inventory

This re-measures glyphs, rewrites the generated YAMLs, re-derives the semantic vocabulary (semantic_types.yaml), and re-splices the generated component reference into rules.md between its markers. lcapy is pinned exactly in pyproject.toml because the measurements are against that version.

Coverage contract: every drawable inventory class either solves and emits (guarded by tests/test_vocabulary_coverage.py, one param per class, no rendering) or sits on gen_inventory.EXCLUDED_CLASSES with a written reason (K, A, W, MISC, sV, sI). A new lcapy class becomes a failing test param until supported or excluded.

Tests

python -m pytest tests -q

Most tests render real PNGs through pdflatex + ghostscript — a TeX distribution and ghostscript must be on PATH. The solve+emit coverage guard and the geometry tests run without rendering.

lcapy quirks this engine works around (do not "simplify" these away)

  • LatexRunner.run never checks the pdflatex result and to_png_ghostscript never checks its output — the adapter verifies the PNG file itself and raises a structured error.
  • The opts parser splits on commas, so every label/value rides braced (l={...}); unbraced LaTeX with commas kills the compile silently.
  • A netlist with zero numeric nodes (all-unwired chips) crashes lcapy's canvas sizing — the adapter raises "nothing in the drawing is wired" first.
  • Uisoamp's class declares a phantom ocm pin its own draw rejects; gen_inventory._pins_for reads property-pin dicts from the class's own __dict__ only.
  • lcapy injection scales by node_spacing (2.0); gutters never move terminal segments.

Relationship to coursesmith

lmschem is standalone and speaks bare IR. Coursesmith integrates it through a thin adapter layer on its side (generator spec/executor, MCP edit tools, discovery): the generator-spec envelope, analysis requests, and example specs are coursesmith concepts and live there, not here.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lmschem-0.1.0.tar.gz (224.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lmschem-0.1.0-py3-none-any.whl (184.5 kB view details)

Uploaded Python 3

File details

Details for the file lmschem-0.1.0.tar.gz.

File metadata

  • Download URL: lmschem-0.1.0.tar.gz
  • Upload date:
  • Size: 224.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for lmschem-0.1.0.tar.gz
Algorithm Hash digest
SHA256 01896eb3c896e92745f18f64d1e72fb7d954a8911a794cfc1aff76b4abf38558
MD5 628d1cde1137035a13ac0e66181261c4
BLAKE2b-256 22ca25dc1400d5ea401b57eb728f0859899bf2a6190f8e1606079ab7c9d63e45

See more details on using hashes here.

File details

Details for the file lmschem-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: lmschem-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 184.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for lmschem-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 65ed4fbd2f536aa4013d35815a15bbe6a69d00b64281b760c06b5eb06ba85c2b
MD5 8edbd401c0adee50510ffa00ceee75ea
BLAKE2b-256 ecf43890c43c5c73d79c600e265cc769fa712743ce1617ee8eb2c7795b25510e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page