Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ef93167
Add multiset clear and fill index, and allow map to be added after mu…
saulshanabrook Nov 25, 2025
ce3a83b
Add flat map
saulshanabrook Nov 25, 2025
8223ed4
Add more multiset ops
saulshanabrook Nov 25, 2025
a0e9863
allow nested vec containers
saulshanabrook Jan 14, 2026
f0cda62
Merge fa1269569a98d89fd63454ba8f49f89ddd13d06b into multiset-changes
saulshanabrook Jan 16, 2026
3c80307
Add multiset fold and make map generic
saulshanabrook Jan 19, 2026
5575331
tmp
saulshanabrook Jan 26, 2026
e5a86ce
Add vec union
saulshanabrook Jan 28, 2026
9f83831
add failing merge fn test
saulshanabrook Jan 28, 2026
3da620a
depend on UF table for primitives
saulshanabrook Jan 29, 2026
8c3fb82
Makes some things public and add more vec methods
saulshanabrook Feb 3, 2026
3ece363
Fail on map failing instead of omitting elements for vec
saulshanabrook Feb 3, 2026
39e6ee4
Add log function
saulshanabrook Feb 5, 2026
b123f71
Add more ops
saulshanabrook Feb 17, 2026
8f67a18
Add filter not and fix filter
saulshanabrook Feb 25, 2026
e2bbf46
go back to only allowing filter on unit so type inference works
saulshanabrook Feb 25, 2026
1eee83c
Add subtract test
saulshanabrook Mar 2, 2026
d2ddb0c
Try switching registering maps to not use global
saulshanabrook Mar 5, 2026
d51ec5f
Refactor to remove global hack
saulshanabrook Mar 5, 2026
d3a7478
rename string log to println
saulshanabrook Mar 5, 2026
31748b4
reduce size of math microbenchmark
saulshanabrook Mar 5, 2026
f0bfe30
Merge main into multiset-changes
saulshanabrook Mar 5, 2026
55d7d16
Fix tests
saulshanabrook Mar 6, 2026
c4e12d2
nits fix
saulshanabrook Mar 6, 2026
d319866
Try removing set no default
saulshanabrook Mar 6, 2026
336a8ed
update snapshots
saulshanabrook Mar 6, 2026
f47ee8d
add code coverage
saulshanabrook Mar 6, 2026
544a8ac
fix reserved primitives
saulshanabrook Mar 6, 2026
bd57829
normalize use of is_eq_container_sort
saulshanabrook Mar 9, 2026
5f4a626
remove extra nits
saulshanabrook Mar 9, 2026
217f469
Check abs
saulshanabrook Mar 9, 2026
fc02e24
Rename fold to reduce
saulshanabrook Mar 9, 2026
49e9072
dont panic on int out of bound for multiset-single
saulshanabrook Mar 9, 2026
d2dee31
Remove public backend and only expose function traversal
saulshanabrook Mar 10, 2026
66b2778
Make functions private
saulshanabrook Mar 10, 2026
625f24d
Change `function_for_each` to take a function name instead of a function
saulshanabrook Mar 13, 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
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all test nits docs graphs rm-graphs doctest coverage insta-test
.PHONY: all test nits docs graphs rm-graphs doctest coverage insta-test fixnits

RUST_SRC=$(shell find . -type f -wholename '*/src/*.rs' -or -name 'Cargo.toml')
TESTS=$(shell find tests/ -type f -name '*.egg' -not -name '*repro-*')
Expand Down Expand Up @@ -28,7 +28,8 @@ nits:
fixnits:
@rustup component add rustfmt
cargo fmt
cargo clippy --fix --workspace --allow-dirty
@rustup component add rustfmt
Comment thread
saulshanabrook marked this conversation as resolved.
cargo clippy --fix --tests --workspace --allow-dirty

