Skip to content

centaur-toolkit/centaur

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Centaur

CI

Centaur is a C++ prototype for symbolic analog-circuit analysis and topology rewriting. The goal is Herbie-like exploration for circuit structure: keep the input close to textbook circuits, infer useful equivalent forms, and produce readable expressions such as vdiv, par, and simplified Thevenin results.

Centaur currently focuses on linear DC/resistive circuits with independent and linear dependent sources. It combines three pieces:

  • a SPICE-like netlist parser
  • symbolic modified nodal analysis (MNA)
  • equality-saturation and topology rewrite passes

Status

Implemented today:

  • symbolic expressions with local simplification
  • egg-style e-graph rewrites for common analog forms
  • Thevenin equivalent calculation
  • operating-point node voltages, branch currents, powers, and source seen resistance
  • constraint solving for backward design queries, including inequality bounds, multiple equality roots, and coupled linear equality systems
  • topology rewrites for series/parallel resistors and ideal-source patterns
  • independent voltage/current sources
  • voltage-controlled voltage/current sources
  • current-controlled current sources using component current references
  • regression examples from Schaum Basic Circuit Analysis exercises 3.20-3.50, 3.52-3.90, and 4.1-4.67

This is still a prototype. The current solver is linear and DC-oriented; AC impedance forms are present in the expression rewrite layer, but not yet a full frequency-domain circuit frontend.

Build

cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
ctest --test-dir build --output-on-failure -R exercise_4_

The main executable is:

./build/centaur

Quick Examples

Optimize a symbolic expression:

./build/centaur '(mul Vin (div R2 (add R1 R2)))'

Output:

(vdiv Vin R1 R2)

Compute a Thevenin equivalent:

./build/centaur --thevenin examples/voltage_divider.cir out 0

Output:

Vth out 0: (vdiv Vin R1 R2)
Rth out 0: (par R1 R2)

Solve selected textbook quantities:

./build/centaur --solve examples/exercise_3_28.cir \
  --voltage a 0 \
  --current R9 \
  --current R13

Output:

V a 0: -35
I R9: 0
I R13: 0

Use --explain to see topology trace lines and expression rewrite activity:

./build/centaur --explain --solve examples/exercise_3_28.cir --voltage a 0

Infer an unknown resistance from a target equivalent resistance:

./build/centaur --solve-rth-for examples/exercise_3_35.cir a 0 R \
  '(eq Rth 12000)'

Output:

R: -15000

Netlist Format

The parser accepts a compact SPICE-like format:

Rname node+ node- value
Vname node+ node- value
Iname node+ node- value
Ename node+ node- ctrl+ ctrl- gain
Gname node+ node- ctrl+ ctrl- gain
Fname node+ node- control-component gain

Component meanings:

  • R: resistor
  • V: independent voltage source
  • I: independent current source
  • E: voltage-controlled voltage source
  • G: voltage-controlled current source
  • F: current-controlled current source

For F, the control is another component name. For example:

Fdep v1 0 R16 0.5

means:

I(Fdep from v1 to 0) = 0.5 * I(R16)

Values may be numeric atoms such as 10, or symbolic atoms such as R1, Vin, and gm.

Ground may be written as 0, gnd, or GND.

Commands

Solve an operating point:

./build/centaur --solve file.cir

With no explicit queries, Centaur prints node voltages relative to ground and resistor currents. With explicit queries, it prints only the requested values:

./build/centaur --solve file.cir \
  --voltage node+ node- \
  --current component \
  --power component \
  --seen-resistance Vsource

Compute a Thevenin equivalent:

./build/centaur --thevenin file.cir node+ node-

Solve a one-variable symbolic constraint:

./build/centaur --solve-for R '(eq (par 10000 20000 R) 12000)'

Inequality constraints are supported with lt/<, le/<=, gt/>, and ge/>=:

./build/centaur --solve-for R '(le (div (sub 15 12) (add R 0.3)) 2)'

Output:

R >= 1.2

Equalities may produce more than one discrete solution:

./build/centaur --solve-for R \
  '(eq (mul R (div 240 (add R 100)) (div 240 (add R 100))) 80)'

Output:

R: 20 or 500

Use circuit-derived values directly inside a constraint:

./build/centaur --solve-constraint examples/exercise_3_57.cir R

Output:

R >= 1.2

The netlist carries the observable inside the constraint:

.constraint (le (current Rlimit) 2)

The observable forms are (current component), (voltage node+ node-), (power component), and (rth node+ node-). Multiple .constraint lines are treated as a conjunction when a solve command asks for a variable; equality-only linear systems may contain additional intermediate variables.

Infer a value from a target Thevenin resistance:

./build/centaur --solve-rth-for file.cir node+ node- R '(eq Rth 12000)'

The Rth atom may appear anywhere in the constraint expression:

./build/centaur --solve-rth-for file.cir node+ node- R '(eq (inv Rth) 1.75)'

Run only the topology prepass:

./build/centaur --rewrite-topology file.cir protected-node ...

Protected nodes are observed terminals; the topology pass avoids removing or contracting them.

Topology Rewrites

Topology rewrites operate on the circuit graph before symbolic MNA. They are symbolic: resistor values such as R1 and R2 are preserved and combined into expressions such as (par R1 R2) and (add R1 R2).

Current rules:

  • parallel resistors with the same two terminals become one resistor with (par ...)
  • series resistors through an unprotected degree-2 node become one resistor with (add ...)
  • shorted resistors are removed
  • unprotected independent 0 V sources are removed by merging their two nodes
  • dangling resistor branches ending at unprotected nodes are removed
  • a resistor in series with an ideal current source is removed and the source is reconnected across the branch
  • a resistor in parallel with an ideal voltage source is removed

