Skip to content

Commit 8008d04

Browse files
authored
Merge pull request #1683 from informalsystems/gabriela/rust-outcome-updates
Add samples and trace length stats to rust simulator
2 parents e7b857f + 84fd278 commit 8008d04

File tree

6 files changed

+54
-6
lines changed

6 files changed

+54
-6
lines changed

evaluator/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

evaluator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "quint_evaluator"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2021"
55

66
[profile.release]

evaluator/src/main.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::time::Instant;
1212
use argh::FromArgs;
1313
use eyre::bail;
1414
use quint_evaluator::ir::{QuintError, QuintEx};
15-
use quint_evaluator::simulator::{ParsedQuint, ProgressUpdate, SimulationResult};
15+
use quint_evaluator::simulator::{ParsedQuint, ProgressUpdate, SimulationResult, TraceStatistics};
1616
use quint_evaluator::{helpers, log};
1717
use serde::{Deserialize, Serialize};
1818

@@ -99,6 +99,7 @@ struct Outcome {
9999
status: SimulationStatus,
100100
errors: Vec<QuintError>,
101101
best_traces: Vec<SimulationTrace>,
102+
trace_statistics: TraceStatistics,
102103
witnessing_traces: Vec<usize>,
103104
samples: usize,
104105
}
@@ -243,8 +244,12 @@ fn to_outcome(source: String, result: Result<SimulationResult, QuintError>) -> O
243244
status,
244245
errors,
245246
best_traces,
247+
trace_statistics: result
248+
.as_ref()
249+
.ok()
250+
.map_or_else(TraceStatistics::default, |r| r.trace_statistics.clone()),
251+
samples: result.as_ref().map_or(0, |r| r.samples),
246252
// TODO: This simulator is not tracking witnesses yet
247253
witnessing_traces: vec![],
248-
samples: 0,
249254
}
250255
}

evaluator/src/simulator.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,22 @@ pub struct ParsedQuint {
2020
pub struct SimulationResult {
2121
pub result: bool,
2222
pub best_traces: Vec<Trace>,
23+
pub trace_statistics: TraceStatistics,
24+
pub samples: usize,
2325
// TODO
2426
// witnessing_traces
25-
// samples
27+
}
28+
29+
/// Statistics about the length of traces collected during simulation.
30+
#[derive(Serialize, Default, Clone)]
31+
#[serde(rename_all = "camelCase")]
32+
pub struct TraceStatistics {
33+
/// The average length of the traces
34+
pub average_trace_length: f64,
35+
/// The maximum length of the traces
36+
pub max_trace_length: usize,
37+
/// The minimum length of the traces
38+
pub min_trace_length: usize,
2639
}
2740

2841
/// Simulation progress update.
@@ -70,6 +83,7 @@ impl ParsedQuint {
7083

7184
// Have one extra space as we insert first and then pop if we have too many traces
7285
let mut best_traces = Vec::with_capacity(n_traces + 1);
86+
let mut trace_lengths = Vec::with_capacity(n_traces + 1);
7387

7488
for sample_number in 1..=samples {
7589
if let Some(callback) = &mut progress_callback {
@@ -82,9 +96,12 @@ impl ParsedQuint {
8296
let mut trace = Vec::with_capacity(steps + 1);
8397

8498
if !init.execute(&mut env)?.as_bool() {
99+
trace_lengths.push(0);
85100
return Ok(SimulationResult {
86101
result: false,
87102
best_traces,
103+
trace_statistics: get_trace_statistics(&trace_lengths),
104+
samples: sample_number,
88105
});
89106
}
90107

@@ -94,6 +111,7 @@ impl ParsedQuint {
94111
trace.push(interpreter.var_storage.borrow().as_record());
95112

96113
if !invariant.execute(&mut env)?.as_bool() {
114+
trace_lengths.push(trace.len());
97115
// Found a counterexample
98116
collect_trace(
99117
&mut best_traces,
@@ -106,6 +124,8 @@ impl ParsedQuint {
106124
return Ok(SimulationResult {
107125
result: false,
108126
best_traces,
127+
trace_statistics: get_trace_statistics(&trace_lengths),
128+
samples: sample_number,
109129
});
110130
}
111131

@@ -116,9 +136,11 @@ impl ParsedQuint {
116136
// the run. Hence, do not report an error here, but simply
117137
// drop the run. Otherwise, we would have a lot of false
118138
// positives, which look like deadlocks but they are not.
139+
trace_lengths.push(trace.len());
119140
break;
120141
}
121142
}
143+
trace_lengths.push(trace.len());
122144
collect_trace(
123145
&mut best_traces,
124146
n_traces,
@@ -131,10 +153,29 @@ impl ParsedQuint {
131153
Ok(SimulationResult {
132154
result: true,
133155
best_traces,
156+
trace_statistics: get_trace_statistics(&trace_lengths),
157+
samples,
134158
})
135159
}
136160
}
137161

162+
/// Get statistics about the lengths of traces collected during simulation.
163+
fn get_trace_statistics(trace_lengths: &[usize]) -> TraceStatistics {
164+
if trace_lengths.is_empty() {
165+
return TraceStatistics {
166+
average_trace_length: 0.0,
167+
max_trace_length: 0,
168+
min_trace_length: 0,
169+
};
170+
}
171+
TraceStatistics {
172+
average_trace_length: trace_lengths.iter().sum::<usize>() as f64
173+
/ trace_lengths.len() as f64,
174+
max_trace_length: *trace_lengths.iter().max().unwrap_or(&0),
175+
min_trace_length: *trace_lengths.iter().min().unwrap_or(&0),
176+
}
177+
}
178+
138179
/// Collect a trace of the simulation, up to a maximum of `n_traces`.
139180
///
140181
/// Assumes `best_traces` is sorted by quality.

quint/src/quintRustWrapper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { spawn } from 'child_process'
2828
import { rustEvaluatorDir } from './config'
2929
import { QuintError } from './quintError'
3030

31-
const QUINT_EVALUATOR_VERSION = 'v0.1.0'
31+
const QUINT_EVALUATOR_VERSION = 'v0.2.0'
3232

3333
export type ParsedQuint = {
3434
modules: QuintModule[]

quint/src/runtime/impl/evaluator.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ export class Evaluator {
189189

190190
const initResult = initEval(this.ctx).mapLeft(error => (failure = error))
191191
if (!isTrue(initResult)) {
192+
traceLengths.push(0)
192193
this.recorder.onUserOperatorReturn(initApp, [], initResult)
193194
} else {
194195
this.shift()
@@ -197,6 +198,7 @@ export class Evaluator {
197198
this.recorder.onUserOperatorReturn(initApp, [], invResult)
198199
if (!isTrue(invResult)) {
199200
errorsFound++
201+
traceLengths.push(this.trace.get().length)
200202
} else {
201203
// check all { step, shift(), inv } in a loop
202204
for (let i = 0; errorsFound < ntraces && !failure && i < nsteps; i++) {

0 commit comments

Comments
 (0)