Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
635b53f
Small changes
mlaveaux Feb 2, 2026
e421089
Added missing word
mlaveaux Feb 2, 2026
b06ccc2
Added an option to apply the sigref with split signatures.
mlaveaux Feb 2, 2026
eb6edbf
Added a specialized subsitution function
mlaveaux Feb 2, 2026
39b2762
Optimised the refine function by applying the edge operators.
mlaveaux Feb 2, 2026
50e2365
Moved this to util
mlaveaux Feb 2, 2026
9109466
Replaced the ite by a proper BDD reduce function in ldd_to_bdd, makin…
mlaveaux Feb 2, 2026
ade92fc
Added a very naive caching, but this already made ldd_to_bdd 10 times…
mlaveaux Feb 2, 2026
53dd594
Fixed the implementation of the variable rename.
mlaveaux Feb 2, 2026
739f723
In refine, we must deal with the case where the signature is empty fo…
mlaveaux Feb 2, 2026
97db7a7
Fixed ldd_to_bdd for non sorted bits.
mlaveaux Feb 2, 2026
1b39147
Use variable_rename for state variable substitution
mlaveaux Feb 2, 2026
5a7df97
Added the variable renaming for the next state to previous as well.
mlaveaux Feb 2, 2026
7aa3839
Applied the substitution immediately to avoid an intermediate blow up…
mlaveaux Feb 3, 2026
86bde77
Skip the header of the read write matrix.
mlaveaux Feb 3, 2026
defbfd0
Compute the total dependency graph span
mlaveaux Feb 3, 2026
00e39c2
Made progress on the split signature approach
mlaveaux Feb 4, 2026
7eb80b7
Ran formatting and fixed clippy warnings
mlaveaux Feb 4, 2026
f952327
Switch from mt-kahypar to called the kahypar tool directly.
mlaveaux Feb 4, 2026
89fd302
Made reorder more general, and added some comments
mlaveaux Feb 5, 2026
337239e
Fixed decoding the block number
mlaveaux Feb 4, 2026
b0f4997
This test was incorrect
mlaveaux Feb 4, 2026
93bf3d3
This was inverted
mlaveaux Feb 5, 2026
542edfe
For iteration time fat LTO is too slow, and does not seem to contribu…
mlaveaux Feb 6, 2026
c4cde11
Added pseudocode vertices in the reordering, and apply vertex weights…
mlaveaux Feb 6, 2026
44dd4f5
Updated to slint 1.15
mlaveaux Feb 7, 2026
1050142
Smaller changes
mlaveaux Feb 7, 2026
e6b0f5d
Refactored create_hypergraph to obtain a struct instead of a tuple
mlaveaux Feb 10, 2026
614ae2c
Fixed an issue where the outputs with a dot would be overwritten.
mlaveaux Feb 11, 2026
9cd6d6d
Warn about actions that do not occur in the LTS
mlaveaux Feb 13, 2026
222a2d6
Added the translation of regular formulas
mlaveaux Feb 17, 2026
e92ed60
Fixed and optimised the projection
mlaveaux Feb 17, 2026
8a39c34
Fixed clippy warnings.
mlaveaux Feb 18, 2026
281123b
Fixed compilation issues.
mlaveaux Feb 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 1 addition & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version = "1.0.0"

# Add debug information to the release binaries.
[profile.release]
lto = "fat"
lto = "thin"
panic = "abort"
debug = "line-tables-only"
split-debuginfo= "packed"
Expand Down Expand Up @@ -63,7 +63,6 @@ hashbrown = "0.16"
html-escape = "0.2"
itertools = "0.14"
log = { version = "0.4", features = ["kv"] }
mt-kahypar = "0.2"
num = "0.4"
oxidd = { version = "0.11", features = ["manager-pointer"] }
oxidd-dump = "0.6"
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Various tools have been implemented so far:
- `merc-vpg` can be used to solve (variability) parity games in the [PGSolver](https://github.com/tcsprojects/pgsolver) `.pg` format, and a slightly extended variability parity game `.vpg` format. Furthermore, it can generate variability parity games for model checking modal mu-calculus on LTSs.
- `merc-pbes` can identify symmetries in parameterised boolean equation systems [PBES](https://doi.org/10.1016%2Fj.tcs.2005.06.016), located in the `tools/mcrl2` workspace.
- `merc-ltsgraph` is a GUI tool to visualize LTSs, located in the `tools/gui` workspace.
- `merc-sym` can explore a symbolic state space given in Sylvan's binary `.ldd` format, or the mCRL2 symbolic binary `.sym` format. It can also compute orderings using MINCE when the `kahypar` feature is enabled.
- `merc-sym` can explore a symbolic state space given in Sylvan's binary `.ldd`
format, or the mCRL2 symbolic binary `.sym` format. It can also compute
variable orderings using MINCE when the `kahypar` feature is enabled.

Various crates are also published on [crates.io](https://crates.io/users/mlaveaux), see the [crates](./crates) directory for an overview.

Expand Down
3 changes: 2 additions & 1 deletion crates/ldd/src/test_utility.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Functions in this module are only relevant for testing purposes.

use rand::Rng;
use rand::RngExt;
use std::collections::HashSet;

use rand::RngExt;
use streaming_iterator::StreamingIterator;

use crate::Ldd;
Expand Down
4 changes: 1 addition & 3 deletions crates/symbolic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ rust-version.workspace = true
version.workspace = true

[features]
# Enable kahypar support to enable the MINCE algorithm, only works on Linux and macOS.
kahypar = ["dep:mt-kahypar"]
# Derive additional traits for clap.
clap = ["dep:clap"]
# Enables keeping track of various performance metrics.
Expand All @@ -28,9 +26,9 @@ merc_lts.workspace = true
merc_utilities.workspace = true

clap = { workspace = true, optional = true }
duct.workspace = true
itertools.workspace = true
log.workspace = true
mt-kahypar = { workspace = true, optional = true }
oxidd-core.workspace = true
oxidd-dump.workspace = true
oxidd.workspace = true
Expand Down
71 changes: 71 additions & 0 deletions crates/symbolic/data/kahypar.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# general
mode=direct
objective=cut
seed=-1
cmaxnet=1000
vcycles=0
quiet=1
# main -> preprocessing -> min hash sparsifier
p-use-sparsifier=true
p-sparsifier-min-median-he-size=28
p-sparsifier-max-hyperedge-size=1200
p-sparsifier-max-cluster-size=10
p-sparsifier-min-cluster-size=2
p-sparsifier-num-hash-func=5
p-sparsifier-combined-num-hash-func=100
# main -> preprocessing -> community detection
p-detect-communities=true
p-detect-communities-in-ip=true
p-reuse-communities=false
p-max-louvain-pass-iterations=150
p-min-eps-improvement=0.0001
p-louvain-edge-weight=hybrid
# main -> coarsening
c-type=ml_style
c-s=1
c-t=160
# main -> coarsening -> rating
c-rating-score=heavy_edge
c-rating-use-communities=true
c-rating-heavy_node_penalty=no_penalty
c-rating-acceptance-criterion=best_prefer_unmatched
c-fixed-vertex-acceptance-criterion=fixed_vertex_allowed
# main -> initial partitioning
i-mode=recursive
i-technique=multi
# initial partitioning -> coarsening
i-c-type=ml_style
i-c-s=1
i-c-t=150
# initial partitioning -> coarsening -> rating
i-c-rating-score=heavy_edge
i-c-rating-use-communities=true
i-c-rating-heavy_node_penalty=no_penalty
i-c-rating-acceptance-criterion=best_prefer_unmatched
i-c-fixed-vertex-acceptance-criterion=fixed_vertex_allowed
# initial partitioning -> initial partitioning
i-algo=pool
i-runs=200
# initial partitioning -> bin packing
i-bp-algorithm=worst_fit
i-bp-heuristic-prepacking=false
i-bp-early-restart=true
i-bp-late-restart=true
# initial partitioning -> local search
i-r-type=twoway_fm
i-r-runs=-1
i-r-fm-stop=simple
i-r-fm-stop-i=50
# main -> local search
r-type=kway_fm_hyperflow_cutter
r-runs=-1
r-fm-stop=adaptive_opt
r-fm-stop-alpha=1
r-fm-stop-i=350
# local_search -> flow scheduling and heuristics
r-flow-execution-policy=exponential
# local_search -> hyperflowcutter configuration
r-hfc-size-constraint=mf-style
r-hfc-scaling=16
r-hfc-distance-based-piercing=true
r-hfc-mbc=true
64 changes: 60 additions & 4 deletions crates/symbolic/src/dependency_graph.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::fmt;

use log::trace;

/// Represents a dependency graph between variables used in symbolic transition relations.
pub struct DependencyGraph {
/// The list of relations in the dependency graph.
Expand All @@ -25,6 +27,32 @@ impl DependencyGraph {
}
}

/// Restrict the dependency graph to the given vertices, and reorder them according to the given order.
pub fn reorder(&self, vertices: &[usize]) -> Self {
let mut new_relations = Vec::with_capacity(self.relations.len());

for relation in &self.relations {
let mut new_read_vars: Vec<usize> = relation
.read_vars()
.filter_map(|var| vertices.iter().position(|&v| v == var))
.collect();

let mut new_write_vars: Vec<usize> = relation
.write_vars()
.filter_map(|var| vertices.iter().position(|&v| v == var))
.collect();

new_read_vars.sort_unstable();
new_write_vars.sort_unstable();

if !new_read_vars.is_empty() || !new_write_vars.is_empty() {
new_relations.push(Relation::new(new_read_vars, new_write_vars));
}
}

DependencyGraph::new(new_relations)
}

/// Returns the number of vertices in the dependency graph.
pub fn num_of_vertices(&self) -> usize {
self.num_of_vertices
Expand All @@ -39,11 +67,21 @@ impl DependencyGraph {
pub fn relations(&self) -> impl Iterator<Item = &Relation> {
self.relations.iter()
}

/// Returns the total span of all relations in the dependency graph.
pub fn total_span(&self) -> usize {
self.relations.iter().map(|rel| rel.span()).sum()
}
}

impl fmt::Debug for DependencyGraph {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "DependencyGraph with {} vertices:", self.num_of_vertices)?;
writeln!(
f,
"graph with {} vertices, and {} hyper-edges",
self.num_of_vertices,
self.relations.len()
)?;
for (i, relation) in self.relations.iter().enumerate() {
writeln!(f, " {}: {:?}", i, relation)?;
}
Expand Down Expand Up @@ -73,6 +111,20 @@ impl Relation {
pub fn write_vars(&self) -> impl Iterator<Item = usize> + '_ {
self.write_vars.iter().copied()
}

/// Returns the span of the relation, i.e., the range between the minimum and maximum
/// variable indices used by this relation.
pub fn span(&self) -> usize {
let min_read = self.read_vars.iter().min().copied().unwrap_or(usize::MAX);
let max_read = self.read_vars.iter().max().copied().unwrap_or(0);
let min_write = self.write_vars.iter().min().copied().unwrap_or(usize::MAX);
let max_write = self.write_vars.iter().max().copied().unwrap_or(0);

let min_var = min_read.min(min_write);
let max_var = max_read.max(max_write);

if max_var >= min_var { max_var - min_var + 1 } else { 0 }
}
}

impl fmt::Debug for Relation {
Expand All @@ -81,14 +133,18 @@ impl fmt::Debug for Relation {
}
}

/// Parses a dependency graph as output by
/// Parses a dependency graph as output by the `--info` option of both
/// [lpreach](https://mcrl2.org/web/user_manual/tools/release/lpsreach.html) and
/// [pbessolvesymbolic](https://mcrl2.org/web/user_manual/tools/release/pbessolvesymbolic.html)
/// flag `--info`.
/// [pbessolvesymbolic](https://mcrl2.org/web/user_manual/tools/release/pbessolvesymbolic.html).
pub fn parse_compacted_dependency_graph(input: &str) -> DependencyGraph {
trace!("Parsing dependency graph:\n{}", input);
let mut relations = Vec::new();

for line in input.lines() {
if line == "read/write patterns compacted" {
continue;
}

// Keep only pattern characters, ignoring indices/whitespace
let pattern: Vec<char> = line.chars().filter(|c| matches!(c, '+' | '-' | 'r' | 'w')).collect();

Expand Down
Loading
Loading