-
Notifications
You must be signed in to change notification settings - Fork 45
feat: prove that regular languages are closed under concatenation #239
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
base: main
Are you sure you want to change the base?
Conversation
chenson2018
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to leave review of LTS to Fabrizio, but I've left a few comments.
chenson2018
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My comments have been addressed, but still leaving LTS to be reviewed.
|
There's a class So I guess this would make some of the constructions noncomputable -- by contrast, Is there an example from mathlib we can refer to for this discussion maybe? It might make sense to have both |
|
To clarify, you are wondering if these are valuable to both have around? You can write: instance (lt : LTS.Total lts) : LTS.LeftTotal lts where
left_total s μ := ⟨lt.next s μ, lt.total s μ⟩
noncomputable def LTS.leftTotal_total [inst : LTS.LeftTotal lts] : LTS.Total lts where
next s μ := Classical.choose (inst.left_total s μ)
total s μ := Classical.choose_spec (inst.left_total s μ)So if you don't care about the computability aspect, it seems they can be consolidated. |
|
I completely missed "LTS.LeftTotal". Sorry! (By the way, shouldn't it be "RightTotal"?). Anyway, I chose the name "total" by following the standard notion of a relation or function being "total" or "partial": https://en.wikipedia.org/wiki/Total_relation. Actually I started with using an existential quantifier as in |
|
@ctchou Heh, funny thing: I had originally called it total too, but in mathlib they follow the 'left total' terminology. (Which makes sense, because you can also be concerned about right totality in general.) @chenson2018 I expect them both to be useful, exactly because of what @ctchou wrote. I'm just wondering what we should call them, because having Just to give an example without caring too much about elegant names, the current An observation: |
|
I find mathlib's use of "left" and "right" regarding relations is really unfortunate, because in the "constructive" versions of those notions the witness is for the opposite side. Here's my proposal:
How do you think about the above? |
|
I like it, modulo the fact that I'd keep totality a class instead of turning it into a Prop, since that's our current practice for similar properties. Or do you have a place where having it as a class is particularly inconvenient? Full reasoning on terminology, etc., below -- some nuances might be important now or later. In the context of relations, they made the most reasonable/immediate choice: it's pretty standard terminology for relations, otherwise there's no established way to name all interesting classes. When one can commit to being interested only in left-totality, saying 'total' is perfectly fine because that's the default meaning, but that's not good in general. However, in this discussion, we can consider also the glossary of transition systems. In this context, people are typically only interested in:
So we can either:
Assuming (1) is ok (my preference), I'd suggest that we rename -- In LTS/Basic.lean
noncomputable def LTS.chooseFLTS [inst : LTS.Total lts] : FLTS State Label [...]
theorem LTS.chooseFLTS_tr [LTS.Total lts] (s : State) (μ : Label) : lts.Tr s μ (lts.chooseFLTS s μ) := [...]
-- In FLTS/FLTSToLTS.lean.
instance (flts : FLTS State Label) : LTS.Total (flts.toLTS) where [...] |
|
Let's stick with the names |
In this patch we prove that regular languages are closed under concatenation, by leveraging the results already proved about the infinite executions of the automata concatenation construction in
NA/Concat.lean. In order to do so, we introduce the notion of a "total LTS", which means that the LTS has a next state for any given starting state and label, and a "LTS.totalize" construction that converts any LTS into a total LTS by adding a sink state and transitions from all states to the sink state. Then the notion of "total" and the "totalize" construction are generalized to NA. By "totalizing" NA's, we can extend any finite execution of a NA into an infinite execution and thus re-use the results already proved for infinite executions.The same technique can be applied to
NA/Loop.leanto prove that regular languages are closed under the Kleene star; see PR #241.