update claude settings and wip DAG with SlotMap

This commit is contained in:
2026-04-22 11:45:35 +02:00
parent 345bc0f126
commit 5ef4893f03
10 changed files with 155 additions and 0 deletions

5
.claude/memory/MEMORY.md Normal file
View File

@@ -0,0 +1,5 @@
# Memory Index
- [No constant leaf in RcCircuit](feedback_dag_no_const_leaf.md) — coefficients live in Poly; don't suggest a Const variant for RcCircuit
- [Always ask before changing settings](feedback_settings_approval.md) — describe proposed settings changes and wait for approval before editing any settings file
- [Use cargo add for dependencies](feedback_cargo_add.md) — never edit Cargo.toml directly; use `cargo add <dep>` instead

View File

@@ -0,0 +1,11 @@
---
name: No constant leaf in RcCircuit
description: User does not want a Const leaf variant in RcCircuit — coefficients belong in Poly, not in the circuit DAG
type: feedback
originSessionId: 4c73b3be-dd4d-4cc5-ae2c-da7af42d444b
---
Do not suggest adding a `Const` (or constant) leaf variant to `RcCircuit` in `src/circuit/dag.rs`.
**Why:** Coefficients are handled at the `Poly` layer. The circuit DAG only encodes structural/symbolic relationships between variables.
**How to apply:** When reviewing or extending `RcCircuit`, treat the absence of a constant leaf as intentional design, not a gap.

View File

@@ -0,0 +1,11 @@
---
name: Always ask before changing settings
description: Never modify any Claude settings files without explicit user approval first
type: feedback
originSessionId: 4c73b3be-dd4d-4cc5-ae2c-da7af42d444b
---
Always ask the user for approval before modifying any settings file (`~/.claude/settings.json`, `.claude/settings.json`, `.claude/settings.local.json`).
**Why:** The user wants full control over their Claude configuration and does not want settings changed autonomously.
**How to apply:** Before any settings change, explicitly describe what you intend to change and wait for the user to confirm. This applies even when the user's request implies a settings change — describe the proposed edit first, then wait.

16
Cargo.lock generated
View File

@@ -7,6 +7,7 @@ name = "circuit-cas"
version = "0.1.0"
dependencies = [
"itertools",
"slotmap",
]
[[package]]
@@ -23,3 +24,18 @@ checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
dependencies = [
"either",
]
[[package]]
name = "slotmap"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
dependencies = [
"version_check",
]
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"

View File

@@ -5,3 +5,4 @@ edition = "2024"
[dependencies]
itertools = "0.14.0"
slotmap = "1.1.1"

26
examples/dag.rs Normal file
View File

@@ -0,0 +1,26 @@
use std::cell::RefCell;
use std::rc::Rc;
use circuit_cas::circuit::dag::{Circuit, CircuitExt};
use circuit_cas::var;
fn main() {
let circuit = Rc::new(RefCell::new(Circuit::new()));
// Build (x + y) * (x + z)
let x = circuit.leaf(var!("x"));
let y = circuit.leaf(var!("y"));
let z = circuit.leaf(var!("z"));
let x_plus_y = circuit.leaf(var!("x")) + y;
let x_plus_z = circuit.leaf(var!("x")) + z;
let expr = x_plus_y * x_plus_z;
// Deduplication: both x leaves share the same NodeId
let x2 = circuit.leaf(var!("x"));
assert_eq!(x.id, x2.id);
println!("(x + y) * (x + z) root node id: {:?}", expr.id);
println!("x node id: {:?}", x.id);
println!("x deduplicated node id: {:?}", x2.id);
}

83
src/circuit/dag.rs Normal file
View File

@@ -0,0 +1,83 @@
use slotmap::{new_key_type, SlotMap};
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::{Add, Mul};
use std::rc::Rc;
use crate::poly::var::Var;
new_key_type! { pub struct NodeId; }
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Node<V: Var> {
Leaf(V),
Sum(NodeId, NodeId),
Prod(NodeId, NodeId),
}
pub struct Circuit<V: Var> {
nodes: SlotMap<NodeId, Node<V>>,
intern: HashMap<Node<V>, NodeId>,
}
impl<V: Var> Circuit<V> {
pub fn new() -> Self {
Circuit {
nodes: SlotMap::with_key(),
intern: HashMap::new(),
}
}
pub fn node(&mut self, n: Node<V>) -> NodeId {
if let Some(&id) = self.intern.get(&n) {
return id;
}
let id = self.nodes.insert(n.clone());
self.intern.insert(n, id);
id
}
pub fn get(&self, id: NodeId) -> Option<&Node<V>> {
self.nodes.get(id)
}
pub fn remove(&mut self, id: NodeId) {
if let Some(node) = self.nodes.remove(id) {
self.intern.remove(&node);
}
}
}
pub struct CircuitNode<V: Var> {
pub id: NodeId,
circuit: Rc<RefCell<Circuit<V>>>,
}
pub trait CircuitExt<V: Var> {
fn leaf(&self, v: V) -> CircuitNode<V>;
}
impl<V: Var> CircuitExt<V> for Rc<RefCell<Circuit<V>>> {
fn leaf(&self, v: V) -> CircuitNode<V> {
let id = self.borrow_mut().node(Node::Leaf(v));
CircuitNode { id, circuit: self.clone() }
}
}
impl<V: Var> Add for CircuitNode<V> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
let id = self.circuit.borrow_mut().node(Node::Sum(self.id, rhs.id));
CircuitNode { id, circuit: self.circuit }
}
}
impl<V: Var> Mul for CircuitNode<V> {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
let id = self.circuit.borrow_mut().node(Node::Prod(self.id, rhs.id));
CircuitNode { id, circuit: self.circuit }
}
}

1
src/circuit/mod.rs Normal file
View File

@@ -0,0 +1 @@
pub mod dag;

View File

@@ -1,2 +1,3 @@
pub mod poly;
pub mod circuit;
pub mod fmt;