use super::RewriteConfig;
use super::edit_validation::{
map_and_invalidate_ranges, valid_clean_gap_bijections, valid_exact_clean_gaps,
valid_replacements,
};
use super::proof::{GateInstructionHistogram, config_is_proven_subset};
use super::rewriter::{LinearRewriteWorkspace, is_linear_workspace_eligible};
use crate::circuit::Circuit;
use crate::compile::transform::RewriteEdits;
use std::ops::Range;
#[derive(Debug, Clone)]
struct RewriteCertificate {
circuit_revision: u64,
proof_config: RewriteConfig,
proof_reach: usize,
pending_ranges: Vec<Range<usize>>,
qubit_bijection_invariant: bool,
gate_histogram: GateInstructionHistogram,
workspace: Option<LinearRewriteWorkspace>,
}
#[derive(Debug, Default)]
pub(crate) struct KnowledgeRewriteSession {
certificate: Option<RewriteCertificate>,
pending_full_scan_fallback: bool,
}
pub(crate) struct RewriteExecutionRecord {
pub(crate) config: RewriteConfig,
pub(crate) proof_reach: usize,
pub(crate) qubit_bijection_invariant: bool,
pub(crate) reached_fixpoint: bool,
pub(crate) workspace: Option<LinearRewriteWorkspace>,
}
pub(crate) struct LinearRewriteReconciliation {
pub(crate) state: Option<(Vec<Range<usize>>, Option<LinearRewriteWorkspace>)>,
pub(crate) full_scan_fallback: bool,
}
impl KnowledgeRewriteSession {
pub(crate) fn tracks_rewrite_edits(&self) -> bool {
self.certificate.is_some()
}
pub(crate) fn invalidate(&mut self) {
self.invalidate_for_full_scan();
}
pub(crate) fn reusable_proof(
&self,
circuit_revision: u64,
requested: &RewriteConfig,
) -> Option<usize> {
if requested.max_rounds() == 0 {
return None;
}
let certificate = self.certificate.as_ref()?;
(certificate.circuit_revision == circuit_revision
&& certificate.pending_ranges.is_empty()
&& config_is_proven_subset(
requested,
&certificate.proof_config,
Some(&certificate.gate_histogram),
))
.then_some(certificate.proof_reach)
}
pub(crate) fn record_execution(
&mut self,
circuit: &Circuit,
circuit_revision: u64,
record: RewriteExecutionRecord,
) {
if record.reached_fixpoint {
self.pending_full_scan_fallback = false;
self.certificate = Some(RewriteCertificate {
circuit_revision,
proof_config: record.config,
proof_reach: record.proof_reach,
pending_ranges: Vec::new(),
qubit_bijection_invariant: record.qubit_bijection_invariant,
gate_histogram: GateInstructionHistogram::from_circuit(circuit),
workspace: record.workspace,
});
} else {
self.certificate = None;
self.pending_full_scan_fallback = true;
}
}
pub(crate) fn apply_rewrite_edits(
&mut self,
old_revision: u64,
new_revision: u64,
before: &Circuit,
after: &Circuit,
edits: &RewriteEdits,
) {
let Some(certificate) = self.certificate.as_ref() else {
return;
};
if certificate.circuit_revision != old_revision {
self.invalidate_for_full_scan();
return;
}
let proof_reach = certificate.proof_reach;
let pending_ranges = certificate.pending_ranges.clone();
let qubit_bijection_invariant = certificate.qubit_bijection_invariant;
let (old_len, new_len, replacements, valid_correspondence, qubits_renamed) = match edits {
RewriteEdits::Linear {
old_len,
new_len,
replacements,
} => (
*old_len,
*new_len,
replacements,
before.has_same_qubits(after)
&& valid_exact_clean_gaps(before, after, replacements),
false,
),
RewriteEdits::LinearModuloQubitBijection {
old_len,
new_len,
replacements,
clean_gap_bijections,
} => (
*old_len,
*new_len,
replacements,
qubit_bijection_invariant
&& valid_clean_gap_bijections(
before,
after,
replacements,
clean_gap_bijections,
),
true,
),
RewriteEdits::Unknown => {
self.invalidate_for_full_scan();
return;
}
};
if before.operations().len() != old_len
|| after.operations().len() != new_len
|| !is_linear_workspace_eligible(before)
|| !is_linear_workspace_eligible(after)
|| !valid_replacements(old_len, new_len, replacements)
|| !valid_correspondence
{
self.invalidate_for_full_scan();
return;
}
let Some(gate_histogram) =
certificate
.gate_histogram
.after_linear_replacements(before, after, replacements)
else {
self.invalidate_for_full_scan();
return;
};
let pending_ranges =
map_and_invalidate_ranges(&pending_ranges, replacements, old_len, new_len, proof_reach);
let workspace = self
.certificate
.as_mut()
.and_then(|certificate| certificate.workspace.take())
.and_then(|workspace| {
workspace.after_linear_replacements(after, replacements, qubits_renamed)
});
let certificate = self
.certificate
.as_mut()
.expect("certificate was validated above");
certificate.pending_ranges = pending_ranges;
certificate.circuit_revision = new_revision;
certificate.gate_histogram = gate_histogram;
certificate.workspace = workspace;
}
pub(crate) fn take_reconciled_linear_state(
&mut self,
circuit_revision: u64,
requested: &RewriteConfig,
) -> LinearRewriteReconciliation {
let Some(certificate) = self.certificate.as_mut() else {
return LinearRewriteReconciliation {
state: None,
full_scan_fallback: std::mem::take(&mut self.pending_full_scan_fallback),
};
};
if certificate.circuit_revision != circuit_revision
|| !config_is_proven_subset(
requested,
&certificate.proof_config,
Some(&certificate.gate_histogram),
)
{
return LinearRewriteReconciliation {
state: None,
full_scan_fallback: true,
};
}
LinearRewriteReconciliation {
state: Some((
certificate.pending_ranges.clone(),
certificate.workspace.take(),
)),
full_scan_fallback: false,
}
}
fn invalidate_for_full_scan(&mut self) {
if self.certificate.take().is_some() {
self.pending_full_scan_fallback = true;
}
}
}
#[cfg(test)]
#[path = "session_test.rs"]
mod session_test;