Skip to content

Commit f20a507

Browse files
rahulk29rohanku
andauthored
feat(gui): minimal support for coincident edge constraints (#39)
* wip * wip * use index maps/sets for determinism * feat(gui): minimal support for coincident edge constraints * basic dimension highlighting --------- Co-authored-by: Rohan Kumar <rohankumar@berkeley.edu>
1 parent e47c210 commit f20a507

File tree

6 files changed

+430
-35
lines changed

6 files changed

+430
-35
lines changed

core/compiler/src/compile.rs

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! Pass 1: assign variable IDs/type checking
44
//! Pass 3: solving
5-
use std::collections::{HashMap, HashSet, VecDeque};
5+
use std::collections::VecDeque;
66
use std::io::BufReader;
77
use std::path::Path;
88

@@ -62,8 +62,8 @@ fn check_layers(output: &CompileOutput) {
6262

6363
#[derive(Default)]
6464
pub(crate) struct VarIdTyFrame<'a> {
65-
var_bindings: HashMap<&'a str, (VarId, Ty)>,
66-
scope_bindings: HashSet<&'a str>,
65+
var_bindings: IndexMap<&'a str, (VarId, Ty)>,
66+
scope_bindings: IndexSet<&'a str>,
6767
}
6868

6969
pub(crate) struct VarIdTyPass<'a> {
@@ -113,12 +113,12 @@ pub struct FnTy {
113113
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
114114
pub struct CellFnTy {
115115
args: Vec<Ty>,
116-
data: HashMap<String, Ty>,
116+
data: IndexMap<String, Ty>,
117117
}
118118

119119
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
120120
pub struct CellTy {
121-
data: HashMap<String, Ty>,
121+
data: IndexMap<String, Ty>,
122122
}
123123

124124
impl AstMetadata for VarIdTyMetadata {
@@ -769,7 +769,7 @@ pub(crate) struct DynLoc {
769769

770770
#[derive(Clone)]
771771
struct Frame {
772-
bindings: HashMap<VarId, ValueId>,
772+
bindings: IndexMap<VarId, ValueId>,
773773
parent: Option<FrameId>,
774774
}
775775

@@ -805,9 +805,9 @@ struct CellState {
805805

806806
struct ExecPass<'a> {
807807
ast: &'a Ast<&'a str, VarIdTyMetadata>,
808-
cell_states: HashMap<CellId, CellState>,
809-
values: HashMap<ValueId, DeferValue<'a, VarIdTyMetadata>>,
810-
frames: HashMap<FrameId, Frame>,
808+
cell_states: IndexMap<CellId, CellState>,
809+
values: IndexMap<ValueId, DeferValue<'a, VarIdTyMetadata>>,
810+
frames: IndexMap<FrameId, Frame>,
811811
nil_value: ValueId,
812812
global_frame: FrameId,
813813
next_id: u64,
@@ -816,7 +816,7 @@ struct ExecPass<'a> {
816816
// The first element of this stack is the root cell.
817817
// the last element of this stack is the current cell.
818818
partial_cells: VecDeque<CellId>,
819-
compiled_cells: HashMap<CellId, CompiledCell>,
819+
compiled_cells: IndexMap<CellId, CompiledCell>,
820820
}
821821

822822
enum ExecScopeName {
@@ -830,9 +830,9 @@ impl<'a> ExecPass<'a> {
830830
pub(crate) fn new(ast: &'a Ast<&'a str, VarIdTyMetadata>) -> Self {
831831
Self {
832832
ast,
833-
cell_states: HashMap::new(),
834-
values: HashMap::from_iter([(1, DeferValue::Ready(Value::None))]),
835-
frames: HashMap::from_iter([(
833+
cell_states: IndexMap::new(),
834+
values: IndexMap::from_iter([(1, DeferValue::Ready(Value::None))]),
835+
frames: IndexMap::from_iter([(
836836
0,
837837
Frame {
838838
bindings: Default::default(),
@@ -843,7 +843,7 @@ impl<'a> ExecPass<'a> {
843843
global_frame: 0,
844844
next_id: 2,
845845
partial_cells: VecDeque::new(),
846-
compiled_cells: HashMap::new(),
846+
compiled_cells: IndexMap::new(),
847847
}
848848
}
849849

@@ -981,10 +981,20 @@ impl<'a> ExecPass<'a> {
981981
if state.nullspace_vecs.is_none() {
982982
state.nullspace_vecs = Some(state.solver.nullspace_vecs());
983983
}
984-
if let Some(expr) = state.fallback_constraints.pop() {
985-
state.fallback_constraints_used.push(expr.clone());
986-
state.solver.constrain_eq0(expr);
987-
} else {
984+
let mut constraint_added = false;
985+
while let Some(expr) = state.fallback_constraints.pop() {
986+
if expr
987+
.coeffs
988+
.iter()
989+
.any(|(c, v)| c.abs() > 1e-6 && !state.solver.is_solved(*v))
990+
{
991+
state.fallback_constraints_used.push(expr.clone());
992+
state.solver.constrain_eq0(expr);
993+
constraint_added = true;
994+
break;
995+
}
996+
}
997+
if !constraint_added {
988998
panic!("no progress");
989999
}
9901000
}
@@ -1050,11 +1060,11 @@ impl<'a> ExecPass<'a> {
10501060
};
10511061

10521062
let mut ccell = CompiledCell {
1053-
scopes: HashMap::new(),
1063+
scopes: IndexMap::new(),
10541064
root: state.root_scope,
10551065
fallback_constraints_used: state.fallback_constraints_used.clone(),
10561066
nullspace_vecs: state.nullspace_vecs.clone().unwrap_or_default(),
1057-
objects: HashMap::new(),
1067+
objects: IndexMap::new(),
10581068
};
10591069
fn add_scope(cell: &mut CompiledCell, state: &CellState, id: ScopeId, scope: &ExecScope) {
10601070
if cell.scopes.contains_key(&id) {
@@ -1472,7 +1482,7 @@ impl<'a> ExecPass<'a> {
14721482
}
14731483

14741484
fn eval_partial(&mut self, vid: ValueId) -> bool {
1475-
let v = self.values.remove(&vid);
1485+
let v = self.values.swap_remove(&vid);
14761486
if v.is_none() {
14771487
return false;
14781488
}
@@ -2213,9 +2223,9 @@ pub struct CompiledScope {
22132223

22142224
#[derive(Debug, Clone, Serialize, Deserialize)]
22152225
pub struct CompiledCell {
2216-
pub scopes: HashMap<ScopeId, CompiledScope>,
2226+
pub scopes: IndexMap<ScopeId, CompiledScope>,
22172227
pub root: ScopeId,
2218-
pub objects: HashMap<ObjectId, SolvedValue>,
2228+
pub objects: IndexMap<ObjectId, SolvedValue>,
22192229
pub fallback_constraints_used: Vec<LinearExpr>,
22202230
pub nullspace_vecs: Vec<Vec<f64>>,
22212231
}
@@ -2277,7 +2287,7 @@ pub struct StaticErrorCompileOutput {
22772287

22782288
#[derive(Debug, Clone, Serialize, Deserialize)]
22792289
pub struct ValidCompileOutput {
2280-
pub cells: HashMap<CellId, CompiledCell>,
2290+
pub cells: IndexMap<CellId, CompiledCell>,
22812291
pub top: CellId,
22822292
pub layers: LayerProperties,
22832293
}

core/compiler/src/solver.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use std::{collections::HashMap, time::Instant};
1+
use std::time::Instant;
22

33
use approx::relative_eq;
4+
use indexmap::IndexMap;
45
use itertools::{Either, Itertools};
56
use nalgebra::{DMatrix, DVector};
67
use ndarray_linalg::SVD;
@@ -15,10 +16,10 @@ pub struct Var(u64);
1516
pub struct Solver {
1617
next_id: u64,
1718
constraints: Vec<LinearExpr>,
18-
solved_vars: HashMap<Var, f64>,
19+
solved_vars: IndexMap<Var, f64>,
1920
}
2021

21-
pub fn substitute_expr(table: &HashMap<Var, f64>, expr: &mut LinearExpr) {
22+
pub fn substitute_expr(table: &IndexMap<Var, f64>, expr: &mut LinearExpr) {
2223
let (l, r): (Vec<f64>, Vec<_>) = expr.coeffs.iter().partition_map(|a @ (coeff, var)| {
2324
if let Some(s) = table.get(var) {
2425
Either::Left(coeff * s)
@@ -135,6 +136,10 @@ impl Solver {
135136
self.solved_vars.get(&var).copied()
136137
}
137138

139+
pub fn is_solved(&self, var: Var) -> bool {
140+
self.solved_vars.contains_key(&var)
141+
}
142+
138143
pub fn eval_expr(&self, expr: &LinearExpr) -> Option<f64> {
139144
Some(
140145
expr.coeffs

0 commit comments

Comments
 (0)