docs:
mkdir -p ${WWW}/
Expand Down
1 change: 1 addition & 0 deletions egglog-bridge/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,7 @@ impl MergeFn {
Primitive(_, args) => {
args.iter()
.for_each(|arg| arg.fill_deps(egraph, read_deps, write_deps));
write_deps.insert(egraph.uf_table);
}
Comment thread
saulshanabrook marked this conversation as resolved.
Function(func, args) => {
read_deps.insert(egraph.funcs[*func].table);
Expand Down
38 changes: 35 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ pub use ast::{ResolvedExpr, ResolvedFact, ResolvedVar};
#[cfg(feature = "bin")]
pub use cli::*;
use constraint::{Constraint, Problem, SimpleTypeConstraint, TypeConstraint};
use core::CoreActionContext;
use core::ResolvedAtomTerm;
pub use core::{Atom, AtomTerm};
use core::{CoreActionContext, ResolvedAtomTerm};
pub use core::{ResolvedCall, SpecializedPrimitive};
pub use core_relations::{BaseValue, ContainerValue, ExecutionState, Value};
use core_relations::{ExternalFunctionId, make_external_func};
Expand All @@ -50,7 +51,7 @@ use egglog_ast::generic_ast::{Change, GenericExpr, Literal};
use egglog_ast::span::Span;
use egglog_ast::util::ListDisplay;
pub use egglog_bridge::FunctionRow;
use egglog_bridge::{ColumnTy, QueryEntry};
use egglog_bridge::{ColumnTy, QueryEntry, UnionAction};
use egglog_core_relations as core_relations;
use egglog_numeric_id as numeric_id;
use egglog_reports::{ReportLevel, RunReport};
Expand Down Expand Up @@ -299,6 +300,11 @@ impl Function {
pub fn can_subsume(&self) -> bool {
self.can_subsume
}

/// Whether this is a let binding
pub fn is_let_binding(&self) -> bool {
self.decl.internal_let
}
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -350,7 +356,6 @@ impl Default for EGraph {
proof_state,
proof_check_program: vec![],
};

add_base_sort(&mut eg, UnitSort, span!()).unwrap();
add_base_sort(&mut eg, StringSort, span!()).unwrap();
add_base_sort(&mut eg, BoolSort, span!()).unwrap();
Expand Down Expand Up @@ -975,6 +980,28 @@ impl EGraph {
}
}

/// Get the list of all functions in the e-graph.
pub fn get_function_names(&self) -> Vec<String> {
self.functions.keys().cloned().collect()
}

/// Read the contents of the given function.
/// The callback f is called with each row and its subsumption status.
Comment thread
saulshanabrook marked this conversation as resolved.
///
/// Raises an error if the function does not exist.
pub fn function_for_each(
&self,
func_name: &str,
f: impl FnMut(FunctionRow<'_>),
) -> Result<(), Error> {
let func = self
.functions
.get(func_name)
.ok_or_else(|| TypeError::UnboundFunction(func_name.to_string(), span!()))?;
self.backend.for_each(func.backend_id, f);
Ok(())
}

/// Evaluates an expression, returns the sort of the expression and the evaluation result.
pub fn eval_expr(&mut self, expr: &Expr) -> Result<(ArcSort, Value), Error> {
let span = expr.span();
Expand Down Expand Up @@ -1799,6 +1826,11 @@ impl EGraph {
self.backend
.get_canon_repr(val, sort.column_ty(&self.backend))
}

/// Create a new union action that can be used to union two values.
pub fn new_union_action(&self) -> egglog_bridge::UnionAction {
UnionAction::new(&self.backend)
}
}

struct BackendRule<'a> {
Expand Down
14 changes: 11 additions & 3 deletions src/sort/fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ use std::sync::Mutex;
use super::*;

#[derive(Clone, Debug)]
pub struct FunctionContainer(ResolvedFunctionId, pub Vec<(ArcSort, Value)>, pub String);
pub struct FunctionContainer(
pub ResolvedFunctionId,
pub Vec<(ArcSort, Value)>,
pub String,
);

// implement hash and equality based on values only not arcsorts, since
// arcsorts are not comparable and any two values that are equal must have the same sort
Expand Down Expand Up @@ -57,7 +61,6 @@ impl ContainerValue for FunctionContainer {
self.1.iter().map(|(_, v)| v).copied()
}
}

#[derive(Debug)]
pub struct FunctionSort {
name: String,
Expand Down Expand Up @@ -161,7 +164,9 @@ impl Sort for FunctionSort {
}

fn is_eq_container_sort(&self) -> bool {
self.inputs.iter().any(|s| s.is_eq_sort())
self.inputs
.iter()
.any(|s| s.is_eq_sort() || s.is_eq_container_sort())
}

fn serialized_name(&self, container_values: &ContainerValues, value: Value) -> String {
Expand Down Expand Up @@ -195,6 +200,9 @@ impl Sort for FunctionSort {
name: "unstable-app".into(),
function: self.clone(),
});

register_vec_primitives_for_function(eg, self.clone());
register_multiset_primitives_for_function(eg, self.clone());
Comment thread
saulshanabrook marked this conversation as resolved.
}

fn value_type(&self) -> Option<TypeId> {
Expand Down
2 changes: 2 additions & 0 deletions src/sort/i64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ impl BaseSort for I64Sort {

add_literal_prim!(eg, "log2" = |a: i64| -> i64 { a.ilog2() as i64 });

add_literal_prim!(eg, "abs" = |a: i64| -?> i64 { a.checked_abs() });

add_literal_prim!(eg, "<" = |a: i64, b: i64| -?> () { (a < b).then_some(()) });
add_literal_prim!(eg, ">" = |a: i64, b: i64| -?> () { (a > b).then_some(()) });
add_literal_prim!(eg, "<=" = |a: i64, b: i64| -?> () { (a <= b).then_some(()) });
Expand Down
25 changes: 6 additions & 19 deletions src/sort/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,6 @@ impl Presort for MapSort {
.get_sort_by_name(v)
.ok_or(TypeError::UndefinedSort(v.clone(), v_span.clone()))?;

// TODO: specialize the error message
if k.is_eq_container_sort() {
return Err(TypeError::DisallowedSort(
name,
"Maps nested with other EqSort containers are not allowed".into(),
k_span.clone(),
));
}
if v.is_container_sort() {
return Err(TypeError::DisallowedSort(
name,
"Maps nested with other containers are not allowed".into(),
v_span.clone(),
));
}

let out = Self {
name,
key: k.clone(),
Expand All @@ -131,7 +115,10 @@ impl ContainerSort for MapSort {
}

fn is_eq_container_sort(&self) -> bool {
self.key.is_eq_sort() || self.value.is_eq_sort()
self.key.is_eq_sort()
|| self.value.is_eq_sort()
|| self.key.is_eq_container_sort()
|| self.value.is_eq_container_sort()
}

fn inner_values(
Expand All @@ -153,8 +140,8 @@ impl ContainerSort for MapSort {
let arc = self.clone().to_arcsort();

add_primitive!(eg, "map-empty" = {self.clone(): MapSort} || -> @MapContainer (arc) { MapContainer {
do_rebuild_keys: self.ctx.key.is_eq_sort(),
do_rebuild_vals: self.ctx.value.is_eq_sort(),
do_rebuild_keys: self.ctx.key.is_eq_sort() || self.ctx.key.is_eq_container_sort(),
do_rebuild_vals: self.ctx.value.is_eq_sort() || self.ctx.value.is_eq_container_sort(),
data: BTreeMap::new()
} });

Expand Down
2 changes: 1 addition & 1 deletion src/sort/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub trait Sort: Any + Send + Sync + Debug {
false
}

// return true if it is a container sort that contains ids.
// return true if it is a container sort that contains ids or other container sorts that contain ids.
// only eq_sort and eq_container_sort need to be canonicalized.
fn is_eq_container_sort(&self) -> bool {
false
Expand Down
Loading
Loading