Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
eb50692
Add SortExpressionKind::TypeVar.
mlaveaux Sep 6, 2026
61777c8
Introduce an explicit (global) VarId to make name resolution more con…
mlaveaux Sep 7, 2026
0c1f4b2
Added a source map to handle imports in the future
mlaveaux Sep 7, 2026
f0df353
Updated name resolution to yield proper variable ids
mlaveaux Sep 7, 2026
f75a1bf
Added StateVarId as well, to be consistent with the VarId.
mlaveaux Sep 7, 2026
198b2a6
Added a struct to actually deal with imports
mlaveaux Sep 7, 2026
8dcbe93
Added the type_var block to handle polymorphic containers in the future
mlaveaux Sep 7, 2026
a602365
Added type vars to the system provided specs
mlaveaux Sep 8, 2026
271db16
Extended the imports for state formulas, updated tests
mlaveaux Sep 8, 2026
8f248ba
Made the builtins also use the type_var construct
mlaveaux Sep 8, 2026
e27c02d
Moved the snapshot setup to utilities
mlaveaux Sep 8, 2026
cdd9bdb
Ran formatting, added source map everywhere
mlaveaux Sep 9, 2026
8a70c98
Ran formatting, added source map everywhere
mlaveaux Sep 8, 2026
531451f
Added snapshots for the typechecking tests as well
mlaveaux Sep 8, 2026
02872dc
Added the builtin spec files to the source map so we can report issue…
mlaveaux Sep 8, 2026
ca9c669
Started the polymorphic scheme
mlaveaux Sep 8, 2026
3e988c7
Carry through the variable spans
mlaveaux Sep 8, 2026
739b3e5
Renamed lsp_info to typing_info, and made the type snapshots actually…
mlaveaux Sep 8, 2026
5836fe2
Added proper import errors.
mlaveaux Sep 8, 2026
f77d89b
Fixed PRES negation being ! instead of -
mlaveaux Sep 8, 2026
3db7a62
Renamed lps_info to typing_info after rebase
mlaveaux Sep 9, 2026
54f3579
Made parse_with_imports also return a structured error
mlaveaux Sep 9, 2026
8824e64
Instead of parsing with an n spaces to offset spans, actually do it a…
mlaveaux Sep 9, 2026
e03a20c
Also add goto for the complex sorts.
mlaveaux Sep 9, 2026
b26898a
Stop threading the VariableSpans, simply compute them in typing_info …
mlaveaux Sep 9, 2026
4366291
Added shift to the Span
mlaveaux Sep 9, 2026
a3dc215
Added printing for PRES
mlaveaux Sep 9, 2026
eff77b0
Renamed DefId to SortId, added PRES pretty printing
mlaveaux Sep 10, 2026
486ea6d
Optimised parsing by changing the ProcExprNoIfInfix to only contain h…
mlaveaux Sep 10, 2026
d50f4b9
Updated various comments
mlaveaux Sep 10, 2026
d66c081
This is a type checking concern
mlaveaux Sep 11, 2026
b1cd094
Avoid exposing pest in the source map, and return the import graph
mlaveaux Sep 11, 2026
2c252fc
Rewrote the precendence such that pretty printing and other aspects c…
mlaveaux Sep 11, 2026
c373648
Add the built in equations as well
mlaveaux Sep 11, 2026
d4bde38
Added several specification tests, made type checking rigid templates…
mlaveaux Sep 11, 2026
812d369
Made variable resolution spans a typing_info concern, instead of coll…
mlaveaux Sep 11, 2026
e5d3791
Made errors actually return the candidates such that they dont have t…
mlaveaux Sep 11, 2026
325ba55
Simplified some implementations
mlaveaux Sep 11, 2026
b737d2a
Return source graph when parsing
mlaveaux Sep 14, 2026
5bf93d6
Actually check that @ prefixes are disallowed in user specs
mlaveaux Sep 14, 2026
9045267
Resolve type variables before type checking, and not in the parser.
mlaveaux Sep 14, 2026
e5750a3
Identify system sorts by the @ symbol.
mlaveaux Sep 14, 2026
c9de9b8
The system signature is now part of the full signature
mlaveaux Sep 14, 2026
c2fa0d9
Moved the template instantiation to the lowering
mlaveaux Sep 14, 2026
2784e76
Made it possible to infer the val sort in a modal formula.
mlaveaux Sep 15, 2026
555e6c7
Fix dangling doc cross-reference and undocumented ValSort variants.
mlaveaux Sep 15, 2026
55e1b97
Merged the system and user signature checks partially, using a truste…
mlaveaux Sep 15, 2026
e07b79f
Split some complicated functions
mlaveaux Sep 15, 2026
dec35d4
Fixed compilation issue with missing script
mlaveaux Sep 15, 2026
4b29c53
Merged resolve_type_variables into one
mlaveaux Sep 15, 2026
6ac72d7
Moved the rhs is bound check to the rewriter
mlaveaux Sep 15, 2026
47ee1f6
Removed the incorrect span offset
mlaveaux Sep 15, 2026
6bbd691
Simplified various comments
mlaveaux Sep 15, 2026
deca602
Cleaned up various code duplication
mlaveaux Sep 15, 2026
20980ac
Changed this for loop to enable auto vectorisation
mlaveaux Sep 15, 2026
dfc4ba2
Fixed the grammar, and commented the exponential parsing test
mlaveaux Sep 15, 2026
bb18965
Only have one place consistently assign ids to expressions
mlaveaux Sep 15, 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
2 changes: 2 additions & 0 deletions Cargo.lock

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

