Skip to content

Commit a049856

Browse files
committed
🚸 Allow non-zero layer as min
1 parent 6a04543 commit a049856

File tree

5 files changed

+34
-19
lines changed

5 files changed

+34
-19
lines changed

python/swiflow/_common.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,12 +264,12 @@ def decode_err(self, err: ValueError) -> ValueError:
264264
"""Decode the error message stored in the first ctor argument of ValueError."""
265265
raw = err.args[0]
266266
# Keep in sync with Rust-side error messages
267-
if isinstance(raw, FlowValidationMessage.ExcessiveNonZeroLayer):
267+
if isinstance(raw, FlowValidationMessage.ExcessiveNonMinLayer):
268268
node = self.decode(raw.node)
269269
msg = f"Layer-{raw.layer} node {node} inside output nodes."
270-
elif isinstance(raw, FlowValidationMessage.ExcessiveZeroLayer):
270+
elif isinstance(raw, FlowValidationMessage.ExcessiveMinLayer):
271271
node = self.decode(raw.node)
272-
msg = f"Zero-layer node {node} outside output nodes."
272+
msg = f"Minimum-layer node {node} outside output nodes."
273273
elif isinstance(raw, FlowValidationMessage.InvalidFlowCodomain):
274274
node = self.decode(raw.node)
275275
msg = f"f({node}) has invalid codomain."

python/swiflow/_impl/__init__.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ from swiflow._impl.gflow import Plane
22
from swiflow._impl.pflow import PPlane
33

44
class FlowValidationMessage:
5-
class ExcessiveNonZeroLayer:
5+
class ExcessiveNonMinLayer:
66
node: int
77
layer: int
88

99
def __init__(self, node: int, layer: int) -> None: ...
1010

11-
class ExcessiveZeroLayer:
11+
class ExcessiveMinLayer:
1212
node: int
1313

1414
def __init__(self, node: int) -> None: ...

src/common.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ pub(crate) type OrderedNodes = BTreeSet<usize>;
2929
pub enum FlowValidationError {
3030
// Keep in sync with Python-side error messages
3131
#[error("layer-{layer} node {node} inside output nodes")]
32-
ExcessiveNonZeroLayer { node: usize, layer: usize },
33-
#[error("zero-layer node {node} outside output nodes")]
34-
ExcessiveZeroLayer { node: usize },
32+
ExcessiveNonMinLayer { node: usize, layer: usize },
33+
#[error("minimum-layer node {node} outside output nodes")]
34+
ExcessiveMinLayer { node: usize },
3535
#[error("f({node}) has invalid codomain")]
3636
InvalidFlowCodomain { node: usize },
3737
#[error("f({node}) has invalid domain")]
@@ -67,6 +67,6 @@ mod tests {
6767

6868
#[test]
6969
fn test_err_from() {
70-
let _ = PyErr::from(FlowValidationError::ExcessiveNonZeroLayer { node: 1, layer: 2 });
70+
let _ = PyErr::from(FlowValidationError::ExcessiveNonMinLayer { node: 1, layer: 2 });
7171
}
7272
}

src/internal/validate.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,29 @@
66
77
use crate::common::{
88
FlowValidationError::{
9-
self, ExcessiveNonZeroLayer, ExcessiveZeroLayer, InvalidFlowCodomain, InvalidFlowDomain,
9+
self, ExcessiveMinLayer, ExcessiveNonMinLayer, InvalidFlowCodomain, InvalidFlowDomain,
1010
},
1111
Layer, Nodes,
1212
};
1313

14-
/// Checks if the layer-zero nodes are correctly chosen.
14+
/// Checks if the minimum-layer nodes are correctly chosen.
1515
///
1616
/// This check can be skipped unless maximally-delayed flow is required.
1717
///
1818
/// # Arguments
1919
///
2020
/// - `layer`: The layer.
2121
/// - `oset`: The set of output nodes.
22-
/// - `iff`: If `true`, `layer[u] == 0` "iff" `u` is in `oset`. Otherwise "if".
22+
/// - `iff`: If `true`, `layer[u]` is minimum "iff" `u` is in `oset`. Otherwise "if".
2323
pub fn check_initial(layer: &Layer, oset: &Nodes, iff: bool) -> Result<(), FlowValidationError> {
24+
let lmin = layer.iter().copied().min().unwrap_or_default();
2425
for (u, &lu) in layer.iter().enumerate() {
25-
match (oset.contains(&u), lu == 0) {
26+
match (oset.contains(&u), lu == lmin) {
2627
(true, false) => {
27-
Err(ExcessiveNonZeroLayer { node: u, layer: lu })?;
28+
Err(ExcessiveNonMinLayer { node: u, layer: lu })?;
2829
}
2930
(false, true) if iff => {
30-
Err(ExcessiveZeroLayer { node: u })?;
31+
Err(ExcessiveMinLayer { node: u })?;
3132
}
3233
_ => {}
3334
}
@@ -103,6 +104,20 @@ mod tests {
103104
assert!(check_initial(&layer, &oset, true).is_err());
104105
}
105106

107+
#[test]
108+
fn test_check_initial_nonzero_min() {
109+
let layer = vec![1, 1, 1, 2, 2, 2];
110+
let oset = Nodes::from([0, 1, 2]);
111+
assert!(check_initial(&layer, &oset, true).is_ok());
112+
}
113+
114+
#[test]
115+
fn test_check_initial_empty() {
116+
let layer = vec![];
117+
let oset = Nodes::default();
118+
assert!(check_initial(&layer, &oset, true).is_ok());
119+
}
120+
106121
#[test]
107122
fn test_check_domain_flow() {
108123
let f = hashbrown::HashMap::<usize, usize>::from([(0, 1), (1, 2)]);

tests/test_common.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def test_encdec(self) -> None:
9898
@pytest.mark.parametrize(
9999
"emsg",
100100
[
101-
FlowValidationMessage.ExcessiveNonZeroLayer(0, 1),
102-
FlowValidationMessage.ExcessiveZeroLayer(0),
101+
FlowValidationMessage.ExcessiveNonMinLayer(0, 1),
102+
FlowValidationMessage.ExcessiveMinLayer(0),
103103
FlowValidationMessage.InvalidFlowCodomain(0),
104104
FlowValidationMessage.InvalidFlowDomain(0),
105105
FlowValidationMessage.InvalidMeasurementSpec(0),
@@ -121,10 +121,10 @@ def dummy_ok(x: int) -> int:
121121
return x
122122

123123
def dummy_ng(_: int) -> Never:
124-
raise ValueError(FlowValidationMessage.ExcessiveZeroLayer(0))
124+
raise ValueError(FlowValidationMessage.ExcessiveMinLayer(0))
125125

126126
assert fx_indexmap.ecatch(dummy_ok, 1) == 1
127-
with pytest.raises(ValueError, match=r"Zero-layer node a outside output nodes\."):
127+
with pytest.raises(ValueError, match=r"Minimum-layer node a outside output nodes\."):
128128
fx_indexmap.ecatch(dummy_ng, 1)
129129

130130

0 commit comments

Comments
 (0)