Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group theory crash #519

Open
wisnesky opened this issue Feb 11, 2025 · 10 comments
Open

Group theory crash #519

wisnesky opened this issue Feb 11, 2025 · 10 comments

Comments

@wisnesky
Copy link

Hi all, I've been experimenting with encoding equational theories in the sense of universal algebra into Egglog. For example, group theory. I understand that I could enter a complete set of re-write rules as discovered by Knuth-Bendix completion but I wanted to see what would happen if I just use the usual 3 equation encoding:

(datatype G
 (id)
 (inv G)
 (plus G G)
)

(rewrite (plus (plus a b) c) (plus a (plus b c)))
(rewrite (plus a (plus b c)) (plus (plus a b) c))

(rewrite (plus a (id)) a)
(rewrite a (plus a (id))) //crash

(rewrite (plus (inv a) a) (id))
(rewrite (id) (plus (inv a) a)) //error

I understand why the erroneous rule is flagged - its right hand side refers to the variable a that is not bound on the left, and the crash is on a kind of rule that is usually disallowed (variable -> non-variable). Here is the message:

[INFO ] Welcome to Egglog REPL! (build: 0.4.0_2025-02-11_)
...
(rewrite a (plus a (id)))
thread 'main' panicked at src/actions.rs:80:69:
called `Option::unwrap()` on a `None` value

I'm wondering - can Egglog be used to semi-decide ground equality of arbitrary equational theories, such as group theory? This paper: https://arxiv.org/pdf/2501.02413 makes it seem like the answer is 'yes' and so I'm trying to figure out how to do, and wondering if the above approach is correct or if there are other approaches.

@yihozhang
Copy link
Collaborator

Right, rule like a -> (plus a (id)) is supported in egg, but not directly in egglog. As egglog translates rules to Datalog/chase-like rules, all variables need to be bound. A standard workaround is to use a universe relation:

(datatype G
 (id)
 (inv G)
 (plus G G)
)

(relation universe (G))
(rule ((= e (id))) ((universe e)))
(rule ((= e (inv a))) ((universe e)))
(rule ((= e (plus a b))) ((universe e)))

(birewrite (plus (plus a b) c) (plus a (plus b c)))

(birewrite (plus a (id)) a :when ((universe a)))

(birewrite (plus (inv a) a) (id) :when ((universe a)))
;; which gets translate to two (slightly inefficient) rules
;; (rule ((= e (plus (inv a) a)) (universe a)) ;; we don't need (universe a) here
;;       ((union a (id))))
;; (rule ((= e (id)) (universe a)) 
;;       ((union a (plus (inv a) a))))
      

@wisnesky
Copy link
Author

wisnesky commented Feb 11, 2025 via email

@yihozhang
Copy link
Collaborator

In this case, (id) has not been populated in the "database", and checking (= (id) (id)) implicitly checks the existence of (id), so it failed. It would work if we manually insert (id) into the database. I also made a slightly more involved example here.

(datatype G
 (id)
 (inv G)
 (plus G G)
)

(relation universe (G))
(rule ((= e (id))) ((universe e)))
(rule ((= e (inv a))) ((universe e)))
(rule ((= e (plus a b))) ((universe e)))

(birewrite (plus (plus a b) c) (plus a (plus b c)))

(birewrite (plus a (id)) a :when ((universe a)))
(birewrite (plus (id) a) a :when ((universe a)))

(birewrite (plus (inv a) a) (id) :when ((universe a)))
(birewrite (plus a (inv a)) (id) :when ((universe a)))

;; ab=1 --> b=a^-1
(rule ((= (id) (plus a b)))
      ((union b (inv a))
       (union a (inv b))))


;; need to populate (id) in the e-graph first
(id)
(check (= (id) (id)))

(constructor a () G)
(constructor b () G)

(let iab (inv (plus (a) (b))))
(let ibia (plus (inv (b)) (inv (a))))

(run 5)

(check (= iab ibia))

@wisnesky
Copy link
Author

wisnesky commented Feb 11, 2025 via email

@yihozhang
Copy link
Collaborator

Yes! The issue I had in my previous program is that it didn't put a and b into the universe relation. We don't actually need the extra rule

(datatype G
 (id)
 (inv G)
 (plus G G)
)

(relation universe (G))
(rule ((= e (id))) ((universe e)))
(rule ((= e (inv a))) ((universe e)))
(rule ((= e (plus a b))) ((universe e)))

(birewrite (plus (plus a b) c) (plus a (plus b c)))

(birewrite (plus a (id)) a :when ((universe a)))
(birewrite (plus (id) a) a :when ((universe a)))

(birewrite (plus (inv a) a) (id) :when ((universe a)))
(birewrite (plus a (inv a)) (id) :when ((universe a)))

(constructor a () G)
(constructor b () G)
(universe (a))
(universe (b))

(push)
(union (id) (plus (a) (b)))
(run 5)
(check (= (a) (inv (b))))
(pop)

(push)
(let iab (inv (plus (a) (b))))
(let ibia (plus (inv (b)) (inv (a))))
(run 5)
(check (= iab ibia))
(pop)

@wisnesky
Copy link
Author

wisnesky commented Feb 11, 2025 via email

@yihozhang
Copy link
Collaborator

yihozhang commented Feb 13, 2025

how does this work with multiple sorts? For example, if I wanted to use a multi-sorted structure such as a category instead of a group, where the constructors depend on two sorts, Ob and Hom, how would the syntax change?

Is this something you have in mind?

(sort Ob)
(sort (Hom a b) for ((a b : Ob)))

(function id () (Hom a b) for ((a b : Ob)))

Assuming I understand your question correctly, I think this is hard in current egglog, since egglog does not have real parametric/dependent types. Real parametric/dependent types introduce problems since each function is supposed to be backed by a database table, and it's not clear when to instantiate a parametric function (like id in the above case) with concrete types.

I'm guessing Egglog can semi-decide entailment of cartesian theories (skolemized horn theories)

Does it suffice to show EqSat subsumes Skolem chase (which we show in the semantics paper)?

  1. can this solution to the ground word problem be lifted to the full word problem?

I think egglog can prove forall c, c+a = c+b by skomizing c to an uninterpreted constant. For entailment, if you have forall c, c+a = c+b as an axiom and check if a+d() = b+d() holds (for Skolem constant d()), would that just work?

@wisnesky
Copy link
Author

wisnesky commented Feb 13, 2025 via email

@yihozhang
Copy link
Collaborator

something like this for the action of a group on a set

Yeah egglog supports multiple sorts. There are also many examples in the web demo.

(datatype*
 (G 
  (id) 
  (inv G)
  (plus G G))
 (A
  (action G A)))

in general, there is no way to turn an arbitrary semi-decision procedure for ground equality in universal algebra into a semi-decision procedure for non-ground equality

I never thought of it! This sounds interesting. Yes EqSat can semi-decide the ground word problem but I kinda just take the full word problem for granted. Let me know if you make any new discoveries about the connection between EqSat and the full word problem.

@wisnesky
Copy link
Author

wisnesky commented Feb 18, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants