Zulip Chat Archive

Stream: Berkeley Lean Seminar

Topic: Cycle Types


Thomas Browning (Mar 31 2021 at 22:21):

@Aaron Anderson Here are a few questions about cycle types:
1) Do you want to include 1's in the cycle type or not?
2) Should the cycle type be a partition, a multiset, a sorted list, or something else?

Aaron Anderson (Mar 31 2021 at 22:23):

There should certainly be a partition version of it, and I think there are advantages to including 1s.

Aaron Anderson (Mar 31 2021 at 22:24):

(If we include 1s, it should be very easy to make it a partition).

Thomas Browning (Mar 31 2021 at 22:24):

I agree that there advantages to including 1's. One disadvantage of including 1's is that it makes it painful to state things like "is_swap corresponds to this cycle type" or "an element of order p has a cycle type of this form"

Thomas Browning (Mar 31 2021 at 22:25):

Would it make sense to have two versions? A partition including 1's, and something (maybe a multiset or sorted list?) not including 1's.

Aaron Anderson (Mar 31 2021 at 22:26):

I'd probably say a multiset not including 1s and then a partition including 1s makes sense.

Aaron Anderson (Mar 31 2021 at 22:26):

If you derive it from same_cycle, you get 1s, and if you derive it from cycle_factors, you get no 1s.

Aaron Anderson (Mar 31 2021 at 22:27):

The advantage I see to including 1s is that it might make it easier to produce the bijection between cycles that I think you need for conjugacy.

Aaron Anderson (Mar 31 2021 at 22:29):

However, @Yakov Pechersky's work in #6959 may obviate the need to consider the 1s at all in the conjugacy argument.

Thomas Browning (Mar 31 2021 at 22:30):

I hadn't though about going from same_cycle (although I can't quite see how to do it nicely). If you go from cycle_factors, is there a nice way to avoid the linear_order assumption?

Aaron Anderson (Mar 31 2021 at 22:30):

On one of my recent PRs I threw in a trunc version...

Aaron Anderson (Mar 31 2021 at 22:31):

Yeah, trunc_cycle_factors in #6951

Aaron Anderson (Mar 31 2021 at 22:32):

We should be able to use that to computably define a cycle_type multiset.

Thomas Browning (Mar 31 2021 at 22:33):

Ok, I'll take a stab at this today, and I'll let you know when I've got something.

Aaron Anderson (Mar 31 2021 at 22:34):