116 changes: 65 additions & 51 deletions crates/aterm/src/aterm_binary_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,62 +255,13 @@ impl<W: Write> BinaryATermWriter<W> {

if !self.terms.read().contains(&current_term) || is_output {
if write_ready {
if is_int_term(&current_term) {
let int_term = ATermIntRef::from(current_term.copy());
if is_output {
// If the integer is output, write the header and just an integer
self.stream.write_bits(PacketType::ATermIntOutput as u64, PACKET_BITS)?;
self.stream.write_integer(int_term.value() as u64)?;
} else {
let symbol_index = self.write_function_symbol(&int_term.get_head_symbol())?;

self.stream.write_bits(PacketType::ATerm as u64, PACKET_BITS)?;
self.stream
.write_bits(symbol_index as u64, self.function_symbol_index_width())?;
self.stream.write_integer(int_term.value() as u64)?;
}
} else {
let symbol_index = self.write_function_symbol(&current_term.get_head_symbol())?;
let packet_type = if is_output {
PacketType::ATermOutput
} else {
PacketType::ATerm
};

self.stream.write_bits(packet_type as u64, PACKET_BITS)?;
self.stream
.write_bits(symbol_index as u64, self.function_symbol_index_width())?;

for arg in current_term.arguments() {
let index = self.terms.read().index(&arg).expect("Argument must already be written");
self.stream.write_bits(*index as u64, self.term_index_width())?;
}
}

if !is_output {
let (_, inserted) = self.terms.write().insert(current_term.copy());
assert!(inserted, "This term should have a new index assigned.");
self.term_index_width = bits_for_value(self.terms.read().len());
}
self.write_term_body(&current_term, is_output)?;

// Done with this entry now that it has been written (and, if not the
// top-level output term, protected independently by `terms` above).
self.stack.write().pop_back();
} else {
// Mark ready for its next visit, once its (not yet written) arguments below
// it on the stack are done -- so leave it in place rather than popping it.
if let Some(back) = self.stack.write().back_mut() {
back.1 = true;
}

// Add arguments to stack for processing first. Two equal
// arguments are both pushed here, but that does not write
// the term twice.
for arg in current_term.arguments() {
if !self.terms.read().contains(&arg) {
self.stack.write().push_back((arg.copy(), false));
}
}
self.queue_arguments(&current_term);
}
} else {
// This term was already written and as such should be skipped. This can happen
Expand All @@ -321,6 +272,69 @@ impl<W: Write> BinaryATermWriter<W> {

Ok(())
}

/// Writes the body of `current_term` to the stream: the head packet and,
/// for a non-integer term, the already-written argument indices. When
/// `is_output` the term is the top-level output term and is written down
/// as such without being added to the term table.
fn write_term_body(&mut self, current_term: &ATermRef<'_>, is_output: bool) -> Result<(), MercError> {
if is_int_term(current_term) {
let int_term = ATermIntRef::from(current_term.copy());
if is_output {
// If the integer is output, write the header and just an integer
self.stream.write_bits(PacketType::ATermIntOutput as u64, PACKET_BITS)?;
self.stream.write_integer(int_term.value() as u64)?;
} else {
let symbol_index = self.write_function_symbol(&int_term.get_head_symbol())?;

self.stream.write_bits(PacketType::ATerm as u64, PACKET_BITS)?;
self.stream
.write_bits(symbol_index as u64, self.function_symbol_index_width())?;
self.stream.write_integer(int_term.value() as u64)?;
}
} else {
let symbol_index = self.write_function_symbol(&current_term.get_head_symbol())?;
let packet_type = if is_output {
PacketType::ATermOutput
} else {
PacketType::ATerm
};

self.stream.write_bits(packet_type as u64, PACKET_BITS)?;
self.stream
.write_bits(symbol_index as u64, self.function_symbol_index_width())?;

for arg in current_term.arguments() {
let index = self.terms.read().index(&arg).expect("Argument must already be written");
self.stream.write_bits(*index as u64, self.term_index_width())?;
}
}

if !is_output {
let (_, inserted) = self.terms.write().insert(current_term.copy());
assert!(inserted, "This term should have a new index assigned.");
self.term_index_width = bits_for_value(self.terms.read().len());
}

Ok(())
}

/// Marks `current_term` ready for its next visit — once its (not yet
/// written) arguments below it on the stack are done — by flipping its
/// `write_ready` flag in place, then queues those arguments for
/// processing first. Two equal arguments are both pushed here, but that
/// does not write the term twice.
fn queue_arguments(&mut self, current_term: &ATermRef<'_>) {
if let Some(back) = self.stack.write().back_mut() {
back.1 = true;
}

for arg in current_term.arguments() {
if !self.terms.read().contains(&arg) {
self.stack.write().push_back((arg.copy(), false));
}
}
}
}

impl<W: Write> ATermWrite for BinaryATermWriter<W> {
Expand Down
64 changes: 38 additions & 26 deletions crates/aterm/src/storage/global_aterm_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,39 @@ impl GlobalTermPool {

/// Collects garbage terms.
pub fn collect_garbage(&mut self) {
let mark_time = Instant::now();
self.mark_roots();
let mark_time_elapsed = mark_time.elapsed();
let collect_time = Instant::now();

let (removed_terms, removed_symbols) = self.sweep_terms_and_symbols();

debug!(
"Garbage collection: marking took {}ms, collection took {}ms, {} terms and {} symbols removed",
mark_time_elapsed.as_millis(),
collect_time.elapsed().as_millis(),
removed_terms,
removed_symbols
);

debug!("{}", self.metrics());

// Print information from the protection sets.
for pool in self.thread_pools.iter().flatten() {
// SAFETY: We have exclusive access to the global term pool, so no other thread can modify the protection sets.
let pool = unsafe { &mut *pool.get() };
debug!("{}", pool.metrics());
}

// Clear marking data structures
self.marked_terms.clear();
self.marked_symbols.clear();
self.stack.clear();
}

/// Marks the default symbols and every root in every protection set as reachable,
/// and reclaims protection sets of threads that have exited.
fn mark_roots(&mut self) {
// Mark the default symbols
// SAFETY: mark-set entries only live for the duration of this collection pass
// (the sets are drained by the sweep below), and a marked symbol is by
Expand All @@ -342,8 +375,6 @@ impl GlobalTermPool {
stack: &mut self.stack,
};

let mark_time = Instant::now();

// Loop through all protection sets and mark the terms.
for pool in self.thread_pools.iter().flatten() {
// SAFETY: We have exclusive access to the global term pool, so no other thread can modify the protection sets.
Expand Down Expand Up @@ -425,10 +456,11 @@ impl GlobalTermPool {
*slot = None;
}
}
}

let mark_time_elapsed = mark_time.elapsed();
let collect_time = Instant::now();

/// Removes every term and symbol that was not marked by [`Self::mark_roots`], and
/// returns how many of each were removed.
fn sweep_terms_and_symbols(&mut self) -> (usize, usize) {
let num_of_terms = self.len();
let num_of_symbols = self.symbol_pool.len();

Expand Down Expand Up @@ -459,27 +491,7 @@ impl GlobalTermPool {
});
}

debug!(
"Garbage collection: marking took {}ms, collection took {}ms, {} terms and {} symbols removed",
mark_time_elapsed.as_millis(),
collect_time.elapsed().as_millis(),
num_of_terms - self.len(),
num_of_symbols - self.symbol_pool.len()
);

debug!("{}", self.metrics());

// Print information from the protection sets.
for pool in self.thread_pools.iter().flatten() {
// SAFETY: We have exclusive access to the global term pool, so no other thread can modify the protection sets.
let pool = unsafe { &mut *pool.get() };
debug!("{}", pool.metrics());
}

// Clear marking data structures
self.marked_terms.clear();
self.marked_symbols.clear();
self.stack.clear();
(num_of_terms - self.len(), num_of_symbols - self.symbol_pool.len())
}

/// Returns the metrics of the term pool, can be formatted and written to output.
Expand Down
66 changes: 42 additions & 24 deletions crates/explore/src/cpu_topology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,7 @@ fn cluster_by_latency(latency_ns: &[f64], num_cores: usize, factor: f64) -> Vec<
return (0..num_cores).map(|core| vec![core]).collect();
}

let mut min_latency = f64::INFINITY;
for i in 0..num_cores {
for j in 0..num_cores {
if i != j {
min_latency = min_latency.min(latency_ns[i * num_cores + j]);
}
}
}
let threshold = min_latency * factor;
let threshold = minimum_off_diagonal_latency(latency_ns, num_cores) * factor;

let mut visited = vec![false; num_cores];
let mut clusters = Vec::new();
Expand All @@ -215,21 +207,7 @@ fn cluster_by_latency(latency_ns: &[f64], num_cores: usize, factor: f64) -> Vec<
continue;
}

let mut component = Vec::new();
let mut queue = VecDeque::new();
queue.push_back(start);
visited[start] = true;

while let Some(node) = queue.pop_front() {
component.push(node);
for neighbor in 0..num_cores {
if !visited[neighbor] && latency_ns[node * num_cores + neighbor] <= threshold {
visited[neighbor] = true;
queue.push_back(neighbor);
}
}
}

let mut component = connected_component(start, latency_ns, num_cores, threshold, &mut visited);
component.sort_unstable();
clusters.push(component);
}
Expand All @@ -238,6 +216,46 @@ fn cluster_by_latency(latency_ns: &[f64], num_cores: usize, factor: f64) -> Vec<
clusters
}

/// Returns the smallest observed off-diagonal one-way latency.
fn minimum_off_diagonal_latency(latency_ns: &[f64], num_cores: usize) -> f64 {
let mut min_latency = f64::INFINITY;
for i in 0..num_cores {
for j in 0..num_cores {
if i != j {
min_latency = min_latency.min(latency_ns[i * num_cores + j]);
}
}
}
min_latency
}

