Zulip Chat Archive
Stream: graph theory
Topic: Digraphs
Rida Hamadani (Sep 18 2024 at 12:38):
Now that we have digraphs in mathlib, what are the next steps to have things such as walks, paths, cycles, (in, out)-degrees, adjacency matrices, etc for digraphs? Do we plan to just redo these definitions from SimpleGraph
s, or should we relate them in some way to their adjacent definitions in SimpleGraph
?
Bhavik Mehta (Sep 18 2024 at 15:13):
My first guess would be to redo the definitions, and have lemmas relating them to the SimpleGraph versions where appropriate. For example, once we have the map sending a digraph to a simple graph which forgets orientations, construct the function from a walk in a digraph to a walk in the corresponding simple graph.
Vincent Beffara (Sep 18 2024 at 15:30):
It feels like a lot of duplication coming up ... Is the plan to refactor SimpleGraph
now to say that a SimpleGraph
is a Digraph
where Adj
is symmetric and has no self-loop? And then we could move to Digraph
everything that is not dependent on these particular properties of Adj
, typically the definition of Path
.
Rida Hamadani (Sep 18 2024 at 16:52):
Does this "orientation-forgetting" map from Digraph
s to SimpleGraph
s look okay?
import Mathlib
def toSimpleGraph {V : Type*} (G : Digraph V) : SimpleGraph V where
Adj v w := v ≠ w ∧ (G.Adj v w ∨ G.Adj w v)
symm := by
intro v w ⟨h₁, h₂⟩
apply And.intro h₁.symm
cases h₂
· exact Or.inr ‹_›
· exact Or.inl ‹_›
loopless := fun _ h ↦ h.1 rfl
Shreyas Srinivas (Sep 18 2024 at 16:58):
My impression is that a copy paste and modify job will suffice
Shreyas Srinivas (Sep 18 2024 at 16:58):
At least for some of the basic files
Bhavik Mehta (Sep 18 2024 at 17:01):
Vincent Beffara said:
It feels like a lot of duplication coming up ... Is the plan to refactor
SimpleGraph
now to say that aSimpleGraph
is aDigraph
whereAdj
is symmetric and has no self-loop? And then we could move toDigraph
everything that is not dependent on these particular properties ofAdj
, typically the definition ofPath
.
Yup, could do! That's definitely a sensible thing to try
Rida Hamadani (Sep 18 2024 at 17:08):
Thanks, I'll try porting some of the things from SimpleGraph
s to Digraphs
while taking these points into consideration.
Rida Hamadani (Sep 18 2024 at 17:08):
Another point:
Since we are having an orientation-forgetting map, how can we formalize the opposite: an "orientation" of a SimpleGraph
, which results in a Digraphs
. I'm asking because I've seen this used often in literature, for instance, tournaments are often defined as an "orientation of a complete simple graph".
Rida Hamadani (Sep 18 2024 at 17:09):
Is there a way to do this without having to "choose" the orientations
Bhavik Mehta (Sep 18 2024 at 17:28):
You can turn every edge into a pair of directed edges in opposite directions (and maybe this turns out to give a galois connection with the forgetful map). But otherwise you do need to specify the orientations in some way, for the notion to be well-defined up to isomorphisms on the vertex set
Vincent Beffara (Sep 18 2024 at 17:44):
Beware that there are two ways to forget orientation, you can have an unoriented edge if either orientation is present, or alternatively if both are present. I don’t know which one is more natural for applications. You did the first, but the second is more dual to Bhavik’s double orientation
Bhavik Mehta (Sep 18 2024 at 17:47):
We should have both!
Shreyas Srinivas (Sep 18 2024 at 17:54):
there are other notions of adding orientation. For example a bfs tree with edges oriented towards the starting node, Sinkless orientations etc
Shreyas Srinivas (Sep 18 2024 at 17:54):
it might be nice to a generic way of orienting each undirected edge
Rida Hamadani (Sep 18 2024 at 18:03):
Maybe we can have an Orientation.lean
file in the SimpleGraph
(or Digraph
?) folder that contains such orientations, and maybe it can contain the Digraph.toSimpleGraph
function with some basic lemmas too.
Rida Hamadani (Sep 19 2024 at 11:24):
According to https://en.wikipedia.org/wiki/Orientation_(graph_theory), an oriented graph is a Digraph
such that none of its pairs of vertices is linked by two mutually symmetric edges. There are many different types of orientations and it would be nice to formalize some of this! It would come in handy once we want to formalize tournaments.
Rida Hamadani (Sep 19 2024 at 11:54):
What do you think about defining it like this:
import Mathlib
variable {V : Type}
def Digraph.IsOriented (G : Digraph V) : Prop :=
∀ v w : V, ¬G.Adj v v ∧ ¬(G.Adj v w ∧ G.Adj w v)
Should oriented graphs contain self-loops or not?
I've found papers that assume they don't, and I think that is better for our purposes.
Vincent Beffara (Sep 19 2024 at 11:58):
Equivalently, its "strong" map into a SimpleGraph
is bot
Rida Hamadani (Sep 19 2024 at 12:00):
What is a "strong map"?
Mauricio Collares (Sep 19 2024 at 12:04):
Vincent Beffara said:
Beware that there are two ways to forget orientation, you can have an unoriented edge if either orientation is present, or alternatively if both are present. I don’t know which one is more natural for applications. You did the first, but the second is more dual to Bhavik’s double orientation
I think Vincent is referring to the "unoriented edge if both oriented edges are present" map
Rida Hamadani (Sep 19 2024 at 12:10):
If we define oriented graphs in that way then we will be allowing them to have self-loops
Daniel Weber (Sep 19 2024 at 12:55):
Rida Hamadani said:
Does this "orientation-forgetting" map from
Digraph
s toSimpleGraph
s look okay?import Mathlib def toSimpleGraph {V : Type*} (G : Digraph V) : SimpleGraph V where Adj v w := v ≠ w ∧ (G.Adj v w ∨ G.Adj w v) symm := by intro v w ⟨h₁, h₂⟩ apply And.intro h₁.symm cases h₂ · exact Or.inr ‹_› · exact Or.inl ‹_› loopless := fun _ h ↦ h.1 rfl
Perhaps it's better to use docs#SimpleGraph.fromRel ?
def toSimpleGraph {V : Type*} (G : Digraph V) : SimpleGraph V := .fromRel G.Adj
Rida Hamadani (Sep 19 2024 at 12:55):
That's a great idea, thank you!
Rida Hamadani (Sep 19 2024 at 23:03):
#16954 starts with some of the things discussed here, but doesn't port anything from SimpleGraph
s to Digraph
s yet
Rida Hamadani (Sep 20 2024 at 15:21):
It would be nice to have an IsLoopless
predicate.
Vincent Beffara (Sep 20 2024 at 17:16):
We have the classes docs#IsIrrefl for loopless, docs#IsAsymm for oriented, and so on ... would it make sense to use these instead of explicit quantifiers?
Rida Hamadani (Sep 20 2024 at 18:02):
Nice idea, but what do you think about using docs#AntiSymmetric and docs#Irreflexive instead? So we won't have to deal with adding h.asymm
every time we want to use the hypothesis h : G.IsOriented
. Also Irreflexive
is used already when defining the loopless property on SimpleGraph
s.
Rida Hamadani (Sep 20 2024 at 18:11):
Oh, Antisymmetric
is different from Asymmetric
, and apparently we don't have Asymmetric
in mathlib
Rida Hamadani (Sep 21 2024 at 00:02):
I've added Asymmetric
and rewrote the PR to use it instead, alongside Irreflexive
.
Mitchell Horner (Dec 08 2024 at 09:42):
I don't know if this is the place to ask, but is there an advantage to implementing digraphs, simple graphs, etc. as separate structures instead of say:
abbrev Graph (V : Type*) := Rel V V
namespace Graph
variable {V : Type*}
class UndirectedGraph (G : Graph V) where
undirected : Symmetric G
class LooplessGraph (G : Graph V) where
loopless : Irreflexive G
class SimpleGraph (G : Graph V) extends UndirectedGraph G, LooplessGraph G
-- and so on
class SemicompleteGraph (G : Graph V) extends LooplessGraph G where
semicomplete : ∀ v₁ v₂, G v₁ v₂ ∨ G v₂ v₁
class QuasiTransitiveGraph (G : Graph V) extends LooplessGraph G where
quasi_transitive : ∀ v₁ v₂ v₃, G v₁ v₂ ∧ G v₂ v₃ → G v₁ v₃ ∨ G v₃ v₁
instance (G : Graph V) [h : SemicompleteGraph G] : QuasiTransitiveGraph G where
quasi_transitive v₁ _ v₃ _ := h.semicomplete v₁ v₃
class OrientedGraph (G : Graph V) where
oriented : ∀ v₁ v₂, Xor' (G v₁ v₂) (G v₂ v₁)
-- DAG, tree, etc.
In this case digraphs, simple graphs, etc. are built up using classes and definitions/theorems pick the resolution they need so no duplication. It also future proofs implementation of new subclasses of graphs.
I'm relatively new to Lean, but this reminds me of how say Ring
is defined as a class extending SemiRing
, AddCommGroup
, AddGroupWithOne
. Is there some lurking reason as to why this isn't done?
Kyle Miller (Dec 09 2024 at 17:31):
@Mitchell Horner There's a bit of discussion about this today at , including a reference to a relevant PR. One other reason is that it's good to have actual types per class of object — for example the lattice structures on Digraph and SimpleGraph are interesting and useful.
Kyle Miller (Dec 09 2024 at 17:39):
For Ring
, etc., the key difference is that these typeclasses implementing synecdoche. We talk about the underlying type for a ring as if it's the ring itself. It's nice because a single type can "be" multiple things in the algebraic hierarchy.
The first complication are types like Subgroup
, but then there's a trick you can use. Given H : Subgroup G
, you can use H
as if it were a type, because Lean has its CoeSort system. Then we can say H
"is" a group by synecdoche through the coercion — that is to say, H
as a type has a Group
instance.
However, this all falls apart when you start working with homomorphisms. You want types of homomorphisms, and there are some complications to, for example, a ring homomorphism "being" an additive homomorphism. This is all the DFunlike business patching it over.
Graphs are similar to homomorphisms. There are complications, and as that PR in the link shows, it's possible to do similar things, but it's not as nice of a situation as Ring
et al.
Mitchell Horner (Dec 10 2024 at 08:04):
Kyle Miller said:
Mitchell Horner There's a bit of discussion about this today at , including a reference to a relevant PR. One other reason is that it's good to have actual types per class of object — for example the lattice structures on Digraph and SimpleGraph are interesting and useful.
Thanks for this explanation. That discussion and #4127 is exactly what I was looking for.
Last updated: May 02 2025 at 03:31 UTC