Zulip Chat Archive
Stream: new members
Topic: Using the Mathlib,
Jonathan Whitehead (May 16 2023 at 20:33):
So I want to turn a Finset into a list. I found a function in finset called to_list that seems to do what I want, but I can't seem to access it. For example, if X : Finset a, I tried X.val.to_list
, X.1.to_list
, and X.to_list
. In each occasion Lean complains that the field to_list is not in the environment. That is Finset.to_list and Multiset.to_list is not in the environment.
Why can't I use to_list? And is this a proper way to turn a Finset to a list?
Kyle Miller (May 16 2023 at 20:34):
Are you looking at the mathlib3 docs instead of the mathlib4 docs? docs4#Finset.toList is the mathlib4 one and docs#finset.to_list is the mathlib3 one.
Jonathan Whitehead (May 16 2023 at 20:36):
I'm actually using the Github https://github.com/leanprover-community/mathlib/blob/master/src/data/finset/basic.lean , whcih I thought was Lean 4.
Kyle Miller (May 16 2023 at 20:37):
That's mathlib3 (generally, no number right now means version 3, and for version 4 you want to see a 4)
Kyle Miller (May 16 2023 at 20:37):
Notice also all the names are lower-case. Mathlib 4 naming convention is upper case types.
Kyle Miller (May 16 2023 at 20:37):
https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Finset/Sort.html might be useful too for turning a finset into a list, since this can actually be computed, if you're wanting to evaluate things
Jonathan Whitehead (May 16 2023 at 20:37):
Ah, I see. It's toList. Thanks!
Kyle Miller (May 16 2023 at 20:38):
I noticed that that also has an (unsafe) Repr
instance for Finset
, which might be useful for debugging.
Jonathan Whitehead (May 16 2023 at 20:39):
Ah, great. I'll play around with it and see how it works.
Eric Wieser (May 16 2023 at 20:39):
And is this a proper way to turn a Finset to a list?
For what purpose? Sometimes docs4#Finset.sort is a better choice
Jonathan Whitehead (May 16 2023 at 20:42):
Eric Wieser said:
And is this a proper way to turn a Finset to a list?
For what purpose? Sometimes docs4#Finset.sort is a better choice
I'm just trying to print the Finset. If I try X.toList.map toString
I get the message "invalid field notation, type is not of the form (C ...) where C is a constant..."
Jonathan Whitehead (May 16 2023 at 20:44):
#check Finset.sort.map toString
instance graph_to_string : ToString Graph := ⟨
fun G => "{Vertices = " ++
String.intercalate ", " (G.vertices.toList.map toString ) ++
" : ¬ Edges = " ++
String.intercalate ", " (G.edges.map toString) ++
"}"
⟩
Lean actually underlines the name of the instance and says that IR check failed at 'graph_to_string' unknown declaration at 'Finset.toList'.
Eric Wieser (May 16 2023 at 20:47):
I think you need to add unsafe
before the word instance
Jonathan Whitehead (May 16 2023 at 20:48):
Well that certainly makes me feel safe about what I'm doing :sweat_smile: What exactly does unsafe
do?
Eric Wieser (May 16 2023 at 20:48):
Though this sounds a bit like an #xy problem; can you just add deriving Repr
to your Graph
Jonathan Whitehead (May 16 2023 at 20:48):
But unsafe still doesn't seem to fix it.
Jonathan Whitehead (May 16 2023 at 20:49):
structure Graph :=
(vertices : Finset Vertex)
(edges : List Edge)
(property : ∀ e ∈ edges, Prod.fst e.edge ∈ vertices ∧ Prod.snd e.edge ∈ vertices)
deriving Repr
You mean like this?
Eric Wieser (May 16 2023 at 20:57):
Oh, I guess it gets unhappy about property
?
Eric Wieser (May 16 2023 at 20:57):
Or does that just work?
Jonathan Whitehead (May 16 2023 at 20:59):
It doesn't work. Here is what I have:
structure Vertex :=
(name : String)
deriving DecidableEq
instance vertex_to_string : ToString Vertex :=
⟨fun v => v.name⟩
structure Edge :=
(name : String)
(edge : Vertex × Vertex)
deriving DecidableEq
instance edge_to_string : ToString Edge :=
⟨fun e => "(" ++ e.edge.fst.name ++ ", " ++ e.edge.snd.name ++ ")" ⟩
structure Graph :=
(vertices : Finset Vertex)
(edges : List Edge)
(property : ∀ e ∈ edges, Prod.fst e.edge ∈ vertices ∧ Prod.snd e.edge ∈ vertices)
deriving Repr
And at deriving Repr, Lean complains because there's not a Repr instance of vertex_list_to_string and edge_list_to_string. I created the instances for vertices and edges, but not for a multiset of vertices and a list of string.
Eric Wieser (May 16 2023 at 21:00):
You need to put deriving Repr
on all of the structures
Jonathan Whitehead (May 16 2023 at 21:00):
It used to work until I added property
in Graph. I needed to add this property because I wrote a program and couldn't prove it to be correct because I couldn't prove that each endpoint of the edges were in the vertices. Hence, I had to define Graph as a structure that carried with it a proof that the endpoints of each edge were vertices of G.
Eric Wieser (May 16 2023 at 21:01):
(I'm not at lean right now, so can't actually give you working code!)
Jonathan Whitehead (May 16 2023 at 21:01):
When I put deriving Repr on Vertex, it tells me that it "expected 'instance'".
structure Vertex :=
(name : String)
deriving DecidableEq
deriving Repr
Eric Wieser (May 16 2023 at 21:02):
I think the syntax is deriving Foo, Bar
not deriving Foo, deriving Bar
Jonathan Whitehead (May 16 2023 at 21:02):
It feels like I need to have more "set up" before I can use deriving Repr
Eric Wieser (May 16 2023 at 21:03):
Does fixing the syntax still not work?
Jonathan Whitehead (May 16 2023 at 21:04):
It doesn't appear to be working. Is Bar supposed to be the name of the instance? Like deriving Repr, vertex_to_string
doesn't seem to work. It still says expected instance.
Jonathan Whitehead (May 16 2023 at 21:04):
I also tried deriving Repr, instance vertex_to_string
and the same result followed.
Eric Wieser (May 16 2023 at 21:04):
Yeah that's nonsense
Eric Wieser (May 16 2023 at 21:04):
I mean deriving DecidableEq, Repr
Jonathan Whitehead (May 16 2023 at 21:05):
Ohhh, okay that it. That worked.
Damiano Testa (May 16 2023 at 21:05):
Can I maybe chime in and go back to your definition of Vertex
: do you really want it to be a string?
Damiano Testa (May 16 2023 at 21:06):
I think that if you want to be able to "print" your vertices, you should put a Repr
instance on the type on whose terms you build the graph.
Jonathan Whitehead (May 16 2023 at 21:07):
Damiano Testa said:
Can I maybe chime in and go back to your definition of
Vertex
: do you really want it to be a string?
I'm new and picked a mathematical object to define and work with. At the current moment, without the wisdowm and foresight of an experienced user, I chose to define a vertex as simply an object with a label. I'm sure that more sophisticated approaches would define things a bit differently but I was just trying to define things the way that I learned them in an undergraduate course.
Moreover, I also wanted to define algorithms on these graphs and prove that the algorithms are correct. Hence, I kind of need some labeling system on the vertices and edges. Hence the reason why I have them as structs with a field for a string.
Damiano Testa (May 16 2023 at 21:07):
Looking at your code, maybe you could define an Edge
to have a source
and a target
, rather than an ordered pair.
Damiano Testa (May 16 2023 at 21:08):
So, let's see if we can get you started with something that will be easier.
Jonathan Whitehead (May 16 2023 at 21:09):
Okay, but remember I'm a new user and things can quickly become esoteric. :sweat_smile:
Jonathan Whitehead (May 16 2023 at 21:12):
I've been worried about finding the easiest implementation to work with because in some instances an easier implementation might not be the canonical interpretation of the object in a math class. And I just want the implementation to be readable to regular math students with little to no computer science back ground. There seems to be a delicate balance between the two that I haven't quite found.
Damiano Testa (May 16 2023 at 21:17):
structure Edge (α : Type) :=
(source : α)
(target : α)
def myEdge : Edge Nat :=
{ source := 1
target := 2 }
instance [ToString α] : ToString (Edge α) where
toString := by
intro e
exact toString e.source ++ "," ++ toString e.target
#eval myEdge
Damiano Testa (May 16 2023 at 21:18):
You get an Edge (a type)
by providing a pair of elements of type
.
Damiano Testa (May 16 2023 at 21:19):
For instance, the def
construct an Edge on the natural numbers.
Damiano Testa (May 16 2023 at 21:20):
Next, you define a ToString
instance on an Edge
, by assuming that there already is a ToString
instance on the type whose elements you are considering. You get to define how you want to represent the edge joining a
to b
. I chose to represent it by using the representation for a
then a comma, then the representation for b
.
Eric Wieser (May 16 2023 at 21:21):
(note the point in my Repr
comments was "you can get a default representation of your object without doing any work". If you want to customize how it looks, rolling your own instead is fine)
Damiano Testa (May 16 2023 at 21:21):
In the exact
line, you get to choose what you want. If you prefer a "list-style" printing, you could say instead
exact "[" ++ toString e.source ++ "," ++ toString e.target ++ "]"
Damiano Testa (May 16 2023 at 21:24):
This way, you "outsource" the printing to the target type. You are likely going to define graphs on Nat, on String, on some enumerated inductive type. In each case, you can leverage a "printing" instance on the type of the vertices to get your printed version.
Damiano Testa (May 16 2023 at 21:25):
Here is another example:
structure Edge (α : Type) :=
(source : α)
(target : α)
def myEdge : Edge Nat :=
{ source := 1
target := 2 }
def myStringEdge : Edge String :=
{ source := "sou"
target := "tar" }
instance [ToString α] : ToString (Edge α) where
toString := by
intro e
exact "[" ++ toString e.source ++ "," ++ toString e.target ++ "]"
#eval myEdge -- [1,2]
#eval myStringEdge -- [sou,tar]
Damiano Testa (May 16 2023 at 21:26):
Lean already knows how to print Nat
and String
, I simply told it how to print an edge, given that notion.
Jonathan Whitehead (May 16 2023 at 21:28):
In my definition I pushed the parameter into the structure and forced it to be a string, because I didn't think that I would ever really care about the type of the vertex, I just wanted to let them all be strings. I reasoned that if they're all strings, I wouldn't have to worry about the printing procedure as much since printing strings has been taken care of in Lean.
What is the point of letting Edge be an "edge of ___"? Is it just going to make things easier to work with?
Eric Wieser (May 16 2023 at 21:29):
I think this is the line of reasoning that gives you things like sh
where the only type of variables is strings :)
Eric Wieser (May 16 2023 at 21:31):
What if you want a graph where the nodes are natural numbers and there are edges whenever one node divides another?
Damiano Testa (May 16 2023 at 21:31):
For instance, if you wanted to define the "divisibility graph", having access to Nat
as a vertex set is useful...
Jonathan Whitehead (May 16 2023 at 21:32):
Another thing about the implementation that you posted is that I get error messages if I try to add deriving DecidableEq
and while I've been working on this stuff, I've found that I certainly want there to be a decidable equality between these edges and manually defining the decidable equality was a bit of work.
Damiano Testa (May 16 2023 at 21:32):
Or if you wanted to work with a finite graph and use dec_trivial, it might be helpful to work with enumerated types. For instance:
inductive vertSet | A | B | C
instance : ToString vertSet where
toString | vertSet.A => "A" | vertSet.B => "B" | vertSet.C => "C"
def myIndEdge : Edge vertSet :=
{ source := vertSet.A
target := vertSet.B }
#eval myIndEdge
Damiano Testa (May 16 2023 at 21:33):
I think that you can derive DecidableEq if you assume it for the base type.
Jonathan Whitehead (May 16 2023 at 21:33):
Great examples of why I would want the parameter.
Damiano Testa (May 16 2023 at 21:34):
Note that the implementation of the instance is a completely arbitrary choice: I do not have to use the string "A" for the vertex called vertSet.A
, of course.
Damiano Testa (May 16 2023 at 21:34):
(I mean the ToString
instance on vertSet
, though for sanity it is helpful to use the same name, of course!)
Eric Wieser (May 16 2023 at 21:35):
Does deriving ToString
on vertSet
do that for you?
Jonathan Whitehead (May 16 2023 at 21:36):
Sorry it's taking a minute to respond. I'm reading through everything.
Damiano Testa (May 16 2023 at 21:37):
inductive vertSet | A | B | C
deriving ToString
-- default handlers have not been implemented yet, class: 'ToString' types: [vertSet]
Damiano Testa (May 16 2023 at 21:37):
@Eric Wieser , so no!
Yakov Pechersky (May 16 2023 at 21:40):
I think Kyle has implemented a handler that covers this
Jonathan Whitehead (May 16 2023 at 21:42):
Aren't there going to be issues with leaving the vertices undefined? For example, when I do
structure Graph :=
(vertices : Finset Vertex)
(edges : List Edge)
(property : proof that the source and target are in Finset Vertex)
I feel like there's going to be problems at Finset Vertex
. So I would need to change the way that I define the Graph too.
Damiano Testa (May 16 2023 at 21:44):
I probably would define a structure Graph (of a type)
and simply assume that every term of the type is a vertex. If you assume that the type is finite, you have a finset of vertices.
Jonathan Whitehead (May 16 2023 at 21:45):
Ah, okay I'll work on implementing these ideas.
Damiano Testa (May 16 2023 at 21:46):
So, something like this:
structure Graph (α : Type) :=
(edges : List (Edge α))
Jonathan Whitehead (May 16 2023 at 21:47):
But wouldn't that prevent me from being able to talk about G - v, where v is a vertex?
Damiano Testa (May 16 2023 at 21:48):
Then, every term of α
is a vertex. Some of these vertices appear as endpoints of edges.
Kyle Miller (May 16 2023 at 21:48):
Yakov Pechersky said:
I think Kyle has implemented a handler that covers this
There's deriving ToExpr
and I think you can maybe use toString (toExpr x)
?
Damiano Testa (May 16 2023 at 21:48):
Here, there might be a difference between a subgraph and a graph that happens to be a subgraph.
Damiano Testa (May 16 2023 at 21:49):
So, "the mathlib way" would probably be to define a "Type of Subgraphs", whose terms are not Graphs, but that have coercions to a Graph.
Yaël Dillies (May 16 2023 at 21:49):
Jonathan Whitehead said:
But wouldn't that prevent me from being able to talk about G - v, where v is a vertex?
No, it simply means G - v won't be of the same type as G (it will have type Graph {a // a \ne v}
)
Yaël Dillies (May 16 2023 at 21:50):
This is all quite fiddly, and it's hard to find a working design that's not mathlib's.
Damiano Testa (May 16 2023 at 21:50):
This means that you will get more or less for free that the Type of Subgraphs is a lattice, and you can get the machinery of lattices to help you with inductions, unions, intersections... without having to redefine these notions from scratch.
Damiano Testa (May 16 2023 at 21:52):
@Kyle Miller toExpr
is an unknown identifier
: should I import
/open
something?
Kyle Miller (May 16 2023 at 21:53):
You need to import https://leanprover-community.github.io/mathlib4_docs/Mathlib/Tactic/DeriveToExpr.html for derive ToExpr
and then I think it's ToExpr.toExpr
Damiano Testa (May 16 2023 at 21:53):
@Jonathan Whitehead the constructions of Subgraphs that I am thinking of is entirely analogous to the one of several, similar ones in mathlib, for instance submodule
.
Kyle Miller (May 16 2023 at 21:57):
Damiano Testa said:
So, "the mathlib way" would probably be to define a "Type of Subgraphs", whose terms are not Graphs, but that have coercions to a Graph.
In practice the algebra hierarchy design doesn't really work for graphs. Most algebraic objects "are" a type, but a graph isn't a type. The coercion design depends on the fact that there is a coercion from a subobject to a type, and that type can be given the additional structure through typeclass inference.
Jonathan Whitehead (May 16 2023 at 21:58):
Damiano Testa said:
Jonathan Whitehead the constructions of Subgraphs that I am thinking of is entirely analogous to the one of several, similar ones in mathlib, for instance
submodule
.
Okay, I'm going to work on these ideas and reread all of your comments. I'm just worried that the framework will be pigeon-hole me into writing an implementation that isn't very "mathematician" friendly. Personally, I don't mind because I'm learning a lot of new ideas, but if things get too strange it will deter some of my friends.
Kyle Miller (May 16 2023 at 22:00):
@Damiano Testa Also, you might want a coercion from subgraphs to graphs, but, at least last I experimented, you can't make a Coe
instance that goes to Graph ?_
and have it solve for ?_
. It had something to do with universe variables not getting unified, if I remember correctly.
Damiano Testa (May 16 2023 at 22:00):
For the record, this works:
import Mathlib.Tactic.DeriveToExpr
open Lean
inductive vertSet
| A | B | C
deriving ToExpr
instance : ToString vertSet where
toString := fun x => toString (toExpr x)
#eval vertSet.A -- vertSet.A
Damiano Testa (May 16 2023 at 22:01):
Sure, I have thought about how to define graphs in mathlib only after this thread started...
Damiano Testa (May 16 2023 at 22:04):
@Jonathan Whitehead keep in mind that "finite" and "concrete" structures have a tendency of being hard to work with. It is often the case that the more abstract something is, the easier it will be to formalize.
Jonathan Whitehead (May 16 2023 at 22:05):
Damiano Testa said:
Jonathan Whitehead keep in mind that "finite" and "concrete" structures have a tendency of being hard to work with. It is often the case that the more abstract something is, the easier it will be to formalize.
Ah, never thought about how concrete things tend to be more difficult. Good to know.
Jonathan Whitehead (May 16 2023 at 22:07):
I suppose another way to think about Graphs is to define the vertex to be a list of vertices with an adjacency relation on them... But that might be stranger and harder to work with. But it seems like it might be easier to do things like vertex deletion and to talk about isolated vertices?
Damiano Testa (May 16 2023 at 22:09):
I have not really though about this, but maybe, following what you say, it might make sense to have the edges be a symmetric relation on a type.
Damiano Testa (May 16 2023 at 22:09):
(or not symmetric, if you want to do directed graphs)
Yakov Pechersky (May 16 2023 at 22:10):
Definitions are hard.
Jonathan Whitehead (May 16 2023 at 22:10):
Damiano Testa said:
I have not really though about this, but maybe, following what you say, it might make sense to have the edges be a symmetric relation on a type.
Yeah, I was also thinking about this when we defined edges to have sources and targets. I realize that these are just identifiers and can be changed but they seem to imply directedness.
Damiano Testa (May 16 2023 at 22:11):
So, I do not know if this will work, but it might be fun to experiment with:
structure Graph (α) :=
(adj : α → α → Prop)
(symm : ∀ {a b}, adj a b → adj b a)
Yakov Pechersky (May 16 2023 at 22:11):
And with graphs, there are a ton of things to define. Maybe pick a theorem first and see what definitions lend itself to it?
Kyle Miller (May 16 2023 at 22:11):
Do you know about docs4#SimpleGraph @Damiano Testa ?
Damiano Testa (May 16 2023 at 22:12):
@Kyle Miller I just learned about it! And, while I was typing the definition, I was wondering if I wanted to include irreflexivity or reflexivity as a condition!
Kyle Miller (May 16 2023 at 22:13):
Ok, so you might also just be discovering docs4#SimpleGraph.Subgraph ?
Damiano Testa (May 16 2023 at 22:13):
It seems like I got the capitalization wrong...
Damiano Testa (May 16 2023 at 22:14):
Kyle Miller said:
Ok, so you might also just be discovering docs4#SimpleGraph.Subgraph ?
This seems exactly where I was headed...
Kyle Miller (May 16 2023 at 22:14):
For Jonathan's purposes, a problem with using a relation on a type is that it has no computational content. I've gotten the sense that he wants to do some computations (with #eval
for example), and it'd be better to avoid Prop
and instead use some actual data for that.
Kyle Miller (May 16 2023 at 22:15):
You can do computations with SimpleGraph
, but it takes defining Decidable instances, which are sort of a lot to master when you're just learning Lean.
Jonathan Whitehead (May 16 2023 at 22:15):
Yakov Pechersky said:
And with graphs, there are a ton of things to define. Maybe pick a theorem first and see what definitions lend itself to it?
My goal is to write programs for some algorithms and show that they're correct. I took a course where "proofs" of algorithms were given (e.g. augmenting path, blosom algorithms, etc.), but the proofs were very hand wavey. So I wanted to see if I could formalize the algorithms and prove they are correct.
Kyle Miller (May 16 2023 at 22:16):
I would suggest ignoring how mathlib does things for that and write a Graph
type that will suit your own purposes for some algorithm
Kyle Miller (May 16 2023 at 22:16):
As you implement a few algorithms, you can revisit whether you made a good choice in your design, and iterate.
Kyle Miller (May 16 2023 at 22:17):
It's too hard to come up with the right definition up front. You need to know where it's all going to know where you were supposed to start
Damiano Testa (May 16 2023 at 22:18):
And maybe even start with something moderately simple, like showing that a connected graph on 3 vertices must have at least 2 edges.
Jonathan Whitehead (May 16 2023 at 22:18):
Kyle Miller said:
I would suggest ignoring how mathlib does things for that and write a
Graph
type that will suit your own purposes for some algorithm
Yes! This is what I've been doing. I wrote some simple programs and proved them, but then I wrote a certain program that I couldn't prove without modifying my definition of a graph to include a proof that the end points of edges are in the vertex set. Hence, I went back to modify my definition of a Graph and then things started breaking :joy:
Kyle Miller (May 16 2023 at 22:19):
That might sound simple @Damiano Testa (most simple things in combinatorics do), but connectivity takes some work to develop to be usable
Kyle Miller (May 16 2023 at 22:20):
It should be pretty straightforward with the mathlib SimpleGraph library though, and that would be a welcome lemma if anyone wants to prove it
Damiano Testa (May 16 2023 at 22:20):
I think that the first project that I worked on was to show something about connected graphs and it was hard...
Kyle Miller (May 16 2023 at 22:21):
docs4#SimpleGraph.Connected is the connectivity predicate
Kyle Miller (May 16 2023 at 22:22):
By the way, speaking of a computation, in the mathlib3 archive there's the Konigsberg bridges problem
Damiano Testa (May 16 2023 at 22:22):
I certainly did not define Preconnected and went straight to Connected!
Kyle Miller (May 16 2023 at 22:59):
@Damiano Testa Here's the well-known "Damiano's lemma":
import Mathlib.Combinatorics.SimpleGraph.Connectivity
open SimpleGraph
variable {V : Type _} (G : SimpleGraph V) [Fintype V] [Fintype G.edgeSet]
lemma damiano (hc : G.Connected) (hv : 2 < Fintype.card V) : 1 < G.edgeFinset.card := by
rw [Fintype.two_lt_card_iff] at hv
simp only [Finset.one_lt_card_iff, Set.mem_toFinset, ne_eq, exists_and_left]
obtain ⟨a, b, c, hab, hac, hbc⟩ := hv
refine (hc a b).elim_path (fun ⟨pab, hp⟩ => ?_)
cases pab
· exact absurd rfl hab
rename_i v hav pvb
cases pvb
· refine ⟨_, G.mem_edgeSet.mpr hav, ?_⟩
refine (hc c a).elim (fun pca => ?_)
cases pca
· exact absurd rfl hac
· rename_i hcv _
refine ⟨_, G.mem_edgeSet.mpr hcv, ?_⟩
simp [not_or, hac, hbc]
· rename_i w hvw _
refine ⟨_, G.mem_edgeSet.mpr hav, _, G.mem_edgeSet.mpr hvw, ?_⟩
simp only [Walk.cons_isPath_iff, Walk.support_cons, List.find?, List.mem_cons, not_or] at hp
simp only [Quotient.eq, Sym2.rel_iff, hp.2.1, false_and, and_true, false_or]
rintro rfl
simp at hp
Edit: Refined a very little
import Mathlib.Combinatorics.SimpleGraph.Connectivity
open SimpleGraph
lemma SimpleGraph.Adj.mem_edgeSet {G : SimpleGraph V} (h : G.Adj v w) : ⟦(v, w)⟧ ∈ G.edgeSet := h
variable (G : SimpleGraph V) [Fintype V] [Fintype G.edgeSet]
lemma damiano (hc : G.Connected) (hv : 2 < Fintype.card V) : 1 < G.edgeFinset.card := by
rw [Fintype.two_lt_card_iff] at hv
simp only [Finset.one_lt_card_iff, Set.mem_toFinset, ne_eq, exists_and_left]
obtain ⟨a, b, c, hab, hac, hbc⟩ := hv
refine (hc a b).elim_path (fun ⟨pab, hp⟩ => ?_)
cases pab with
| nil => exact absurd rfl hab
| cons hav pvb =>
cases pvb with
| nil =>
refine ⟨_, hav.mem_edgeSet, ?_⟩
refine (hc c a).elim (fun pca => ?_)
cases pca with
| nil => exact absurd rfl hac
| cons hcv _ =>
refine ⟨_, hcv.mem_edgeSet, ?_⟩
simp [not_or, hac, hbc]
| cons hvw _ =>
refine ⟨_, hav.mem_edgeSet, _, hvw.mem_edgeSet, ?_⟩
simp only [Walk.cons_isPath_iff, Walk.support_cons, List.find?, List.mem_cons, not_or] at hp
simp only [Quotient.eq, Sym2.rel_iff, hp.2.1, false_and, and_true, false_or]
rintro rfl
simp at hp
Kyle Miller (May 16 2023 at 23:01):
The proof is a rough draft, and there are likely some hidden lemmas just waiting to be extracted
Damiano Testa (May 17 2023 at 01:01):
Kyle, I simply extracted one lemma from your proof.
import Mathlib.Combinatorics.SimpleGraph.Connectivity
namespace SimpleGraph
variable {G : SimpleGraph V} [Fintype V] [Fintype G.edgeSet] (hc : G.Connected)
lemma Connected.mem_edgeSet_of_ne (hva : v ≠ a) : ∃ e, e ∈ edgeSet G ∧ v ∈ e := by
refine (hc v a).elim_path (fun ⟨pab, hp⟩ => ?_)
match pab with
| Walk.nil => exact absurd rfl hva
| Walk.cons _ _ => exact ⟨⟦(v, _)⟧, by simpa⟩
lemma Connected.one_lt_of_two_lt (hv : 2 < Fintype.card V) : 1 < G.edgeFinset.card := by
simp only [Finset.one_lt_card_iff, Set.mem_toFinset, ne_eq, exists_and_left]
obtain ⟨a, b, c, hab, hac, hbc⟩ := Fintype.two_lt_card_iff.mp hv
obtain ⟨e, he, ae⟩ := hc.mem_edgeSet_of_ne hab
use e, he
rcases eq_or_ne e ⟦(a, b)⟧ with rfl | pv
. obtain ⟨f, hf, af⟩ := hc.mem_edgeSet_of_ne hbc.symm
use f, hf
rintro rfl
simp [hac.symm, hbc.symm] at af
. obtain ⟨f, hf, be⟩ := hc.mem_edgeSet_of_ne hab.symm
exact ⟨f, hf, fun ef ↦ pv ((Sym2.mem_and_mem_iff hab).mp ⟨ae, ef ▸ be⟩)⟩
end SimpleGraph
Jonathan Whitehead (May 17 2023 at 07:01):
I know we discussed defining things differently, but it really bothers me that I can't get this simple print function to work. So I kept working on it and I feel like there's an issue happening with the printing module for Finsets and Multisets. Below is the code that I wrote and the error message I receive is:
IR check failed at 'finsetToList.loop._rarg', error: unknown declaration 'Finset.toList'
The reason why I feel like something is going on with porting some code from Lean 3 to 4 is because sometimes the tool tips mention to_list and sometimes they mention toList. I can #check toList, but the error says toList is unknown.
structure Vertex :=
(name : String)
deriving DecidableEq, Repr
instance finset_to_string : ToString (Finset Vertex) := ⟨
fun f => String.intercalate "," $ f.toList.map (fun v => v.name)
⟩
Mario Carneiro (May 17 2023 at 07:04):
#mwe ?
Jonathan Whitehead (May 17 2023 at 07:04):
I also tried creating my own function to send a Finset to List but Lean kept complaining that it couldn't determine if the program terminated:
partial def finsetToList {α : Type} [DecidableEq α] (s : Finset α) : List α :=
let rec loop (l : List α) (s : Finset α) : List α :=
match s.to_list with
| [] => l.reverse
| x :: xs => loop (x :: l) (s.erase x)
loop [] s
Jonathan Whitehead (May 17 2023 at 07:05):
import Mathlib.Data.List.Basic
import Mathlib.Data.Finset.Basic
structure Vertex :=
(name : String)
deriving DecidableEq, Repr
structure Edge :=
(name : String)
(edge : Vertex × Vertex)
deriving DecidableEq, Repr
instance finset_to_string : ToString (Finset Vertex) := ⟨
fun f => String.intercalate "," $ f.toList.map (fun v => v.name)
⟩
instance edge_list_to_string : ToString (List Edge) :=
⟨fun l => String.intercalate ", " $ l.map (fun edge => edge.name) ⟩
structure Graph :=
(vertices : Finset Vertex)
(edges : List Edge)
(property : ∀ e ∈ edges, Prod.fst e.edge ∈ vertices ∧ Prod.snd e.edge ∈ vertices)
deriving Repr
Damiano Testa (May 17 2023 at 07:06):
I think that the issue is that f.toList
is interpreted as Finset.toList
, since f
has Type Finset ...
. This is simply saying that there is no function to go from a there is one.Finset
to a List
Jonathan Whitehead (May 17 2023 at 07:06):
For the graph, deriving Repr
says that it fails to find an instance of Repr (Finset Vertex), so I'm trying to make one.
Jonathan Whitehead (May 17 2023 at 07:06):
(deleted)
Damiano Testa (May 17 2023 at 07:07):
I was missing an import, let me keep digging!
Jonathan Whitehead (May 17 2023 at 07:08):
Thanks, I'll keep trying too.
Mario Carneiro (May 17 2023 at 07:08):
the issue is that Finset.toList
exists but is noncomputable
. That's why the error is reported in a weird place, the compiler is complaining, not the typechecker
Jonathan Whitehead (May 17 2023 at 07:08):
Mario Carneiro said:
the issue is that
Finset.toList
exists but isnoncomputable
. That's why the error is reported in a weird place, the compiler is complaining, not the typechecker
Ah, yes, I remember seeing that it was noncomputable. Is there some work around?
Damiano Testa (May 17 2023 at 07:09):
Mario beat me to it! You can add noncomputable
before the instance
to get it to compile.
Jonathan Whitehead (May 17 2023 at 07:09):
Like I said, I even tried making my own toList function, but couldn't figure out how to convince lean that it terminated.
Jonathan Whitehead (May 17 2023 at 07:09):
Yes! You guys just fixed my problem in a couple minutes that I worked on for hours :rolling_on_the_floor_laughing:
Mario Carneiro (May 17 2023 at 07:10):
the power of a good #mwe :)
Jonathan Whitehead (May 17 2023 at 07:10):
Will I have to worry about it being noncomputable in any of my concrete examples?
Jonathan Whitehead (May 17 2023 at 07:10):
I guess I'm not really relying on printing stuff out, it's just for the user experience.
Mario Carneiro (May 17 2023 at 07:10):
probably, if you want to run the toString
instance
Mario Carneiro (May 17 2023 at 07:11):
for a ToString
instance it is generally useless if it is not computable
Jonathan Whitehead (May 17 2023 at 07:11):
Ah, but I guess declaring that it's noncomputable didn't fix the deriving Repr
in the Graph structure.
Jonathan Whitehead (May 17 2023 at 07:14):
Yeah, letting it be noncomputable makes lean top complaining, but makes it unusable.
Damiano Testa (May 17 2023 at 07:15):
Also, I think that Finset Vertex
does not mean what you think it does...
Mario Carneiro (May 17 2023 at 07:15):
here's a computable implementation:
instance finset_to_string : ToString (Finset Vertex) := ⟨
let trans : IsTrans String (· < ·) := sorry
let trans : IsAntisymm String (· < ·) := sorry
let trans : IsTotal String (· < ·) := sorry
fun f => String.intercalate "," $ f.val.map (fun v => v.name) |>.sort (· < ·)
⟩
Damiano Testa (May 17 2023 at 07:18):
Mario is being very conservative with the choice of names for his let
s...
Jonathan Whitehead (May 17 2023 at 07:19):
Mario Carneiro said:
here's a computable implementation:
instance finset_to_string : ToString (Finset Vertex) := ⟨ let trans : IsTrans String (· < ·) := sorry let trans : IsAntisymm String (· < ·) := sorry let trans : IsTotal String (· < ·) := sorry fun f => String.intercalate "," $ f.val.map (fun v => v.name) |>.sort (· < ·) ⟩
When I try to use it I get an error
invalid field 'sort', the environment does not contain 'Multiset.sort'
Multiset.map (fun v => ?m.3236 v) f.val
has type
Multiset
Damiano Testa (May 17 2023 at 07:20):
import Mathlib.Data.Multiset.Sort
Jonathan Whitehead (May 17 2023 at 07:21):
Ah yeah, thanks I'll work on looking through it. I'll also look into understanding the Finset a little better.
Damiano Testa (May 17 2023 at 07:36):
Here is an example, in case it is helpful:
def attempt : Finset Vertex where
val := ⟦[⟨"hello"⟩, ⟨"world"⟩, ⟨"!"⟩]⟧
nodup := by simp
#eval attempt -- !,hello,world
Damiano Testa (May 17 2023 at 07:57):
I do not think that the design is particularly ergonomic, but I found this funny and confusing!
def getWords (S : String) : Finset Vertex where
val := ⟦ S.splitOn.map fun x ↦ ⟨x⟩ ⟧
nodup := sorry
#eval (getWords "My words are the vertices of a graph")
#eval (getWords " ")
#eval (getWords " , , ")
Last updated: Dec 20 2023 at 11:08 UTC