Struct mz_transform::analysis::equivalences::EquivalenceClasses
source · pub struct EquivalenceClasses {
pub classes: Vec<Vec<MirScalarExpr>>,
remap: BTreeMap<MirScalarExpr, MirScalarExpr>,
}
Expand description
A compact representation of classes of expressions that must be equivalent.
Each “class” contains a list of expressions, each of which must be Eq::eq
equal.
Ideally, the first element is the “simplest”, e.g. a literal or column reference,
and any other element of that list can be replaced by it.
The classes are meant to be minimized, with each expression as reduced as it can be, and all classes sharing an element merged.
Fields§
§classes: Vec<Vec<MirScalarExpr>>
Multiple lists of equivalent expressions, each representing an equivalence class.
The first element should be the “canonical” simplest element, that any other element
can be replaced by.
These classes are unified whenever possible, to minimize the number of classes.
They are only guaranteed to form an equivalence relation after a call to minimize
,
which refreshes both self.classes
and self.remap
.
remap: BTreeMap<MirScalarExpr, MirScalarExpr>
An expression simplification map.
This map reflects an equivalence relation based on a prior version of self.classes
.
As users may add to self.classes
, self.remap
may become stale. We refresh remap
only in self.refresh()
, to the equivalence relation that derives from self.classes
.
It is important to self.remap.clear()
if you invalidate it by mutating rather than
appending to self.classes
. This will be corrected in the next call to self.refresh()
,
but until then remap
could be arbitrarily wrong. This should be improved in the future.
Implementations§
source§impl EquivalenceClasses
impl EquivalenceClasses
sourcepub fn mir_scalar_expr_complexity(
e1: &MirScalarExpr,
e2: &MirScalarExpr,
) -> Ordering
pub fn mir_scalar_expr_complexity( e1: &MirScalarExpr, e2: &MirScalarExpr, ) -> Ordering
Comparator function for the complexity of scalar expressions. Simpler expressions are smaller. Can be used when we need to decide which of several equivalent expressions to use.
sourcefn tidy(&mut self)
fn tidy(&mut self)
Sorts and deduplicates each class, removing literal errors.
This method does not ensure equivalence relation structure, but instead performs only minimal structural clean-up.
sourcefn refresh(&mut self) -> bool
fn refresh(&mut self) -> bool
Restore equivalence relation structure to self.classes
and refresh self.remap
.
This method takes roughly linear time, and returns true iff self.remap
has changed.
This is the only method that refreshes self.remap
, and is a perfect place to decide
whether the equivalence classes it represents have experienced any changes since the
last refresh.
sourcepub fn minimize(&mut self, columns: Option<&[ColumnType]>)
pub fn minimize(&mut self, columns: Option<&[ColumnType]>)
Update self
to maintain the same equivalences which potentially reducing along Ord::le
.
Informally this means simplifying constraints, removing redundant constraints, and unifying equivalence classes.
sourcefn expand(&self) -> Vec<Vec<MirScalarExpr>>
fn expand(&self) -> Vec<Vec<MirScalarExpr>>
Proposes new equivalences that are likely to be novel.
This method invokes self.implications()
to propose equivalences, and then judges them to be
novel or not based on existing knowledge, reducing the equivalences down to their novel core.
This method may produce non-novel equivalences, due to its inability to perform MSE::reduce
.
We can end up with e.g. constant expressions that cannot be found until they are so reduced.
The novelty detection is best-effort, and meant to provide a clearer signal and minimize the
number of times we call and amount of work we do in self.refresh()
.
sourcefn implications(&self) -> Vec<Vec<MirScalarExpr>>
fn implications(&self) -> Vec<Vec<MirScalarExpr>>
Derives potentially novel equivalences without regard for minimization.
This is an opportunity to explore equivalences that do not correspond to expression minimization,
and therefore should not be used in minimize_once
. They are still potentially important, but
required additional guardrails to ensure we reach a fixed point.
The implications will be introduced into self.classes
and will prompt a round of minimization,
making it somewhat polite to avoid producing outputs that cannot result in novel equivalences.
For example, before producing a new equivalence, one could check that the involved terms are not
already present in the same class.
sourcefn minimize_once(&mut self, columns: Option<&[ColumnType]>) -> bool
fn minimize_once(&mut self, columns: Option<&[ColumnType]>) -> bool
A single iteration of minimization, which we expect to repeat but benefit from factoring out.
This invocation should take roughly linear time. It starts with equivalence class invariants maintained (closed under transitivity), and then
- Performs per-expression reduction, including the class structure to replace subexpressions.
- Applies idiom detection to e.g. unpack expressions equivalence to literal true or false.
- Restores the equivalence class invariants.
sourcepub fn union_many<'a, I>(&self, others: I) -> Selfwhere
I: IntoIterator<Item = &'a Self>,
pub fn union_many<'a, I>(&self, others: I) -> Selfwhere
I: IntoIterator<Item = &'a Self>,
The equivalence classes of terms equivalent in all inputs.
This method relies on the remap
member of each input, and bases the intersection on these rather than classes
.
This means one should ensure minimize()
has been called on all inputs, or risk getting a stale, but conservatively
correct, result.
This method currently misses opportunities, because it only looks for exactly matches in expressions,
which may not include all possible matches. For example, f(#1) == g(#1)
may exist in one class, but
in another class where #0 == #1
it may exist as f(#0) == g(#0)
.
sourcepub fn permute(&mut self, permutation: &[usize])
pub fn permute(&mut self, permutation: &[usize])
Permutes each expression, looking up each column reference in permutation
and replacing with what it finds.
sourcepub fn project<I>(&mut self, output_columns: I)
pub fn project<I>(&mut self, output_columns: I)
Subject the constraints to the column projection, reworking and removing equivalences.
This method should also introduce equivalences representing any repeated columns.
sourcepub fn unsatisfiable(&self) -> bool
pub fn unsatisfiable(&self) -> bool
True if any equivalence class contains two distinct non-error literals.
sourcepub fn reducer(&self) -> &BTreeMap<MirScalarExpr, MirScalarExpr>
pub fn reducer(&self) -> &BTreeMap<MirScalarExpr, MirScalarExpr>
Returns a map that can be used to replace (sub-)expressions.
sourcefn class_contains_literal<P>(class: &[MirScalarExpr], predicate: P) -> bool
fn class_contains_literal<P>(class: &[MirScalarExpr], predicate: P) -> bool
Examines the prefix of class
of literals, looking for any satisfying predicate
.
This test bails out as soon as it sees a non-literal, and may have false negatives if the data are not sorted with literals at the front.
Trait Implementations§
source§impl Clone for EquivalenceClasses
impl Clone for EquivalenceClasses
source§fn clone(&self) -> EquivalenceClasses
fn clone(&self) -> EquivalenceClasses
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for EquivalenceClasses
impl Debug for EquivalenceClasses
source§impl Default for EquivalenceClasses
impl Default for EquivalenceClasses
source§fn default() -> EquivalenceClasses
fn default() -> EquivalenceClasses
source§impl Display for EquivalenceClasses
impl Display for EquivalenceClasses
source§impl Ord for EquivalenceClasses
impl Ord for EquivalenceClasses
source§fn cmp(&self, other: &EquivalenceClasses) -> Ordering
fn cmp(&self, other: &EquivalenceClasses) -> Ordering
1.21.0 · source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
source§impl PartialEq for EquivalenceClasses
impl PartialEq for EquivalenceClasses
source§impl PartialOrd for EquivalenceClasses
impl PartialOrd for EquivalenceClasses
impl Eq for EquivalenceClasses
impl StructuralPartialEq for EquivalenceClasses
Auto Trait Implementations§
impl Freeze for EquivalenceClasses
impl RefUnwindSafe for EquivalenceClasses
impl Send for EquivalenceClasses
impl Sync for EquivalenceClasses
impl Unpin for EquivalenceClasses
impl UnwindSafe for EquivalenceClasses
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
source§impl<T> FmtForward for T
impl<T> FmtForward for T
source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.source§impl<T> FutureExt for T
impl<T> FutureExt for T
source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request
source§impl<T, U> OverrideFrom<Option<&T>> for Uwhere
U: OverrideFrom<T>,
impl<T, U> OverrideFrom<Option<&T>> for Uwhere
U: OverrideFrom<T>,
source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moresource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.source§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<T> PreferredContainer for T
impl<T> PreferredContainer for T
source§impl<T> ProgressEventTimestamp for T
impl<T> ProgressEventTimestamp for T
source§impl<P, R> ProtoType<R> for Pwhere
R: RustType<P>,
impl<P, R> ProtoType<R> for Pwhere
R: RustType<P>,
source§fn into_rust(self) -> Result<R, TryFromProtoError>
fn into_rust(self) -> Result<R, TryFromProtoError>
RustType::from_proto
.source§fn from_rust(rust: &R) -> P
fn from_rust(rust: &R) -> P
RustType::into_proto
.source§impl<'a, S, T> Semigroup<&'a S> for Twhere
T: Semigroup<S>,
impl<'a, S, T> Semigroup<&'a S> for Twhere
T: Semigroup<S>,
source§fn plus_equals(&mut self, rhs: &&'a S)
fn plus_equals(&mut self, rhs: &&'a S)
std::ops::AddAssign
, for types that do not implement AddAssign
.source§impl<T> Tap for T
impl<T> Tap for T
source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moresource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moresource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moresource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moresource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moresource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moresource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.