As far as the partition, I might even suggest saving that for when we have conjugacy (and conjugacy classes, from #6896) and defining an equiv between conj_classes and partitions.

Aaron Anderson (Mar 31 2021 at 22:36):

As far as proving that the same cycle type implies conjugacy, I feel like we can maybe manage to prove it for cycles, and inductively for products of disjoint permutations.

Thomas Browning (Apr 01 2021 at 20:19):

@Aaron Anderson I've made a start at constructing cycles_type from trunc_cycle_factors, from which it shouldn't be too hard to make the partition. It look doable, but let me know if you see an easier to prove that the cycle_type doesn't depend on the choice of
cycle_factors.

Aaron Anderson (Apr 01 2021 at 20:59):

Where are you working on this?

Aaron Anderson (Apr 01 2021 at 21:00):

I think we want the lemma anyway that any two lists that satisfy the requirements of cycle factors are related by list.perm.

Aaron Anderson (Apr 01 2021 at 21:01):

That should be enough to appease the trunc, and it is a nicer place to put the sorry, but Idk how to prove it yet

Thomas Browning (Apr 01 2021 at 21:09):

ah, sorry, I forgot the link: https://github.com/leanprover-community/mathlib/compare/cycle_type

Thomas Browning (Apr 01 2021 at 21:09):

Good point that we should prove the permutation fact

Aaron Anderson (Apr 01 2021 at 21:44):

Actually, not that sure it does help, because we know the lists each satisfy list.erase_dup, so we can turn them into finsets and use finset.ext. I think we need to show that a member of one is a member of the other anyway.

Thomas Browning (Apr 01 2021 at 22:25):

@Aaron Anderson Would it make sense to prove something like this:

lemma main_theorem
  (l : list (perm α))
  (h1 :  σ : perm α, σ  l  σ.is_cycle)
  (h2 : l.pairwise disjoint)
  (c : perm α) (a : α) (hc : c a  a) :
  c  l  l.prod.cycle_of a = c :=

Aaron Anderson (Apr 01 2021 at 23:34):

Yes, then you can just hit it with list.perm_ext

Thomas Browning (Apr 01 2021 at 23:34):

I just pushed this approach to the branch. There's just one sorry left, but it's a bit of a doozy.

Thomas Browning (Apr 01 2021 at 23:35):

lemma thm2
  (σ τ : perm α)
  (h : disjoint σ τ)
  (c : perm α)
  (a : α)
  (hc : c a  a) :
  (σ * τ).cycle_of a = c  (σ.cycle_of a = c  τ.cycle_of a = c) :=
begin
  sorry
end

Thomas Browning (Apr 02 2021 at 07:21):

@Aaron Anderson The branch now is now sorry-free
https://github.com/leanprover-community/mathlib/compare/cycle_type

Thomas Browning (Apr 02 2021 at 07:43):

#6999

Aaron Anderson (Apr 03 2021 at 20:30):

Check out branch#cycle_conj

Aaron Anderson (Apr 03 2021 at 20:31):

I have a proof (although some things need to be cleaned up) that two cycles of the same size are conjugate

Aaron Anderson (Apr 03 2021 at 21:17):

#7024

Thomas Browning (Apr 03 2021 at 22:02):

@Aaron Anderson Great! I'm wondering whether we can get the full conjugate/partition theorem from the induction lemma?

Aaron Anderson (Apr 03 2021 at 22:05):

If you look at my proof, it basically glues two equivs together

Thomas Browning (Apr 03 2021 at 22:07):

Actually, so I'm curious. Do you think that this result will be useful in proving the full theorem? I'm starting to get worried that a cycle induction strategy won't work.

Aaron Anderson (Apr 03 2021 at 22:07):

For two disjoint perms, you could glue together equivs between their supports with one between the rest of the elements

Aaron Anderson (Apr 03 2021 at 22:07):

I think it will work.

Thomas Browning (Apr 03 2021 at 22:08):

Would that require passing permutations back and forth between subtypes? I'm worried that it might be a bit painful.

Aaron Anderson (Apr 03 2021 at 22:10):

Not more painful than the cycle proof, and I’m not sure I see a better option

Thomas Browning (Apr 03 2021 at 22:16):

Is it conceivable that you could prove a lemma along these lines?

Let a,b,c,d be permutations. Assume a and b are disjoint, c and d are disjoint, a is conjugate to c, b is conjugate to d. Then a*b is conjugate to c*d.

Aaron Anderson (Apr 03 2021 at 22:16):

Yes, that’s what I had in mind.

Thomas Browning (Apr 03 2021 at 22:16):

If so, then you could make a plain induction work, without the need for any more subtype mess (outside of the proof of the lemma)

Aaron Anderson (Apr 03 2021 at 22:17):

I think the alternative is creating some other data structure that represents cycle notation

Aaron Anderson (Apr 04 2021 at 21:15):

I have that lemma proven at branch#disjoint_conj.

Aaron Anderson (Apr 04 2021 at 21:16):

Again, messy, and I should really think more about how I'm going to organize all of these random permutation facts and long proofs, but the statement is there in case you want to sorry it and work on proving the cycle_type induction.

Yakov Pechersky (Apr 05 2021 at 13:07):

Kevin just let me know about this stream! I've been doing some parallel/complementary work. I've been trying to make it possible to specify explicit perm cycles using lists. Here's a smattering of what I have:

lemma perm.commutes_of_disjoint (e₁ e₂ : equiv.perm α)
  (h : _root_.disjoint (function.fixed_points e₁) (function.fixed_points e₂)) :
  commute e₁ e₂ :=
begin
  ext t,
  by_cases ht₁ : function.is_fixed_pt e₁ t;
  by_cases ht₂ : function.is_fixed_pt e₂ t,
  { simp [ht₁.eq, ht₂.eq] },
  { have : function.is_fixed_pt e₁ (e₂ t),
      { rw [function.mem_fixed_points, set.not_mem_compl_iff],
        refine set.mem_disjoint_imp _ h.symm,
        rw [set.mem_compl_iff, function.mem_fixed_points],
        contrapose! ht₂,
        rw function.is_fixed_pt at ht₂ ,
        apply e₂.injective,
        exact ht₂ },
    simp [ht₁.eq, this.eq] },
  { -- how does one use wlog to skip this?
    have : function.is_fixed_pt e₂ (e₁ t),
      { rw [function.mem_fixed_points, set.not_mem_compl_iff],
        refine set.mem_disjoint_imp _ h,
        rw [set.mem_compl_iff, function.mem_fixed_points],
        contrapose! ht₁,
        rw function.is_fixed_pt at ht₁ ,
        apply e₁.injective,
        exact ht₁ },
    simp [ht₂.eq, this.eq] },
  { exfalso,
    exact h (set.mem_inter ht₁ ht₂) }
end

def is_rotated (l l' : list α) : Prop :=  n, l.rotate n = l'

infixr ` ~r `:1000 := is_rotated

def cycle (α : Type*) : Type* := quotient (@is_rotated.setoid α)

Yakov Pechersky (Apr 05 2021 at 13:08):

With the goal of proving things like:

lemma form_perm_rotation_invariant (n : ) (l : list α) (h : nodup l) :
  form_perm (l.rotate n) = form_perm l := sorry

lemma is_cycle_form_perm (l : list α) (x y : α) (h : nodup (x :: y :: l)) :
  is_cycle (form_perm (x :: y :: l)) := sorry

Yakov Pechersky (Apr 05 2021 at 13:08):

(not including a lot of API)

Yakov Pechersky (Apr 05 2021 at 13:12):

Which, looking at your code, is similar to cycle_type

Yakov Pechersky (Apr 05 2021 at 13:30):

If you'd like any contribution or if you have any suggestions on refactoring, let me know!

Eric Wieser (Apr 05 2021 at 14:16):

docs#set.not_mem_compl_iff and docs#set.mem_disjoint_imp seem not to exist

Yakov Pechersky (Apr 05 2021 at 14:26):

Yeah, I just wanted to share a snippet of what I had.

lemma set.mem_disjoint_imp {α : Type*} {s t : set α} {x : α} (h : x  s) (hd : disjoint s t) :
  x  t :=
λ ht, hd (set.mem_inter h ht)

lemma set.not_mem_compl_iff {α : Type*} (s : set α) (x : α) : x  s  x  s := set.not_not_mem

Aaron Anderson (Apr 05 2021 at 14:56):

Hrm, I think that means we need to do a lot more coordination work, @Yakov Pechersky

Aaron Anderson (Apr 05 2021 at 14:57):

I'm not sure I see the benefit of this version of perm.commutes_of_disjoint over the existing proof of perm.disjoint.mul_comm

Aaron Anderson (Apr 05 2021 at 14:58):

but if you can represent cycles as lists, then that probably means you can give a much more intuitive proof of the conjugacy results

Yakov Pechersky (Apr 05 2021 at 15:00):

I haven't merged any of your branches -- just discovered them!

Yakov Pechersky (Apr 05 2021 at 15:00):

Is there a particular PR or branch I should rebase on?

Aaron Anderson (Apr 05 2021 at 15:00):

I'm not sure, equiv.perm.disjoint.mul_commis in master, just in the group_theory.perm.sign file, where it maybe shouldn't be

Aaron Anderson (Apr 05 2021 at 15:01):

Most of my random-helpful-lemmas are in branch#card_support_perm

Aaron Anderson (Apr 05 2021 at 15:02):

which is #6951

Aaron Anderson (Apr 05 2021 at 15:03):

but the work on branch#cycle_conj (#7024) which I've improved at branch#disjoint_conj involves some subtype shenanigans and long composition chains of equivs

Aaron Anderson (Apr 05 2021 at 15:03):

and the goal is just to prove the result that two permutations with the same cycle type are conjugate

Aaron Anderson (Apr 05 2021 at 15:04):

which is a 1-line proof on paper

Aaron Anderson (Apr 05 2021 at 15:04):

and it might be possible to get closer to that 1-line proof, and perhaps skip the induction, if you have both permutations represented as products of disjoint cycles which are represented as lists

Yakov Pechersky (Apr 05 2021 at 15:06):

Yeah, and a perm cycle should be representable as

def form_perm : equiv.perm α :=
(zip_with equiv.swap l (l.rotate 1)).tail.prod

Yakov Pechersky (Apr 05 2021 at 15:06):

Where it behave as expected if nodup l

Yakov Pechersky (Apr 05 2021 at 15:07):

(Or just define it with erase_dup in there)

Yakov Pechersky (Apr 05 2021 at 15:07):

Then disjointedness has to do with a statement about some sublists being disjoint or not

Aaron Anderson (Apr 05 2021 at 15:08):

I guess my question is

Aaron Anderson (Apr 05 2021 at 15:10):

If I give you two lists of disjoint cycles, with the cycles represented as lists, and the lists of the lengths of the cycles are the same, how hard might it be to define the equiv mapping from the ith element of the jth cycle of one list to the ith element of the jth cycle of the other list?

Yakov Pechersky (Apr 05 2021 at 15:11):

Do you know that each of the cycle elements are paired in length?

Aaron Anderson (Apr 05 2021 at 15:12):

Yes, but I did a bad job of describing that condition.

Yakov Pechersky (Apr 05 2021 at 15:12):

Then it's just a stacked zip_with

Aaron Anderson (Apr 05 2021 at 15:14):

I'm not sure I follow. list.zip_with seems to be a tool for applying a binary function pointwise to two lists to get a third list.

Aaron Anderson (Apr 05 2021 at 15:15):

I'm trying to find a permutation f such that when I apply list.map f to every cycle element in the first list, I get the second list

Aaron Anderson (Apr 05 2021 at 15:16):

Because list.map will correspond to conjugation for a given cycle, as in lemma conjugation_of_cycle at https://isabelle.in.tum.de/website-Isabelle2018/dist/library/HOL/HOL-Algebra/Cycles.html

Yakov Pechersky (Apr 05 2021 at 15:20):

My first question is when you say "list of cycles" you mean { l : list (equiv.perm α) // ∀ p ∈ l, is_cycle p }?

Aaron Anderson (Apr 05 2021 at 15:21):

I mean an element of that, yes, or else a list of lists, such that each element represents a disjoint cycle (so I suppose, a list such that if you concatenated all the elements it'd be nodup)

Yakov Pechersky (Apr 05 2021 at 15:22):

Right. So I think trying to map element to element will be wonky because of the rotational invariance

Yakov Pechersky (Apr 05 2021 at 15:22):

So, if you have to map element to element, then you have to escape the rotational invariance, probably via choosing the lexicographically smallest representation of that cycle

Aaron Anderson (Apr 05 2021 at 15:23):

I think we can get around that. I don't need this to be computable, although having a computable version under extra assumptions would potentially be useful.

Yakov Pechersky (Apr 05 2021 at 15:25):

Ah. My goal has precisely been computability here, which is why I've been building "bottom-up" from lists

Aaron Anderson (Apr 05 2021 at 15:26):

Yeah, I can tell... that's why I tried to phrase it in terms of assuming we already have two lists of lists, rather than two lists of cycles.

Aaron Anderson (Apr 05 2021 at 15:26):

Assuming we've already got past that choice hurdle.

Aaron Anderson (Apr 05 2021 at 15:26):

There's still going to have to be choice involved, in order to map the fixed points of one permutation to the other.

Aaron Anderson (Apr 05 2021 at 15:29):

One conclusion I have is that I should probably recall (or reduce the scope of) #7024

Yakov Pechersky (Apr 05 2021 at 15:33):

I'm not too familiar with HOL syntax. Is this describing that conjugating a [perm represented by disjoint cycles] by a perm is equal to [perm represented by disjoint cycles, [each trans that perm]]?

Aaron Anderson (Apr 05 2021 at 15:37):

I believe it’s more like [perm represented by disjoint cycles, [each list.mapped by that perm]

Aaron Anderson (Apr 05 2021 at 15:39):

Proving that should probably be easy enough, but proving sufficient conditions for there to exist a perm that does that particular conjugation is harder

Yakov Pechersky (Apr 05 2021 at 15:42):

Right, each of the disjoint cycles is conjugated by that perm, if I understand correctly

Yakov Pechersky (Apr 05 2021 at 15:42):

So can't you prove that it's the case for one, so it's the care for all?

Yakov Pechersky (Apr 05 2021 at 15:42):

(which is your "easy to prove" statement)

Aaron Anderson (Apr 05 2021 at 17:47):

Actually, I have an idea for how to do the harder statement. To construct such a permutation, we first concatenate both lists of lists, and then pad them both with all the fixed points (using list.filter or something) so that the domain of our permutations is listed out twice. Then, using fintype.equiv_fin.of_forall_mem_list, we can construct a permutation that sends the ith entry of one list to the ith entry of the other.

Yakov Pechersky (Apr 06 2021 at 00:55):

Why should perm.support be defined solely for fintype?

Yakov Pechersky (Apr 06 2021 at 01:03):

Because re-reading the code, I see that my commute lemma above works for non-fintype too.

Thomas Browning (Apr 06 2021 at 04:20):

@Yakov Pechersky In general, the support of a permutation won't be a finset. But I suppose you could try to refactor support to be a set.

Yakov Pechersky (Apr 06 2021 at 04:22):

Yes, agreed that it can often be nonfinite. I have already started on the refactor

Aaron Anderson (Apr 13 2021 at 00:36):

@Thomas Browning, I have just one sorry at branch#disjoint_conj required to prove that the same cycle type implies conjugacy.

Aaron Anderson (Apr 13 2021 at 00:37):

We just need to show that if the cycle type of a permutation is m1 + m2, then it can be expressed as a product of disjoint permutations with cycle types m1 and m2.

Aaron Anderson (Apr 13 2021 at 00:37):

Given as you wrote up cycle_type, do you have any insight into what kind of (possibly induction) we want to do?

Thomas Browning (Apr 13 2021 at 00:51):

Can you induct on sigma, after reverting m1 and m2?

Aaron Anderson (Apr 13 2021 at 15:45):

I think I’m finding that cycle_induction_on should allow you to assume that one of your two disjoint permutations is a cycle. I keep trying to use trunc_cycle_factors to get that...

Thomas Browning (Apr 13 2021 at 16:36):

Ah, so would changing the induction lemma to this be better:

@[elab_as_eliminator] lemma cycle_induction_on [fintype β] (P : perm β  Prop) (σ : perm β)
  (base_one : P 1) (base_cycles :  σ : perm β, σ.is_cycle  P σ)
  (induction_disjoint :  σ τ : perm β, σ.is_cycle  disjoint σ τ  P σ  P τ  P (σ * τ)) :
  P σ :=
begin
  suffices :
     l : list (perm β), ( τ : perm β, τ  l  τ.is_cycle)  l.pairwise disjoint  P l.prod,
  { classical,
    let x := σ.trunc_cycle_factors.out,
    exact (congr_arg P x.2.1).mp (this x.1 x.2.2.1 x.2.2.2) },
  intro l,
  induction l with σ l ih,
  { exact λ _ _, base_one },
  { intros h1 h2,
    rw list.prod_cons,
    refine induction_disjoint σ l.prod (h1 σ (l.mem_cons_self σ))
      (disjoint_prod_list_of_disjoint (list.pairwise_cons.mp h2).1)
      (base_cycles σ (h1 σ (l.mem_cons_self σ)))
      (ih (λ τ , h1 τ (list.mem_cons_of_mem σ )) (list.pairwise_of_pairwise_cons h2)) },
end

Aaron Anderson (Apr 13 2021 at 18:28):

Yeah, I think so.

Yakov Pechersky (Apr 13 2021 at 22:35):

I've made a lot of headway on constructable cycles via lists, like proving

lemma is_cycle_form_perm (x y : α) (xs : list α) (h : nodup (x :: y :: xs)) :
  is_cycle (form_perm (x :: y :: xs)) :=

https://github.com/leanprover-community/mathlib/commit/e7ffca5fffc981a097e0fdf1285977aae78216d9#diff-9c65c703978eccccaa9dcbcc614d775ffe4a39aac3347edb1f88c5c12b403cd4R784

Yakov Pechersky (Apr 13 2021 at 22:36):

As well as

lemma form_perm_reverse (l : list α) (h : nodup l) :
  form_perm l.reverse = (form_perm l)⁻¹ := sorry

lemma form_perm_rotate (l : list α) (h : nodup l) (n : ) :
  form_perm (l.rotate n) = form_perm l := sorry

lemma support_form_perm_of_nodup (l : list α) (h : nodup l) (h' :  (x : α), l  [x]) :
  support (form_perm l) = l.to_finset := sorry

Last updated: Dec 20 2023 at 11:08 UTC