Skip to content

Commit 75432fe

Browse files
authored
Merge pull request #725 from ToposInstitute/stable-elem-order
Ensure stable order of object/morphism generators and plot variables
2 parents 3dd40af + 65ab832 commit 75432fe

File tree

7 files changed

+37
-38
lines changed

7 files changed

+37
-38
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/catlog-wasm/src/model.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -446,25 +446,21 @@ impl DblModel {
446446
/// Returns the object generators for the model.
447447
#[wasm_bindgen(js_name = "obGenerators")]
448448
pub fn ob_generators(&self) -> Vec<QualifiedName> {
449-
let mut ob_gens: Vec<_> = all_the_same!(match &self.model {
449+
all_the_same!(match &self.model {
450450
DblModelBox::[Discrete, DiscreteTab, Modal](model) => {
451451
model.ob_generators().collect()
452452
}
453-
});
454-
ob_gens.sort(); // Ensure stable order in frontend.
455-
ob_gens
453+
})
456454
}
457455

458456
/// Returns the morphism generators for the model.
459457
#[wasm_bindgen(js_name = "morGenerators")]
460458
pub fn mor_generators(&self) -> Vec<QualifiedName> {
461-
let mut mor_gens: Vec<_> = all_the_same!(match &self.model {
459+
all_the_same!(match &self.model {
462460
DblModelBox::[Discrete, DiscreteTab, Modal](model) => {
463461
model.mor_generators().collect()
464462
}
465-
});
466-
mor_gens.sort(); // Ensure stable order in frontend.
467-
mor_gens
463+
})
468464
}
469465

470466
/// Returns the object generators of the given object type.

packages/catlog-wasm/src/model_diagram.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -171,27 +171,23 @@ impl DblModelDiagram {
171171
/// Returns the object generators for the diagram's indexing model.
172172
#[wasm_bindgen(js_name = "obGenerators")]
173173
pub fn ob_generators(&self) -> Vec<QualifiedName> {
174-
let mut ob_gens: Vec<_> = all_the_same!(match &self.diagram {
174+
all_the_same!(match &self.diagram {
175175
DblModelDiagramBox::[Discrete](diagram) => {
176176
let (_, model) = diagram.into();
177177
model.ob_generators().collect()
178178
}
179-
});
180-
ob_gens.sort();
181-
ob_gens
179+
})
182180
}
183181

184182
/// Returns the morphism generators for the diagram's indexing model.
185183
#[wasm_bindgen(js_name = "morGenerators")]
186184
pub fn mor_generators(&self) -> Vec<QualifiedName> {
187-
let mut mor_gens: Vec<_> = all_the_same!(match &self.diagram {
185+
all_the_same!(match &self.diagram {
188186
DblModelDiagramBox::[Discrete](diagram) => {
189187
let (_, model) = diagram.into();
190188
model.mor_generators().collect()
191189
}
192-
});
193-
mor_gens.sort();
194-
mor_gens
190+
})
195191
}
196192

197193
/// Returns the object generators of the given object type.

packages/catlog/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ egglog = { version = "0.5", default-features = false }
2020
ego-tree = "0.10"
2121
instant = { version = "0.1", optional = true } # Needed for egglog v0.5
2222
fnotation = "0.8.1"
23-
indexmap = "2.11.1"
23+
indexmap = "2.11"
2424
itertools = "0.14"
2525
nalgebra = { version = "0.33", optional = true }
2626
nonempty = "0.12"

packages/catlog/src/zero/set.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ This module provides interfaces and simple wrapper types to enable sets to be
44
treated in a generic way.
55
*/
66

7+
use std::hash::Hash;
78
use std::ops::Range;
8-
use std::{collections::HashSet, hash::Hash};
99

1010
use derivative::Derivative;
1111
use derive_more::{From, Into};
12+
use indexmap::IndexSet;
1213
use ref_cast::RefCast;
1314
use ustr::Ustr;
1415

@@ -116,12 +117,17 @@ impl IntoIterator for SkelFinSet {
116117
}
117118
}
118119

119-
/// A finite set backed by a hash set.
120-
#[derive(Clone, Debug, From, Into, Derivative)]
120+
/** A finite set backed by a hash set.
121+
122+
A stable order is guaranteed when iterating over the elements of the set.
123+
Currently, this achieved by using an [`IndexSet`] rather than a `HashSet` for
124+
the underlying data structure.
125+
*/
126+
#[derive(Clone, Debug, Derivative)]
121127
#[derivative(Default(bound = ""))]
122128
#[derivative(PartialEq(bound = "T: Eq + Hash"))]
123129
#[derivative(Eq(bound = "T: Eq + Hash"))]
124-
pub struct HashFinSet<T>(HashSet<T>);
130+
pub struct HashFinSet<T>(IndexSet<T>);
125131

126132
/// A finite set with elements of type `Ustr`.
127133
pub type UstrFinSet = HashFinSet<Ustr>;
@@ -179,7 +185,7 @@ where
179185
T: Eq + Hash,
180186
{
181187
type Item = T;
182-
type IntoIter = std::collections::hash_set::IntoIter<T>;
188+
type IntoIter = indexmap::set::IntoIter<T>;
183189

184190
fn into_iter(self) -> Self::IntoIter {
185191
self.0.into_iter()
@@ -275,10 +281,7 @@ mod tests {
275281
assert!(s.contains(&3));
276282
assert!(s.contains(&7));
277283
assert!(!s.contains(&2));
278-
279-
let s = HashFinSet::from(HashSet::from([3, 5, 7]));
280-
let sum: i32 = s.iter().sum();
281-
assert_eq!(sum, 15);
284+
assert_eq!(s.iter().sum::<i32>(), 15);
282285
assert_eq!(s.len(), 3);
283286
}
284287

packages/frontend/src/stdlib/analyses/simulation.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type Accessor, createMemo } from "solid-js";
22

33
import type { DblModel, JsResult, ODEResult } from "catlog-wasm";
44
import type { LiveModelDocument } from "../../model";
5-
import type { ODEPlotData } from "../../visualization";
5+
import type { ODEPlotData, StateVarData } from "../../visualization";
66

77
/** Reactively simulate and plot an ODE derived from a model.
88
@@ -24,15 +24,19 @@ export function createModelODEPlot(
2424
if (simulationResult?.tag !== "Ok") {
2525
return simulationResult;
2626
}
27-
2827
const solution = simulationResult.content;
29-
const content = {
30-
time: solution.time,
31-
states: Array.from(solution.states.entries()).map(([id, data]) => ({
32-
name: model.obGeneratorLabel(id)?.join(".") ?? "",
33-
data,
34-
})),
35-
};
28+
29+
const states: StateVarData[] = [];
30+
for (const id of model.obGenerators()) {
31+
const data = solution.states.get(id);
32+
if (data !== undefined) {
33+
states.push({
34+
name: model.obGeneratorLabel(id)?.join(".") ?? "",
35+
data,
36+
});
37+
}
38+
}
39+
const content = { time: solution.time, states };
3640
return { tag: "Ok", content };
3741
},
3842
undefined,

packages/frontend/src/visualization/ode_plot.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type ODEPlotData = {
1313
};
1414

1515
/** Values of a state variable over time. */
16-
type StateVarData = {
16+
export type StateVarData = {
1717
name: string;
1818
data: number[];
1919
};

0 commit comments

Comments
 (0)