mirror of
https://github.com/powdr-labs/powdr.git
synced 2026-04-20 03:03:25 -04:00
Create row struct (#1510)
This commit is contained in:
@@ -208,7 +208,7 @@ mod tests {
|
||||
|
||||
for &(i, name, expected) in asserted_values.iter() {
|
||||
let poly_id = poly_ids[name];
|
||||
let actual: T = data[i][&poly_id].value_or_zero();
|
||||
let actual: T = data[i].value_or_zero(&poly_id);
|
||||
assert_eq!(actual, T::from(expected));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -62,7 +62,7 @@ impl<V, T: PolynomialTypeTrait> ColumnMap<V, T> {
|
||||
let mut values: Vec<V> = (0..len).map(|_| V::default()).collect();
|
||||
for (poly, value) in items {
|
||||
values[poly.id as usize] = value;
|
||||
assert_eq!(poly.ptype, T::P_TYPE);
|
||||
debug_assert_eq!(poly.ptype, T::P_TYPE);
|
||||
}
|
||||
|
||||
ColumnMap {
|
||||
@@ -90,17 +90,40 @@ impl<V, T: PolynomialTypeTrait> ColumnMap<V, T> {
|
||||
self.values.iter()
|
||||
}
|
||||
|
||||
pub fn values_into_iter(self) -> impl Iterator<Item = V> {
|
||||
self.values.into_iter()
|
||||
}
|
||||
|
||||
pub fn values_iter_mut(&mut self) -> impl Iterator<Item = &mut V> {
|
||||
self.values.iter_mut()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.values.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, T: PolynomialTypeTrait> Default for ColumnMap<V, T> {
|
||||
fn default() -> Self {
|
||||
ColumnMap {
|
||||
values: Vec::new(),
|
||||
_ptype: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: PartialEq, T: PolynomialTypeTrait> PartialEq for ColumnMap<V, T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.values == other.values
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, T: PolynomialTypeTrait> Index<&PolyID> for ColumnMap<V, T> {
|
||||
type Output = V;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, poly_id: &PolyID) -> &Self::Output {
|
||||
assert!(poly_id.ptype == T::P_TYPE);
|
||||
debug_assert!(poly_id.ptype == T::P_TYPE);
|
||||
&self.values[poly_id.id as usize]
|
||||
}
|
||||
}
|
||||
@@ -108,7 +131,7 @@ impl<V, T: PolynomialTypeTrait> Index<&PolyID> for ColumnMap<V, T> {
|
||||
impl<V, T: PolynomialTypeTrait> IndexMut<&PolyID> for ColumnMap<V, T> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, poly_id: &PolyID) -> &mut Self::Output {
|
||||
assert!(poly_id.ptype == T::P_TYPE);
|
||||
debug_assert!(poly_id.ptype == T::P_TYPE);
|
||||
&mut self.values[poly_id.id as usize]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use bit_vec::BitVec;
|
||||
use powdr_ast::analyzed::PolyID;
|
||||
use powdr_number::FieldElement;
|
||||
|
||||
use crate::witgen::rows::{finalize_row, Row};
|
||||
use crate::witgen::rows::Row;
|
||||
|
||||
/// A row entry in [FinalizableData].
|
||||
#[derive(Clone)]
|
||||
@@ -125,8 +125,8 @@ impl<'a, T: FieldElement> FinalizableData<'a, T> {
|
||||
}
|
||||
|
||||
pub fn finalize(&mut self, i: usize) -> bool {
|
||||
if let Entry::InProgress(row) = &self.data[i] {
|
||||
self.data[i] = Entry::Finalized(finalize_row(row, &self.column_ids));
|
||||
if let Entry::InProgress(row) = &mut self.data[i] {
|
||||
self.data[i] = Entry::Finalized(row.finalize(&self.column_ids));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
||||
@@ -5,7 +5,6 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use crate::witgen::data_structures::finalizable_data::FinalizableData;
|
||||
use crate::witgen::machines::profiling::{record_end, record_start};
|
||||
use crate::witgen::processor::OuterQuery;
|
||||
use crate::witgen::rows::merge_row_with;
|
||||
use crate::witgen::EvalValue;
|
||||
use crate::Identity;
|
||||
|
||||
@@ -216,7 +215,8 @@ impl<'a, T: FieldElement> Generator<'a, T> {
|
||||
is_main_run: bool,
|
||||
) -> ProcessResult<'a, T> {
|
||||
log::trace!(
|
||||
"Running main machine from row {row_offset} with the following initial values in the first row:\n{}", first_row.render_values(false, None)
|
||||
"Running main machine from row {row_offset} with the following initial values in the first row:\n{}",
|
||||
first_row.render_values(false, None, self.fixed_data)
|
||||
);
|
||||
let data = FinalizableData::with_initial_rows_in_progress(
|
||||
&self.witnesses,
|
||||
@@ -244,6 +244,6 @@ impl<'a, T: FieldElement> Generator<'a, T> {
|
||||
assert_eq!(self.data.len() as DegreeType, self.fixed_data.degree + 1);
|
||||
|
||||
let last_row = self.data.pop().unwrap();
|
||||
merge_row_with(&mut self.data[0], &last_row).unwrap();
|
||||
self.data[0].merge_with(&last_row).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::witgen::block_processor::BlockProcessor;
|
||||
use crate::witgen::data_structures::finalizable_data::FinalizableData;
|
||||
use crate::witgen::identity_processor::IdentityProcessor;
|
||||
use crate::witgen::processor::{OuterQuery, Processor};
|
||||
use crate::witgen::rows::{merge_row_with, Row, RowIndex, RowPair, UnknownStrategy};
|
||||
use crate::witgen::rows::{Row, RowIndex, RowPair, UnknownStrategy};
|
||||
use crate::witgen::sequence_iterator::{
|
||||
DefaultSequenceIterator, ProcessingSequenceCache, ProcessingSequenceIterator,
|
||||
};
|
||||
@@ -644,15 +644,16 @@ impl<'a, T: FieldElement> BlockMachine<'a, T> {
|
||||
// 1. Ignore the first row of the next block:
|
||||
new_block.pop();
|
||||
// 2. Merge the last row of the previous block
|
||||
merge_row_with(
|
||||
new_block.get_mut(0).unwrap(),
|
||||
self.get_row(self.last_row_index()),
|
||||
)
|
||||
.map_err(|_| {
|
||||
EvalError::Generic(
|
||||
"Block machine overwrites existing value with different value!".to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
new_block
|
||||
.get_mut(0)
|
||||
.unwrap()
|
||||
.merge_with(self.get_row(self.last_row_index()))
|
||||
.map_err(|_| {
|
||||
EvalError::Generic(
|
||||
"Block machine overwrites existing value with different value!".to_string(),
|
||||
)
|
||||
})?;
|
||||
// 3. Remove the last row of the previous block from data
|
||||
self.data.pop();
|
||||
|
||||
|
||||
@@ -4,11 +4,9 @@ use powdr_ast::analyzed::PolynomialType;
|
||||
use powdr_ast::analyzed::{AlgebraicExpression as Expression, AlgebraicReference, PolyID};
|
||||
use powdr_number::{DegreeType, FieldElement};
|
||||
|
||||
use crate::witgen::rows::set_cell_unknown;
|
||||
use crate::witgen::{query_processor::QueryProcessor, util::try_to_simple_poly, Constraint};
|
||||
use crate::Identity;
|
||||
|
||||
use super::rows::value_is_known;
|
||||
use super::{
|
||||
affine_expression::AffineExpression,
|
||||
data_structures::{
|
||||
@@ -225,14 +223,22 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> Processor<'a, 'b, 'c, T,
|
||||
Known values in current row (local: {row_index}, global {global_row_index}):
|
||||
{}
|
||||
",
|
||||
self.data[row_index].render_values(false, Some(self.witness_cols))
|
||||
self.data[row_index].render_values(
|
||||
false,
|
||||
Some(self.witness_cols),
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
if identity.contains_next_ref() {
|
||||
error += &format!(
|
||||
"Known values in next row (local: {}, global {}):\n{}\n",
|
||||
row_index + 1,
|
||||
global_row_index + 1,
|
||||
self.data[row_index + 1].render_values(false, Some(self.witness_cols))
|
||||
self.data[row_index + 1].render_values(
|
||||
false,
|
||||
Some(self.witness_cols),
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
}
|
||||
error += &format!(" => Error: {e}");
|
||||
@@ -319,7 +325,7 @@ Known values in current row (local: {row_index}, global {global_row_index}):
|
||||
pub fn set_inputs_if_unset(&mut self, row_index: usize) -> bool {
|
||||
let mut input_updates = EvalValue::complete(vec![]);
|
||||
for (poly_id, value) in self.inputs.iter() {
|
||||
if !value_is_known(&self.data[row_index], poly_id) {
|
||||
if !self.data[row_index].value_is_known(poly_id) {
|
||||
input_updates.combine(EvalValue::complete(vec![(
|
||||
&self.fixed_data.witness_cols[poly_id].poly,
|
||||
Constraint::Assignment(*value),
|
||||
@@ -335,7 +341,7 @@ Known values in current row (local: {row_index}, global {global_row_index}):
|
||||
self.fixed_data.column_name(poly_id)
|
||||
);
|
||||
for row_index in start_row..row_index {
|
||||
set_cell_unknown(&mut self.data[row_index], poly_id);
|
||||
self.data[row_index].set_cell_unknown(poly_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,8 +520,14 @@ Known values in current row (local: {row_index}, global {global_row_index}):
|
||||
.process_identity(identity, &row_pair)
|
||||
.is_err()
|
||||
{
|
||||
log::debug!("Previous {:?}", &self.data[row_index - 1]);
|
||||
log::debug!("Proposed {:?}", proposed_row);
|
||||
log::debug!(
|
||||
"Previous {}",
|
||||
self.data[row_index - 1].render_values(true, None, self.fixed_data)
|
||||
);
|
||||
log::debug!(
|
||||
"Proposed {:?}",
|
||||
proposed_row.render_values(true, None, self.fixed_data)
|
||||
);
|
||||
log::debug!("Failed on identity: {}", identity);
|
||||
|
||||
return false;
|
||||
|
||||
@@ -34,7 +34,7 @@ impl<'a, 'b, T: FieldElement, QueryCallback: super::QueryCallback<T>>
|
||||
) -> Option<EvalResult<'a, T>> {
|
||||
let column = &self.fixed_data.witness_cols[poly_id];
|
||||
|
||||
if rows.get_value(&column.poly).is_none() {
|
||||
if !rows.value_is_known(&column.poly) {
|
||||
Some(self.process_witness_query(column.query.unwrap(), &column.poly, rows))
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
fmt::Debug,
|
||||
fmt::Display,
|
||||
ops::{Add, Sub},
|
||||
};
|
||||
|
||||
@@ -105,16 +105,17 @@ impl Sub<RowIndex> for RowIndex {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RowIndex {
|
||||
impl Display for RowIndex {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[derive(Default, Clone, PartialEq)]
|
||||
enum CellValue<T: FieldElement> {
|
||||
Known(T),
|
||||
RangeConstraint(RangeConstraint<T>),
|
||||
#[default]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@@ -123,217 +124,209 @@ impl<T: FieldElement> CellValue<T> {
|
||||
matches!(self, CellValue::Known(_))
|
||||
}
|
||||
|
||||
pub fn unwrap_or_default(&self) -> T {
|
||||
/// Returns the value if known, otherwise zero.
|
||||
pub fn unwrap_or_zero(&self) -> T {
|
||||
match self {
|
||||
CellValue::Known(v) => *v,
|
||||
_ => Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the new combined range constraint or new value for this cell.
|
||||
/// Returns Some(value) if known, otherwise None.
|
||||
pub fn value(&self) -> Option<T> {
|
||||
match self {
|
||||
CellValue::Known(v) => Some(*v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the cell with the new combined range constraint or new value for this cell.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the update is not an improvement.
|
||||
pub fn update_with(&self, c: &Constraint<T>) -> Self {
|
||||
match (self, c) {
|
||||
pub fn apply_update(&mut self, c: &Constraint<T>) {
|
||||
match (&self, c) {
|
||||
(CellValue::Known(_), _) => {
|
||||
// Note that this is a problem even if the value that was set is the same,
|
||||
// because we would return that progress was made when it wasn't.
|
||||
panic!("Value was already set.");
|
||||
}
|
||||
(_, Constraint::Assignment(v)) => CellValue::Known(*v),
|
||||
(_, Constraint::Assignment(v)) => {
|
||||
*self = CellValue::Known(*v);
|
||||
}
|
||||
(CellValue::RangeConstraint(current), Constraint::RangeConstraint(c)) => {
|
||||
let new = c.conjunction(current);
|
||||
assert!(new != *current, "Range constraint was already set");
|
||||
log::trace!(" (the conjunction is {})", new);
|
||||
CellValue::RangeConstraint(new)
|
||||
*self = CellValue::RangeConstraint(new)
|
||||
}
|
||||
(CellValue::Unknown, Constraint::RangeConstraint(c)) => {
|
||||
CellValue::RangeConstraint(c.clone())
|
||||
*self = CellValue::RangeConstraint(c.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FieldElement> From<CellValue<T>> for Option<T> {
|
||||
fn from(val: CellValue<T>) -> Self {
|
||||
match val {
|
||||
CellValue::Known(v) => Some(v),
|
||||
impl<T: FieldElement> Display for CellValue<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
CellValue::Known(v) => write!(f, "{v}"),
|
||||
CellValue::RangeConstraint(rc) => write!(f, "? (range constraint: {rc})"),
|
||||
CellValue::Unknown => write!(f, "?"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Row<'a, T: FieldElement> {
|
||||
values: WitnessColumnMap<CellValue<T>>,
|
||||
// TODO remove this.
|
||||
names: Vec<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a, T: FieldElement> Row<'a, T> {
|
||||
pub fn value_or_zero(&self, poly_id: &PolyID) -> T {
|
||||
self.values[poly_id].unwrap_or_zero()
|
||||
}
|
||||
|
||||
pub fn value(&self, poly_id: &PolyID) -> Option<T> {
|
||||
self.values[poly_id].value()
|
||||
}
|
||||
|
||||
pub fn range_constraint(&self, poly_id: &PolyID) -> Option<RangeConstraint<T>> {
|
||||
match &self.values[poly_id] {
|
||||
CellValue::RangeConstraint(c) => Some(c.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A single cell, holding an optional value and range constraint.
|
||||
#[derive(Clone)]
|
||||
pub struct Cell<'a, T: FieldElement> {
|
||||
/// The column name, for debugging purposes.
|
||||
name: &'a str,
|
||||
value: CellValue<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: FieldElement> Cell<'a, T> {
|
||||
/// Applies the new range constraint or new value to this cell.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the update is not an improvement.
|
||||
pub fn apply_update(&mut self, c: &Constraint<T>) {
|
||||
self.value = self.value.update_with(c);
|
||||
}
|
||||
|
||||
/// Returns the value if it is known or zero if it is unknown.
|
||||
pub fn value_or_zero(&self) -> T {
|
||||
self.value.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FieldElement> Debug for Cell<'_, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let debug_str = match &self.value {
|
||||
CellValue::Known(v) => format!("{} = {}", self.name, v),
|
||||
CellValue::RangeConstraint(rc) => {
|
||||
format!("{} = ? (range constraint: {})", self.name, rc)
|
||||
}
|
||||
CellValue::Unknown => format!("{} = ?", self.name),
|
||||
/// Merges two rows, updating the first.
|
||||
/// Range constraints from the second row are ignored.
|
||||
pub fn merge_with(&mut self, other: &Row<'a, T>) -> Result<(), ()> {
|
||||
// First check for conflicts, otherwise we would have to roll back changes.
|
||||
if self
|
||||
.values
|
||||
.values()
|
||||
.zip(other.values.values())
|
||||
.any(|(cell1, cell2)| match (&cell1, &cell2) {
|
||||
(CellValue::Known(v1), CellValue::Known(v2)) => v1 != v2,
|
||||
_ => false,
|
||||
})
|
||||
{
|
||||
return Err(());
|
||||
};
|
||||
f.write_str(&debug_str)
|
||||
|
||||
self.values
|
||||
.values_iter_mut()
|
||||
.zip(other.values.values())
|
||||
.for_each(|(cell1, cell2)| match (&cell1, &cell2) {
|
||||
(CellValue::Known(_), _) => {}
|
||||
_ => *cell1 = cell2.clone(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub type Row<'a, T> = WitnessColumnMap<Cell<'a, T>>;
|
||||
pub fn value_is_known(&self, poly_id: &PolyID) -> bool {
|
||||
self.values[poly_id].is_known()
|
||||
}
|
||||
|
||||
/// Merges two rows, updating the first.
|
||||
/// Range constraints from the second row are ignored.
|
||||
pub fn merge_row_with<'a, T: FieldElement>(
|
||||
row: &mut Row<'a, T>,
|
||||
other: &Row<'a, T>,
|
||||
) -> Result<(), ()> {
|
||||
// First check for conflicts, otherwise we would have to roll back changes.
|
||||
if row
|
||||
.values()
|
||||
.zip(other.values())
|
||||
.any(|(cell1, cell2)| match (&cell1.value, &cell2.value) {
|
||||
(CellValue::Known(v1), CellValue::Known(v2)) => v1 != v2,
|
||||
_ => false,
|
||||
})
|
||||
{
|
||||
return Err(());
|
||||
};
|
||||
*row = WitnessColumnMap::from(row.values().zip(other.values()).map(|(cell1, cell2)| {
|
||||
match (&cell1.value, &cell2.value) {
|
||||
(CellValue::Known(_), _) => cell1.clone(),
|
||||
_ => cell2.clone(),
|
||||
}
|
||||
}));
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_cell_unknown(&mut self, poly_id: &PolyID) {
|
||||
self.values[poly_id] = CellValue::Unknown;
|
||||
}
|
||||
|
||||
// TODO will be impl method of row later.
|
||||
pub fn value_is_known<T: FieldElement>(row: &Row<'_, T>, poly_id: &PolyID) -> bool {
|
||||
row[poly_id].value.is_known()
|
||||
}
|
||||
pub fn apply_update(&mut self, poly_id: &PolyID, constr: &Constraint<T>) {
|
||||
self.values[poly_id].apply_update(constr);
|
||||
}
|
||||
|
||||
// TODO will be impl method of row later.
|
||||
pub fn set_cell_unknown<T: FieldElement>(row: &mut Row<'_, T>, poly_id: &PolyID) {
|
||||
row[poly_id].value = CellValue::Unknown;
|
||||
}
|
||||
|
||||
// TODO will be impl method of row later.
|
||||
/// Returns true if the values and known constraints are equal for the two rows.
|
||||
pub fn rows_are_equal<T: FieldElement>(row1: &Row<'_, T>, row2: &Row<'_, T>) -> bool {
|
||||
row1.values()
|
||||
.zip(row2.values())
|
||||
.all(|(cell1, cell2)| cell1.value == cell2.value)
|
||||
}
|
||||
|
||||
// TODO will be impl method of row later.
|
||||
// TODO we need to get rid of column_ids and ensure that the vector is already in that shape.
|
||||
pub fn finalize_row<'a, T: FieldElement>(
|
||||
row: &Row<'_, T>,
|
||||
column_ids: impl IntoIterator<Item = &'a PolyID>,
|
||||
) -> FinalizedRow<T> {
|
||||
let (values, know_cells) = column_ids
|
||||
.into_iter()
|
||||
.map(|c| (row[c].value.unwrap_or_default(), row[c].value.is_known()))
|
||||
.unzip();
|
||||
FinalizedRow::new(values, know_cells)
|
||||
}
|
||||
|
||||
impl<T: FieldElement> Debug for Row<'_, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Row:\n{}", self.render_values(true, None))
|
||||
pub fn finalize(&self, column_ids: &[PolyID]) -> FinalizedRow<T> {
|
||||
let (values, known_cells) = column_ids
|
||||
.iter()
|
||||
.map(|poly_id| {
|
||||
// TODO avoid these accesses.
|
||||
let cell = &self.values[poly_id];
|
||||
(cell.unwrap_or_zero(), cell.is_known())
|
||||
})
|
||||
.unzip();
|
||||
FinalizedRow::new(values, known_cells)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FieldElement> Row<'a, T> {
|
||||
/// Creates a "fresh" row, i.e., one that is empty but initialized with the global range constraints.
|
||||
pub fn fresh(fixed_data: &'a FixedData<'a, T>, row: RowIndex) -> Row<'a, T> {
|
||||
WitnessColumnMap::from(
|
||||
// TODO this instance could be computed exactly once (per column set) and then cloned.
|
||||
// TODO and we could copy in the external witnesses later on
|
||||
// TODO we should really only have a subset of the columns.
|
||||
let values = WitnessColumnMap::from(
|
||||
fixed_data
|
||||
.global_range_constraints()
|
||||
.witness_constraints
|
||||
.iter()
|
||||
.map(|(poly_id, range_constraint)| {
|
||||
let name = fixed_data.column_name(&poly_id);
|
||||
let value = match (
|
||||
fixed_data.external_witness(row.into(), &poly_id),
|
||||
range_constraint.as_ref(),
|
||||
) {
|
||||
(Some(external_witness), _) => CellValue::Known(external_witness),
|
||||
(None, Some(range_constraint)) => {
|
||||
CellValue::RangeConstraint(range_constraint.clone())
|
||||
}
|
||||
(None, None) => CellValue::Unknown,
|
||||
};
|
||||
Cell { name, value }
|
||||
.map(|(poly_id, rc)| {
|
||||
if let Some(external_witness) =
|
||||
fixed_data.external_witness(row.into(), &poly_id)
|
||||
{
|
||||
CellValue::Known(external_witness)
|
||||
} else if let Some(rc) = rc {
|
||||
CellValue::RangeConstraint(rc.clone())
|
||||
} else {
|
||||
CellValue::Unknown
|
||||
}
|
||||
}),
|
||||
)
|
||||
);
|
||||
Self {
|
||||
values,
|
||||
names: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a string representing the current row
|
||||
pub fn render(&self, title: &str, include_unknown: bool, cols: &HashSet<PolyID>) -> String {
|
||||
pub fn render(
|
||||
&self,
|
||||
title: &str,
|
||||
include_unknown: bool,
|
||||
cols: &HashSet<PolyID>,
|
||||
fixed_data: &FixedData<'_, T>,
|
||||
) -> String {
|
||||
format!(
|
||||
"{}:\n{}\n---------------------",
|
||||
title,
|
||||
self.render_values(include_unknown, Some(cols))
|
||||
self.render_values(include_unknown, Some(cols), fixed_data)
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds a string listing all values, one by row. Nonzero entries are
|
||||
/// first, then zero, then unknown (if `include_unknown == true`).
|
||||
pub fn render_values(&self, include_unknown: bool, cols: Option<&HashSet<PolyID>>) -> String {
|
||||
let mut cells = self
|
||||
pub fn render_values(
|
||||
&self,
|
||||
include_unknown: bool,
|
||||
cols: Option<&HashSet<PolyID>>,
|
||||
fixed_data: &FixedData<'_, T>,
|
||||
) -> String {
|
||||
self.values
|
||||
.iter()
|
||||
.filter(|(_, cell)| cell.value.is_known() || include_unknown)
|
||||
.filter(|(_, cell)| cell.is_known() || include_unknown)
|
||||
.filter(|(col, _)| cols.map(|cols| cols.contains(col)).unwrap_or(true))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Nonzero first, then zero, then unknown
|
||||
cells.sort_by_key(|(i, cell)| {
|
||||
(
|
||||
match cell.value {
|
||||
CellValue::Known(v) if v.is_zero() => 1,
|
||||
CellValue::Known(_) => 0,
|
||||
_ => 2,
|
||||
},
|
||||
*i,
|
||||
)
|
||||
});
|
||||
|
||||
cells
|
||||
.into_iter()
|
||||
.map(|(_, cell)| format!(" {cell:?}"))
|
||||
// Nonzero first, then zero, then unknown
|
||||
.sorted_by_key(|(i, cell)| {
|
||||
(
|
||||
match cell {
|
||||
CellValue::Known(v) if v.is_zero() => 1,
|
||||
CellValue::Known(_) => 0,
|
||||
_ => 2,
|
||||
},
|
||||
*i,
|
||||
)
|
||||
})
|
||||
.map(|(poly_id, cell)| format!(" {} = {cell}", fixed_data.column_name(&poly_id)))
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FieldElement> From<Row<'_, T>> for WitnessColumnMap<T> {
|
||||
/// Builds a map from polynomial ID to value. Unknown values are set to zero.
|
||||
fn from(val: Row<T>) -> Self {
|
||||
WitnessColumnMap::from(
|
||||
val.into_iter()
|
||||
.map(|(_, cell)| cell.value.unwrap_or_default()),
|
||||
)
|
||||
fn from(row: Row<T>) -> Self {
|
||||
WitnessColumnMap::from(row.values.values_into_iter().map(|c| c.unwrap_or_zero()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,13 +369,13 @@ impl<'row, 'a, T: FieldElement> RowUpdater<'row, 'a, T> {
|
||||
);
|
||||
}
|
||||
}
|
||||
self.get_cell_mut(poly).apply_update(c);
|
||||
self.get_row_mut(poly.next).apply_update(&poly.poly_id, c);
|
||||
}
|
||||
|
||||
fn get_cell_mut<'b>(&'b mut self, poly: &AlgebraicReference) -> &'b mut Cell<'a, T> {
|
||||
match poly.next {
|
||||
false => &mut self.current[&poly.poly_id],
|
||||
true => &mut self.next[&poly.poly_id],
|
||||
fn get_row_mut<'b>(&'b mut self, next: bool) -> &'b mut Row<'a, T> {
|
||||
match next {
|
||||
false => self.current,
|
||||
true => self.next,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,26 +438,34 @@ impl<'row, 'a, T: FieldElement> RowPair<'row, 'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the cell corresponding to the given polynomial reference.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the next row is accessed but the row pair has been constructed with
|
||||
/// [RowPair::from_single_row].
|
||||
fn get_cell(&self, poly: &AlgebraicReference) -> &Cell<T> {
|
||||
match (poly.next, self.next.as_ref()) {
|
||||
(false, _) => &self.current[&poly.poly_id],
|
||||
(true, Some(next)) => &next[&poly.poly_id],
|
||||
(true, None) => panic!("Tried to access next row, but it is not available."),
|
||||
pub fn value_is_known(&self, poly: &AlgebraicReference) -> bool {
|
||||
self.get_row_mut(poly.next).value_is_known(&poly.poly_id)
|
||||
}
|
||||
|
||||
fn get_row_mut(&self, next: bool) -> &Row<'a, T> {
|
||||
match next {
|
||||
false => self.current,
|
||||
true => self
|
||||
.next
|
||||
.unwrap_or_else(|| panic!("Tried to access next row, but it is not available.")),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_row(&self, next: bool) -> &Row<'a, T> {
|
||||
match next {
|
||||
false => self.current,
|
||||
true => self
|
||||
.next
|
||||
.unwrap_or_else(|| panic!("Tried to access next row, but it is not available.")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(&self, poly: &AlgebraicReference) -> Option<T> {
|
||||
match self.get_cell(poly).value {
|
||||
CellValue::Known(value) => Some(value),
|
||||
_ => match self.unknown_strategy {
|
||||
UnknownStrategy::Zero => Some(T::zero()),
|
||||
UnknownStrategy::Unknown => None,
|
||||
},
|
||||
let row = self.get_row(poly.next);
|
||||
if self.unknown_strategy == UnknownStrategy::Zero {
|
||||
Some(row.value_or_zero(&poly.poly_id))
|
||||
} else {
|
||||
row.value(&poly.poly_id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,9 +493,6 @@ impl<T: FieldElement> WitnessColumnEvaluator<T> for RowPair<'_, '_, T> {
|
||||
|
||||
impl<T: FieldElement> RangeConstraintSet<&AlgebraicReference, T> for RowPair<'_, '_, T> {
|
||||
fn range_constraint(&self, poly: &AlgebraicReference) -> Option<RangeConstraint<T>> {
|
||||
match self.get_cell(poly).value {
|
||||
CellValue::RangeConstraint(ref c) => Some(c.clone()),
|
||||
_ => None,
|
||||
}
|
||||
self.get_row(poly.next).range_constraint(&poly.poly_id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::Identity;
|
||||
use super::data_structures::finalizable_data::FinalizableData;
|
||||
use super::processor::{OuterQuery, Processor};
|
||||
|
||||
use super::rows::{rows_are_equal, Row, RowIndex, UnknownStrategy};
|
||||
use super::rows::{Row, RowIndex, UnknownStrategy};
|
||||
use super::{Constraints, EvalError, EvalValue, FixedData, MutableState, QueryCallback};
|
||||
|
||||
/// Maximal period checked during loop detection.
|
||||
@@ -219,12 +219,8 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'b, 'c, T
|
||||
|
||||
let row = row_index as usize;
|
||||
(1..MAX_PERIOD).find(|&period| {
|
||||
(1..=period).all(|i| {
|
||||
rows_are_equal(
|
||||
self.processor.row(row - i - period),
|
||||
self.processor.row(row - i),
|
||||
)
|
||||
})
|
||||
(1..=period)
|
||||
.all(|i| self.processor.row(row - i - period) == self.processor.row(row - i))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -297,7 +293,8 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'b, 'c, T
|
||||
row_index as DegreeType + self.row_offset
|
||||
),
|
||||
true,
|
||||
&self.witnesses
|
||||
&self.witnesses,
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
|
||||
@@ -442,7 +439,8 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'b, 'c, T
|
||||
self.processor.row(row_index).render(
|
||||
&format!("Current row ({row_index})"),
|
||||
false,
|
||||
&self.witnesses
|
||||
&self.witnesses,
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
log::debug!(
|
||||
@@ -450,7 +448,8 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'b, 'c, T
|
||||
self.processor.row(row_index + 1).render(
|
||||
&format!("Next row ({})", row_index + 1),
|
||||
false,
|
||||
&self.witnesses
|
||||
&self.witnesses,
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
log::debug!("Set RUST_LOG=trace to understand why these values were chosen.");
|
||||
@@ -478,7 +477,8 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'b, 'c, T
|
||||
self.processor.row(row_index).render(
|
||||
&format!("Current row ({row_index})"),
|
||||
true,
|
||||
&self.witnesses
|
||||
&self.witnesses,
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
log::debug!(
|
||||
@@ -486,7 +486,8 @@ impl<'a, 'b, 'c, T: FieldElement, Q: QueryCallback<T>> VmProcessor<'a, 'b, 'c, T
|
||||
self.processor.row(row_index + 1).render(
|
||||
&format!("Next row ({})", row_index + 1),
|
||||
true,
|
||||
&self.witnesses
|
||||
&self.witnesses,
|
||||
self.fixed_data,
|
||||
)
|
||||
);
|
||||
log::debug!("\nSet RUST_LOG=trace to understand why these values were (not) chosen.");
|
||||
|
||||
Reference in New Issue
Block a user