/// Single-linkage flood fill: returns every core reachable from `start` through
/// edges of latency at most `threshold`, marking the reached cores as visited.
fn connected_component(
start: usize,
latency_ns: &[f64],
num_cores: usize,
threshold: f64,
visited: &mut [bool],
) -> Vec<usize> {
let mut component = Vec::new();
let mut queue = VecDeque::new();
queue.push_back(start);
visited[start] = true;

while let Some(node) = queue.pop_front() {
component.push(node);
for neighbor in 0..num_cores {
if !visited[neighbor] && latency_ns[node * num_cores + neighbor] <= threshold {
visited[neighbor] = true;
queue.push_back(neighbor);
}
}
}

component
}

/// Measures the row-major one-way latency matrix over `cores`, sequentially pair by pair.
///
/// Pairs are measured one at a time because concurrently running pairs would perturb each
Expand Down
5 changes: 3 additions & 2 deletions crates/reduction/src/weak_bisimulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,9 @@ fn compute_weak_acts_inner<L: LTS>(
let [marked_s, marked_t] = marked
.get_disjoint_mut([*transition.from, *t])
.expect("The indices are disjoint");
for (i, number) in marked_s.as_raw_mut_slice().iter_mut().enumerate() {
*number |= marked_t.as_raw_slice()[i];
let marked_t_raw = marked_t.as_raw_slice();
for (s, t) in marked_s.as_raw_mut_slice().iter_mut().zip(marked_t_raw) {
*s |= *t;
}
}
}
Expand Down
Loading
Loading