The solve path is query-aware. Explicit --voltage queries protect their nodes; explicit --current, --power, and --seen-resistance queries protect their components. This lets Centaur simplify the circuit for a Vab query while still keeping a resistor if the user asks for that resistor current.

Example:

./build/centaur --explain --rewrite-topology examples/exercise_3_28.cir a 0

The topology summary reports two current-source series resistor removals and one voltage-source parallel resistor removal. For ladder-style reductions, --explain also prints each topology rewrite step:

./build/centaur --explain --rewrite-topology examples/exercise_3_41.cir a 0

Example trace line:

series-resistors: R4 inner tail 4 + R8 tail right 8 through tail -> Rser2 inner right (add 4 8)

Expression Language

Expressions use s-expressions:

(add a b)
(sub a b)
(mul a b)
(div a b)
(neg a)
(inv a)
(par R1 R2 ...)
(vdiv Vin Rtop Rbot)
(zc C1)
(zl L1)

The rewrite rules include algebraic identities, parallel impedance forms, voltage-divider recognition, capacitor/inductor impedance forms, RC low-pass forms, and a common-source gain idiom.

Constraint queries are ordinary expressions:

(eq (par 10000 20000 R) 12000)
(eq Rth 12000)
(eq (inv Rth) 1.75)
(le (div (sub 15 12) (add R 0.3)) 2)
(lt (current Rlimit) 2)

Textbook Examples

The examples/ directory includes checked examples from Schaum Basic Circuit Analysis:

./build/centaur --solve examples/exercise_3_20.cir \
  --current R10 --current R25 --voltage top n15

./build/centaur --solve examples/exercise_3_26.cir \
  --voltage v1 0 --current R16 --current Fdep

./build/centaur --solve examples/exercise_3_28.cir \
  --voltage a 0 --current R9 --current R13

./build/centaur --solve-rth-for examples/exercise_3_35.cir \
  a 0 R '(eq Rth 12000)'

./build/centaur --solve-rth-for examples/exercise_3_36.cir \
  a 0 R '(eq (inv Rth) 1.75)'

./build/centaur --solve-constraint examples/exercise_3_57.cir R

./build/centaur --solve-constraint examples/exercise_3_58.cir R

./build/centaur --solve examples/exercise_3_59.cir \
  --power R2 --power R4 --power R6

./build/centaur --solve examples/exercise_3_60.cir --voltage a 0

./build/centaur --solve examples/exercise_3_60.cir \
  --voltage bottom_left bottom_mid

./build/centaur --solve examples/exercise_3_62.cir --voltage n5 n6

./build/centaur --solve examples/exercise_3_63.cir --current R2

./build/centaur --solve examples/exercise_3_64.cir \
  --voltage out_plus out_minus

./build/centaur --solve-constraint examples/exercise_3_65.cir I1
./build/centaur --solve-constraint examples/exercise_3_65.cir I2
./build/centaur --solve-constraint examples/exercise_3_65.cir I3
./build/centaur --solve-constraint examples/exercise_3_65.cir I4

./build/centaur --solve examples/exercise_3_66.cir --current V_I

./build/centaur --solve examples/exercise_3_67.cir --voltage out_top 0

./build/centaur '(par (add 4 4) 4)'

./build/centaur --solve-constraint examples/exercise_3_69.cir R

./build/centaur --thevenin examples/exercise_3_70.cir a 0

./build/centaur --solve-constraint examples/exercise_3_71.cir R

./build/centaur --solve-constraint examples/exercise_3_72.cir R

./build/centaur '(par (add (par 24 48) 24) 10)'

./build/centaur '(par (add (par 6 12) (par 10 40)) (add 6 2))'

./build/centaur --explain --rewrite-topology examples/exercise_3_75.cir a 0

./build/centaur --thevenin examples/exercise_3_75.cir a 0

./build/centaur --thevenin examples/exercise_3_76.cir a 0

./build/centaur --thevenin examples/exercise_3_77a.cir in 0

./build/centaur --thevenin examples/exercise_3_77b.cir in 0

./build/centaur --solve examples/exercise_3_78.cir --current R4 --current R6 --current R8 --current R12

./build/centaur --solve examples/exercise_3_79.cir --current R8 --current R12 --current R16 --current R24

./build/centaur --solve examples/exercise_3_80.cir --current R24_i1 --current R24_i2 --current R8_i3 --current R24_i4 --current R20_i5

./build/centaur --solve-constraint examples/exercise_3_81.cir R1

./build/centaur --solve-constraint examples/exercise_3_81.cir R2

./build/centaur --solve examples/exercise_3_82.cir --current R1

./build/centaur --solve examples/exercise_3_83.cir --current R10

./build/centaur --solve-constraint examples/exercise_3_84.cir R

./build/centaur --solve examples/exercise_3_85.cir --current R40

./build/centaur --solve-constraint examples/exercise_3_86.cir Vs

./build/centaur --solve examples/exercise_3_87.cir --current R70 --power Fdep

./build/centaur --solve examples/exercise_3_88.cir --voltage out 0

./build/centaur --solve examples/exercise_3_89a.cir --current Vload

./build/centaur --solve examples/exercise_3_89b.cir --current Rload

./build/centaur --solve examples/exercise_3_89c.cir --current Rload

./build/centaur --solve examples/exercise_3_90.cir --current R30

These are also covered by CTest.

Project Direction

Near-term work:

  • add more source-control forms, including current-controlled voltage sources
  • generalize constraints to multiple variables with a solver backend and verified observable lowering
  • improve symbolic linear solving to avoid floating-point artifacts
  • add typed symbols and dimensions
  • extend the frontend toward impedance-domain Z circuits
  • integrate c-spice as an optional parser/simulation frontend
  • grow the textbook regression suite into a rule-discovery harness

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors