From 5ef4893f03179ef171e80fed78463f11ba58ec05 Mon Sep 17 00:00:00 2001 From: asteri Date: Wed, 22 Apr 2026 11:45:35 +0200 Subject: [PATCH] update claude settings and wip DAG with SlotMap --- .claude/memory/MEMORY.md | 5 ++ .claude/memory/feedback_dag_no_const_leaf.md | 11 +++ .claude/memory/feedback_settings_approval.md | 11 +++ Cargo.lock | 16 ++++ Cargo.toml | 1 + examples/dag.rs | 26 ++++++ {src/bin => examples}/flat.rs | 0 src/circuit/dag.rs | 83 ++++++++++++++++++++ src/circuit/mod.rs | 1 + src/lib.rs | 1 + 10 files changed, 155 insertions(+) create mode 100644 .claude/memory/MEMORY.md create mode 100644 .claude/memory/feedback_dag_no_const_leaf.md create mode 100644 .claude/memory/feedback_settings_approval.md create mode 100644 examples/dag.rs rename {src/bin => examples}/flat.rs (100%) create mode 100644 src/circuit/dag.rs create mode 100644 src/circuit/mod.rs diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md new file mode 100644 index 0000000..e2645fa --- /dev/null +++ b/.claude/memory/MEMORY.md @@ -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 ` instead diff --git a/.claude/memory/feedback_dag_no_const_leaf.md b/.claude/memory/feedback_dag_no_const_leaf.md new file mode 100644 index 0000000..8281d13 --- /dev/null +++ b/.claude/memory/feedback_dag_no_const_leaf.md @@ -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. diff --git a/.claude/memory/feedback_settings_approval.md b/.claude/memory/feedback_settings_approval.md new file mode 100644 index 0000000..52f43ab --- /dev/null +++ b/.claude/memory/feedback_settings_approval.md @@ -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. diff --git a/Cargo.lock b/Cargo.lock index e13543d..8aba91a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 0170a05..22a911c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] itertools = "0.14.0" +slotmap = "1.1.1" diff --git a/examples/dag.rs b/examples/dag.rs new file mode 100644 index 0000000..a5d188c --- /dev/null +++ b/examples/dag.rs @@ -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); +} diff --git a/src/bin/flat.rs b/examples/flat.rs similarity index 100% rename from src/bin/flat.rs rename to examples/flat.rs diff --git a/src/circuit/dag.rs b/src/circuit/dag.rs new file mode 100644 index 0000000..7547db7 --- /dev/null +++ b/src/circuit/dag.rs @@ -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 { + Leaf(V), + Sum(NodeId, NodeId), + Prod(NodeId, NodeId), +} + +pub struct Circuit { + nodes: SlotMap>, + intern: HashMap, NodeId>, +} + +impl Circuit { + pub fn new() -> Self { + Circuit { + nodes: SlotMap::with_key(), + intern: HashMap::new(), + } + } + + pub fn node(&mut self, n: Node) -> 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> { + 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 { + pub id: NodeId, + circuit: Rc>>, +} + +pub trait CircuitExt { + fn leaf(&self, v: V) -> CircuitNode; +} + +impl CircuitExt for Rc>> { + fn leaf(&self, v: V) -> CircuitNode { + let id = self.borrow_mut().node(Node::Leaf(v)); + CircuitNode { id, circuit: self.clone() } + } +} + +impl Add for CircuitNode { + 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 Mul for CircuitNode { + 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 } + } +} diff --git a/src/circuit/mod.rs b/src/circuit/mod.rs new file mode 100644 index 0000000..f2884ca --- /dev/null +++ b/src/circuit/mod.rs @@ -0,0 +1 @@ +pub mod dag; diff --git a/src/lib.rs b/src/lib.rs index e37ef5d..c624ce1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod poly; +pub mod circuit; pub mod fmt;