Definitions bundle OAIQ051M001 of the split of OpenAI, A Fully Polynomial Randomized Approximation Scheme for Perfect Matchings in General Graphs (result family 113)
DefinitionOAIQ051M001A definitions bundle of the split of OpenAI's proof of OAI.MatchingFPRAS.thm_main, carved from OpenAI's openai/math development (OpenAI, A Fully Polynomial Randomized Approximation Scheme for Perfect Matchings in General Graphs (result family 113), OpenAI Math Release, September 23, 2026, result family 113, github.com/openai/math at commit adc7f12, Apache License 2.0) and ported to Lean 4.33.1 and Mathlib 0df444a. The declarations and their proofs are OpenAI's.
Contents. It holds 982 declarations of OpenAI's Lean: 625 definitions, 19 inductive types or structures, 20 instances and 318 theorems. The definitions and types are OAI.MatchingFPRAS.ExecutableBottleneck.square, OAI.MatchingFPRAS.ExecutableDP.BInitial, OAI.MatchingFPRAS.ExecutableDP.Bag, OAI.MatchingFPRAS.ExecutableDP.Bags, OAI.MatchingFPRAS.ExecutableDP.CappedState, OAI.MatchingFPRAS.ExecutableDP.CountInput, OAI.MatchingFPRAS.ExecutableDP.EntryCtx, OAI.MatchingFPRAS.ExecutableDP.Parents, OAI.MatchingFPRAS.ExecutableDP.RawCtx, OAI.MatchingFPRAS.ExecutableDP.State, OAI.MatchingFPRAS.ExecutableDP.Table, OAI.MatchingFPRAS.ExecutableDP.UpdateInput, OAI.MatchingFPRAS.ExecutableDP.activeRep, OAI.MatchingFPRAS.ExecutableDP.bagRep, OAI.MatchingFPRAS.ExecutableDP.capBits, OAI.MatchingFPRAS.ExecutableDP.cappedCount, OAI.MatchingFPRAS.ExecutableDP.cappedEntry, OAI.MatchingFPRAS.ExecutableDP.cappedStep, OAI.MatchingFPRAS.ExecutableDP.cappedUpdate, OAI.MatchingFPRAS.ExecutableDP.context, OAI.MatchingFPRAS.ExecutableDP.entry, OAI.MatchingFPRAS.ExecutableDP.finish, OAI.MatchingFPRAS.ExecutableDP.initial, OAI.MatchingFPRAS.ExecutableDP.initialEntry, OAI.MatchingFPRAS.ExecutableDP.nLabels, OAI.MatchingFPRAS.ExecutableDP.nPlan, OAI.MatchingFPRAS.ExecutableDP.nVertices, OAI.MatchingFPRAS.ExecutableDP.orderedRep, OAI.MatchingFPRAS.ExecutableDP.parentRep, OAI.MatchingFPRAS.ExecutableDP.parentTag, OAI.MatchingFPRAS.ExecutableDP.privateFlag, OAI.MatchingFPRAS.ExecutableDP.privateNumber, OAI.MatchingFPRAS.ExecutableDP.rawEntry, OAI.MatchingFPRAS.ExecutableDP.rawTerm, OAI.MatchingFPRAS.ExecutableDP.read, OAI.MatchingFPRAS.ExecutableDP.runCapped, OAI.MatchingFPRAS.ExecutableDP.sharedFlag, OAI.MatchingFPRAS.ExecutableDP.sharedNumber, OAI.MatchingFPRAS.ExecutableDP.tableWeightBound, OAI.MatchingFPRAS.ExecutableDP.tabulate and 604 more.
Sources. They come from these modules of lean/OAI/Combinatorics/MatchingCount, in whole or in part: MatchingCount_Algorithm_AffineWeights, MatchingCount_Algorithm_OnlineHistorySize, MatchingCount_Algorithm_OnlineInitial, MatchingCount_Algorithm_OnlineLadderSchedule, MatchingCount_Algorithm_OnlineRequest, MatchingCount_Algorithm_OnlineScheduleNat, MatchingCount_Algorithm_OutputLengthBound, MatchingCount_Algorithm_RationalEstimator, MatchingCount_Algorithm_RationalScale, MatchingCount_Algorithm_RationalStart, MatchingCount_Algorithm_TreeGeneratedPrepared, MatchingCount_Algorithm_TreeNumericStatistics, MatchingCount_Algorithm_TreeNumericSummaries, MatchingCount_Algorithm_TreeObservables, MatchingCount_Algorithm_TreeStageStatisticsCorrect, MatchingCount_Algorithm_TreeStatistics, MatchingCount_Arithmetic_ArithmeticSize, MatchingCount_Arithmetic_OnlineFractionParam, MatchingCount_Arithmetic_TreeGCD, MatchingCount_Arithmetic_TreeNatDivision, MatchingCount_Arithmetic_TreeStateNormalize, MatchingCount_Complexity_GuardMachineBase, MatchingCount_Complexity_OnlineRequestCost, MatchingCount_Complexity_OnlineRunCost, MatchingCount_Complexity_StackCompilerCost, MatchingCount_Complexity_TreePolynomialGrid, MatchingCount_Graphs_AdaptiveStream, MatchingCount_Graphs_Admissible, MatchingCount_Graphs_ColoredEdge, MatchingCount_Graphs_CompleteGraph, MatchingCount_Graphs_Cumulative, MatchingCount_Graphs_Cycle, MatchingCount_Graphs_Density, MatchingCount_Graphs_Edge2, MatchingCount_Graphs_EdgeLow, MatchingCount_Graphs_EnlargementRun, MatchingCount_Graphs_Evolve, MatchingCount_Graphs_ExperimentSupport, MatchingCount_Graphs_HoleBlocks, MatchingCount_Graphs_IndexedCycle, MatchingCount_Graphs_LabelCycle, MatchingCount_Graphs_LabelOrder, MatchingCount_Graphs_OnlineGraphInvariant, MatchingCount_Graphs_PM, MatchingCount_Graphs_PathStrength, MatchingCount_Graphs_PushedFlow, MatchingCount_Graphs_RatWeight, MatchingCount_Graphs_Related, MatchingCount_Graphs_Related2, MatchingCount_Graphs_RemainingBags, MatchingCount_Graphs_RowPeak, MatchingCount_Graphs_SafeSwitch, MatchingCount_Graphs_Sets, MatchingCount_Graphs_SumLiftMate, MatchingCount_Graphs_ThresholdGraph, MatchingCount_Graphs_TreeBagCorrect, MatchingCount_Graphs_TreeBagTable, MatchingCount_Graphs_TreeBags, MatchingCount_Graphs_TreeCycleTable, MatchingCount_Graphs_TreeGeometry, MatchingCount_Graphs_TreeHierarchyReindex, MatchingCount_Graphs_TreeInitialMatching, MatchingCount_Graphs_TreeMatchingCheck, MatchingCount_Graphs_TreeRankPlan, MatchingCount_Graphs_TreeSwitchRaw, MatchingCount_Graphs_TreeSwitchValid, MatchingCount_Machines_OnlineCase, MatchingCount_Machines_OnlineFold, MatchingCount_Machines_OnlineFrame, MatchingCount_Machines_OnlineTraverse, MatchingCount_Machines_OnlineUniform, MatchingCount_Machines_PhysicalPost, MatchingCount_Machines_SupportedCompiler, MatchingCount_Machines_TreeBindings, MatchingCount_Machines_TreeBottleneck, MatchingCount_Machines_TreeCanonical, MatchingCount_Machines_TreeCappedAssembly, MatchingCount_Machines_TreeCertify, MatchingCount_Machines_TreeClippedCorrect, MatchingCount_Machines_TreeClippedRun, MatchingCount_Machines_TreeClosureReindex, MatchingCount_Machines_TreeColorRaw, MatchingCount_Machines_TreeEnumeration, MatchingCount_Machines_TreeFold, MatchingCount_Machines_TreeIndex, MatchingCount_Machines_TreeLabelCorrect, MatchingCount_Machines_TreeLabelTable, MatchingCount_Machines_TreeList, MatchingCount_Machines_TreeListMore, MatchingCount_Machines_TreeListOps, MatchingCount_Machines_TreeNaturalComb, MatchingCount_Machines_TreeNumberedSets, MatchingCount_Machines_TreePairProposal, MatchingCount_Machines_TreeParentTable, MatchingCount_Machines_TreeQuad, MatchingCount_Machines_TreeReach, MatchingCount_Machines_TreeRefreshCatalog, MatchingCount_Machines_TreeRefreshIndexed, MatchingCount_Machines_TreeRefreshNumbered, MatchingCount_Machines_TreeRepeat, MatchingCount_Machines_TreeSlotIndex, MatchingCount_Machines_TreeSlotWeight, MatchingCount_Machines_TreeStart, MatchingCount_Machines_TreeStateTable, MatchingCount_Machines_TreeSum, MatchingCount_Probability_LocalVariance, MatchingCount_Probability_Mean, MatchingCount_Probability_OnlineSampleLaw, MatchingCount_Probability_Tv, MatchingCount_Probability_Variance, MatchingCount_Sampling_AssignmentEquiv, MatchingCount_Sampling_Certify, MatchingCount_Sampling_ClippedEnvelope, MatchingCount_Sampling_Component, MatchingCount_Sampling_ComponentOrder, MatchingCount_Sampling_Components, MatchingCount_Sampling_Corner, MatchingCount_Sampling_DPEnvelope, MatchingCount_Sampling_DiscreteLadderSteps, MatchingCount_Sampling_EndpointPair, MatchingCount_Sampling_Endpoints, MatchingCount_Sampling_Endpoints2, MatchingCount_Sampling_IntervalPattern, MatchingCount_Sampling_LadderL, MatchingCount_Sampling_MetropolisChoice, MatchingCount_Sampling_OnlineSample, MatchingCount_Sampling_PM, MatchingCount_Sampling_PairStep, MatchingCount_Sampling_Plan, MatchingCount_Sampling_RankOrder, MatchingCount_Sampling_Relabel, MatchingCount_Sampling_RelationDestinations, MatchingCount_Sampling_Sewn, MatchingCount_Sampling_Span, MatchingCount_Sampling_Sym2Order, MatchingCount_Sampling_TableMarking, MatchingCount_Sampling_Through, MatchingCount_Sampling_TierClamp, MatchingCount_Sampling_TreeCategorical, MatchingCount_Sampling_TreeClippedDP, MatchingCount_Sampling_TreeDPCount, MatchingCount_Sampling_TreeDPCounts, MatchingCount_Sampling_TreeDPEntry, MatchingCount_Sampling_TreeDPProgram, MatchingCount_Sampling_TreeDPRepresentation, MatchingCount_Sampling_TreeFastDPEntry, MatchingCount_Sampling_TreeFastDescent, MatchingCount_Sampling_TreeFastSample, MatchingCount_Sampling_TreeFastUnit, MatchingCount_Sampling_TreeIndexedPair, MatchingCount_Sampling_TreeIndexedPairCorrect, MatchingCount_Sampling_TreeLadder, MatchingCount_Sampling_TreeLadderIndexed, MatchingCount_Sampling_TreeLadderPost, MatchingCount_Sampling_TreeLocalSampler, MatchingCount_Sampling_TreeMarking, MatchingCount_Sampling_TreeNumericLadder, MatchingCount_Sampling_TreeNumericMarking, MatchingCount_Sampling_TreePairTable, MatchingCount_Sampling_TreePreparedMarked, MatchingCount_Sampling_TreeScan, MatchingCount_Sampling_TreeScanChoice, MatchingCount_Sampling_TreeScanRun, MatchingCount_Sampling_TreeUnitAssemble, MatchingCount_Sampling_TreeUnitBranch, MatchingCount_Sampling_TreeUnitDraw, MatchingCount_Sampling_TreeUnitSampler, MatchingCount_Sampling_Underlying, MatchingCount_Tapes_BlockMap, MatchingCount_Tapes_Codec, MatchingCount_Tapes_FixedAlphabetCompiler, MatchingCount_Tapes_FixedEncoding, MatchingCount_Tapes_Input, MatchingCount_Tapes_OnlineStackCompiler, MatchingCount_Tapes_OnlineWord, MatchingCount_Tapes_Packed, MatchingCount_Tapes_PackedExecution, MatchingCount_Tapes_Parse, MatchingCount_Tapes_Physical, MatchingCount_Tapes_StackWords, MatchingCount_Tapes_TapeTools, MatchingCount_Tapes_TreeNumberedCodec, MatchingCount_Tapes_TreeSparseComponents, MatchingCount_Tapes_TreeSparseNeighbors, MatchingCount_Tapes_TreeSparseStage.
Imports. It imports the published bundle Def_MatchingFPRAS.
Imported by (directly, in this split): the bundles OAIQ051M002 and OAIQ051M003.
import Mathlib
import Definitions.Def_MatchingFPRAS
section
-- module Solutions.OAIQ051_MC.Compat
namespace OAI
/-! Compatibility with the newer Lean core OpenAI's code was written against: lemmas it uses by
names this environment (Lean 4.33.1, Mathlib 0df444a) does not have yet. Each is the
corresponding `if_pos` / `if_neg` / `dif_pos` / `dif_neg`. The `dite` forms are stated as
`dite p a b`, not with the `if hp : p then …` notation: its eta-expanded lambdas form is a higher-order pattern
that `rw` cannot find (DepthThree, PeriodicTiling 2026-10-25). -/
section OAICompat434
/-- Mathlib's newer `TensorProduct.inductionOn` (no `zero` case: it is the `tmul` case at
`0 ⊗ₜ 0`); ours has only `TensorProduct.induction_on`, which asks for one. Not named
`TensorProduct.inductionOn`: inside `namespace OAI` that would make `open TensorProduct` open
`OAI.TensorProduct` instead of Mathlib's. -/
@[elab_as_elim]
theorem tensorInductionOn {R M N : Type*} [CommSemiring R] [AddCommMonoid M] [AddCommMonoid N]
[Module R M] [Module R N] {motive : TensorProduct R M N → Prop} (z : TensorProduct R M N)
(tmul : ∀ x y, motive (TensorProduct.tmul R x y))
(add : ∀ x y, motive x → motive y → motive (x + y)) : motive z :=
TensorProduct.induction_on z (by simpa using tmul 0 0) tmul add
/-- Mathlib's newer case names for `FreeGroup.induction_on` (`one`, where ours says `C1`). -/
@[elab_as_elim]
theorem freeGroupInductionOn {α : Type*} {C : FreeGroup α → Prop} (z : FreeGroup α) (one : C 1)
(of : ∀ x, C (FreeGroup.of x)) (inv_of : ∀ x, C (FreeGroup.of x) → C (FreeGroup.of x)⁻¹)
(mul : ∀ x y, C x → C y → C (x * y)) : C z :=
FreeGroup.induction_on z one of inv_of mul
/-- The first projection of a probability measure on a product: found by instance search in d13f23b
(total `Measure.map`), here a measurable map. -/
instance isProbabilityMeasure_map_fst {α β : Type*} [MeasurableSpace α] [MeasurableSpace β]
{μ : MeasureTheory.Measure (α × β)} [MeasureTheory.IsProbabilityMeasure μ] :
MeasureTheory.IsProbabilityMeasure (μ.map Prod.fst) :=
MeasureTheory.Measure.isProbabilityMeasure_map measurable_fst.aemeasurable
instance isProbabilityMeasure_map_snd {α β : Type*} [MeasurableSpace α] [MeasurableSpace β]
{μ : MeasureTheory.Measure (α × β)} [MeasureTheory.IsProbabilityMeasure μ] :
MeasureTheory.IsProbabilityMeasure (μ.map Prod.snd) :=
MeasureTheory.Measure.isProbabilityMeasure_map measurable_snd.aemeasurable
instance isProbabilityMeasure_map_subtype_val {α : Type*} [MeasurableSpace α] {p : α → Prop}
{μ : MeasureTheory.Measure {a // p a}} [MeasureTheory.IsProbabilityMeasure μ] :
MeasureTheory.IsProbabilityMeasure (μ.map Subtype.val) :=
MeasureTheory.Measure.isProbabilityMeasure_map measurable_subtype_coe.aemeasurable
/-- Mathlib d13f23b's `YoungDiagram.card_transpose`. -/
@[simp]
theorem _root_.YoungDiagram.card_transpose (μ : YoungDiagram) : μ.transpose.card = μ.card := by
unfold YoungDiagram.card
apply Finset.card_bij (fun c _ => c.swap)
· intro c hc
have : c ∈ μ.transpose := hc
rw [YoungDiagram.mem_transpose] at this
exact this
· intro a _ b _ h
simpa using h
· intro b hb
refine ⟨b.swap, ?_, by simp⟩
show b.swap ∈ μ.transpose
rw [YoungDiagram.mem_transpose]
simpa using hb
/-- For a measurable equivalence `e`, `IsProbabilityMeasure (μ.map e)` is found by instance search
(Mathlib d13f23b finds it for every map `f`: there `Measure.map` of a non-measurable map is a Dirac
mass, here it is `0`, so only the measurable case can be shimmed). -/
instance isProbabilityMeasure_map_measurableEquiv {α β : Type*} [MeasurableSpace α]
[MeasurableSpace β] {μ : MeasureTheory.Measure α} [MeasureTheory.IsProbabilityMeasure μ]
(e : α ≃ᵐ β) : MeasureTheory.IsProbabilityMeasure (μ.map e) :=
MeasureTheory.Measure.isProbabilityMeasure_map e.measurable.aemeasurable
/-- `simp` closes `2 ≤ ∞` in `WithTop ℕ∞` (the smoothness order) in Mathlib d13f23b; ours has the
lemma only for `1` and casts (AffineBernstein, `isSymmSndFDerivAt (by simp)`, 2026-10-26). -/
@[simp]
theorem ofNat_le_infty (n : ℕ) [n.AtLeastTwo] : (no_index (OfNat.ofNat n) : WithTop ℕ∞) ≤ ((⊤ : ℕ∞) : WithTop ℕ∞) :=
ENat.LEInfty.out
end OAICompat434
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_PathStrength
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Switching
open Finset
open scoped Classical symmDiff
variable {V : Type*}
theorem sdiff_pair_card [DecidableEq V] (S : Finset V) (a b : V)
(ha : a ∈ S) (hb : b ∈ S) (hab : a ≠ b) :
(S \ {a,b}).card = S.card - 2 := by
have hsub : ({a,b} : Finset V) ⊆ S := by
intro x hx
rcases Finset.mem_insert.mp hx with h | h
· subst x
exact ha
· have he := Finset.mem_singleton.mp h
subst x
exact hb
rw [Finset.card_sdiff_of_subset hsub, Finset.card_pair hab]
end MatchingFPRAS.Switching
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_AffineWeights
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Switching
open Finset
open scoped Classical symmDiff
variable {V : Type*}
def affineWeights (w d : V → V → ℝ) (t : ℝ) (a b : V) : ℝ := w a b + t * d a b
noncomputable def edgeSum [Fintype V] [LinearOrder V]
(S : Finset V) (f : V → V → ℝ) : ℝ :=
∑ a, ∑ b, if a < b ∧ a ∉ S ∧ b ∉ S then f a b else 0
noncomputable def holeScale (V : Type*) [Fintype V] : ℝ :=
100000000 * ((Fintype.card V : ℝ) + 1)^4
end MatchingFPRAS.Switching
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Complexity_GuardMachineBase
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.MachineCost
open Turing
def statementCost {Γ Λ σ : Type*} : TM1.Stmt Γ Λ σ → ℕ
| .move _ q => statementCost q+1
| .write _ q => statementCost q+1
| .load _ q => statementCost q
| .branch _ q r => max (statementCost q) (statementCost r)
| .goto _ => 1
| .halt => 1
variable {Γ Λ σ : Type*} [Inhabited Γ] [Inhabited Λ] [Inhabited σ]
variable (M : Λ → TM1.Stmt Γ Λ σ)
noncomputable def programCost [Fintype Λ] : ℕ := Finset.univ.sup (fun l=>statementCost (M l))
end MatchingFPRAS.MachineCost
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Complexity_StackCompilerCost
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.StackCost
open Turing Turing.TM2to1 Turing.TM2to1.Λ' MachineCost
variable {K : Type*} {Γ : K → Type*} {Λ σ : Type*} [DecidableEq K]
def accesses : TM2.Stmt Γ Λ σ → ℕ
| .push _ _ q => accesses q+1
| .peek _ _ q => accesses q+1
| .pop _ _ q => accesses q+1
| .load _ q => accesses q
| .branch _ q r => max (accesses q) (accesses r)
| .goto _ => 0
| .halt => 0
def StackBound (S : ∀ k,List (Γ k)) (H : ℕ) : Prop := ∀ k,(S k).length≤H
end MatchingFPRAS.StackCost
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_SupportedCompiler
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.SupportedCompiler
open Turing MachineCost
open scoped Classical
variable {Γ Λ σ : Type*} [Inhabited Γ] [Inhabited Λ] [Inhabited σ]
variable (M : Λ → TM1.Stmt Γ Λ σ) (S : Finset Λ) (hS : TM1.Supports M S)
noncomputable def cost : ℕ := S.sup (fun l=>statementCost (M l))
end MatchingFPRAS.SupportedCompiler
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_FixedAlphabetCompiler
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FixedAlphabetCompiler
open Turing MachineCost
open scoped Classical
variable {Γ Λ σ : Type*} [Inhabited Γ] [Fintype Γ] [Inhabited Λ]
[Inhabited σ] [Fintype σ]
variable {w : ℕ} (enc : Γ → List.Vector Bool w) (dec : List.Vector Bool w → Γ)
(enc0 : enc default = List.Vector.replicate w false)
(encdec : ∀ a,dec (enc a)=a) (M : Λ → TM1.Stmt Γ Λ σ)
(S : Finset Λ) (hS : TM1.Supports M S)
def bitsWord (input : List Γ) : List Bool := input.flatMap (fun a=>(enc a).toList)
end MatchingFPRAS.FixedAlphabetCompiler
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_FixedEncoding
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FixedEncoding
variable (Γ : Type*) [Fintype Γ] [Inhabited Γ]
noncomputable def enc (a : Γ) : List.Vector Bool (Fintype.card Γ) := by
classical
exact List.Vector.ofFn (fun i=>decide (a≠default ∧ Fintype.equivFin Γ a=i))
lemma blank : enc Γ default=List.Vector.replicate (Fintype.card Γ) false := by
classical
apply List.Vector.ext
intro i
simp [enc]
noncomputable def dec : List.Vector Bool (Fintype.card Γ) → Γ := Function.invFun (enc Γ)
end MatchingFPRAS.FixedEncoding
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_StackWords
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.StackWords
open Turing MachineCost
variable {K : Type*} {Γ : K → Type*}
def rows (S : ∀ k,List (Γ k)) (H : ℕ) : List (∀ k,Option (Γ k)) :=
List.ofFn (fun i : Fin H=>fun k=>(S k).reverse[i.val]?)
def word (S : ∀ k,List (Γ k)) (H : ℕ) : List (TM2to1.Γ' K Γ) :=
(true,(rows S H).headI)::((rows S H).tail.map (fun a=>(false,a)))
end MatchingFPRAS.StackWords
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_ColoredEdge
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V L : Type*}
variable {E : Type*} [DecidableEq V] [DecidableEq E] (inc : E → V → Prop)
lemma union_val_add {F G : Finset E} (h : Disjoint F G) :
(F ∪ G).val = F.val + G.val := by
rw [← Finset.disjUnion_eq_union F G h, Finset.disjUnion_val]
lemma sdiff_val_add {F G : Finset E} (h : G ⊆ F) :
(F \ G).val + G.val = F.val := by
rw [← union_val_add Finset.sdiff_disjoint, Finset.sdiff_union_of_subset h]
def pathPattern (edges : ℕ → E) (lo hi : ℕ) : Finset E :=
((Finset.Ico lo hi).filter (fun i => i % 2 = lo % 2)).image edges
lemma pathPattern_boundary (edges : ℕ → E) (lo hi : ℕ)
(hlong : lo + 3 ≤ hi) (hodd : (hi - lo) % 2 = 1) :
pathPattern edges lo hi = pathPattern edges (lo + 2) (hi - 2) ∪
{edges lo, edges (hi - 1)} := by
have hidx : (Finset.Ico lo hi).filter (fun i => i % 2 = lo % 2) =
((Finset.Ico (lo + 2) (hi - 2)).filter (fun i => i % 2 = (lo + 2) % 2)) ∪
{lo, hi - 1} := by
ext i
simp only [Finset.mem_filter, Finset.mem_Ico, Finset.mem_union,
Finset.mem_insert, Finset.mem_singleton]
omega
unfold pathPattern
rw [hidx, Finset.image_union]
simp only [Finset.image_insert, Finset.image_singleton]
def overlayLineGraph (S : Finset E) : SimpleGraph E where
Adj e f := e ≠ f ∧ e ∈ S ∧ f ∈ S ∧ ∃ v, inc e v ∧ inc f v
symm := ⟨by
intro e f h
rcases h with ⟨h, he, hf, v, hev, hfv⟩
exact ⟨h.symm, hf, he, v, hfv, hev⟩⟩
loopless := ⟨by intro e h; exact h.1 rfl⟩
omit [DecidableEq E] in
lemma multiset_product_comparison (w : E → ℝ) (hw : ∀ e, 0 < w e)
(A : ℝ) (hA : 0 ≤ A) (drop add : Multiset E) (hcard : drop.card = add.card)
(hcompare : ∀ e ∈ drop, ∀ f ∈ add, w e ≤ A * w f) :
(drop.map w).prod ≤ A ^ drop.card * (add.map w).prod := by
induction drop using Multiset.induction_on generalizing add with
| empty =>
have ha : add = 0 := Multiset.card_eq_zero.mp (by simpa using hcard.symm)
subst add
simp
| @cons e drop ih =>
obtain ⟨f, hf⟩ := Multiset.card_pos_iff_exists_mem.mp
(show 0 < add.card by simp only [Multiset.card_cons] at hcard; omega)
obtain ⟨add', rfl⟩ := Multiset.exists_cons_of_mem hf
have hcard' : drop.card = add'.card := by simpa using hcard
have hi := ih add' hcard' (fun a ha b hb =>
hcompare a (Multiset.mem_cons_of_mem ha) b (Multiset.mem_cons_of_mem hb))
have he := hcompare e (Multiset.mem_cons_self _ _) f (Multiset.mem_cons_self _ _)
have hp : 0 ≤ (drop.map w).prod := le_of_lt <| Multiset.prod_pos (by
intro z hz
obtain ⟨a, _, rfl⟩ := Multiset.mem_map.mp hz
exact hw a)
have hb : 0 ≤ A * w f := mul_nonneg hA (le_of_lt (hw f))
simpa only [Multiset.map_cons, Multiset.prod_cons, Multiset.card_cons, pow_succ,
mul_assoc, mul_left_comm, mul_comm] using mul_le_mul he hi hp hb
omit [DecidableEq E] in
lemma four_edge_weight_bound (w : E → ℝ) (hw : ∀ e, 0 < w e)
(A : ℝ) (hA : 1 ≤ A) (input output drop add : Multiset E)
(hcons : input + add = output + drop)
(hcard : drop.card = add.card) (hfour : drop.card ≤ 4)
(hcompare : ∀ e ∈ drop, ∀ f ∈ add, w e ≤ A * w f) :
(input.map w).prod ≤ A ^ 4 * (output.map w).prod := by
have hnonneg : 0 ≤ A := by linarith
have hc := multiset_product_comparison w hw A hnonneg drop add hcard hcompare
have ha : 0 < (add.map w).prod := Multiset.prod_pos (by
intro z hz
obtain ⟨e, _, rfl⟩ := Multiset.mem_map.mp hz
exact hw e)
have ho : 0 ≤ (output.map w).prod := le_of_lt <| Multiset.prod_pos (by
intro z hz
obtain ⟨e, _, rfl⟩ := Multiset.mem_map.mp hz
exact hw e)
have hweight := congrArg (fun s : Multiset E => (s.map w).prod) hcons
simp only [Multiset.map_add, Multiset.prod_add] at hweight
have hpow : A ^ drop.card ≤ A ^ 4 := pow_le_pow_right₀ hA hfour
have hc' : (drop.map w).prod ≤ A ^ 4 * (add.map w).prod :=
hc.trans (mul_le_mul_of_nonneg_right hpow (le_of_lt ha))
apply (mul_le_mul_iff_left₀ ha).mp
calc
_ = (output.map w).prod * (drop.map w).prod := hweight
_ ≤ (output.map w).prod * (A ^ 4 * (add.map w).prod) :=
mul_le_mul_of_nonneg_left hc' ho
_ = _ := by ring
structure OddPath where
length : ℕ
positive : 0 < length
odd : length % 2 = 1
vertex : ℕ → V
edge : ℕ → E
simple : Set.InjOn vertex (Set.Icc 0 length)
incidence : ∀ i, i < length → ∀ v,
inc (edge i) v ↔ v = vertex i ∨ v = vertex (i + 1)
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Span
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V L : Type*} [DecidableEq V]
variable {E : Type*} [DecidableEq E] (inc : E → V → Prop)
namespace OddPath
variable {inc}
variable (p : OddPath inc)
def span : Finset V := (Finset.Icc 0 p.length).image p.vertex
def inside : Finset V := (Finset.Icc 1 (p.length - 1)).image p.vertex
def ends : Finset V := {p.vertex 0, p.vertex p.length}
def through : Finset E := pathPattern p.edge 0 p.length
def interior : Finset E := pathPattern p.edge 1 (p.length - 1)
def closed (chord : E) : Finset E := p.interior ∪ {chord}
def boundary : Finset E := if p.length = 1 then {p.edge 0}
else {p.edge 0, p.edge (p.length - 1)}
def repaired (repair : E) : Finset E := if p.length = 1 then ∅
else pathPattern p.edge 2 (p.length - 2) ∪ {repair}
def repairAdded (repair : E) : Multiset E := if p.length = 1 then 0 else {repair}
omit [DecidableEq E] in
lemma inside_disjoint_ends : Disjoint p.inside p.ends := by
apply Finset.disjoint_left.mpr
intro v hv hw
obtain ⟨i, hi, rfl⟩ := Finset.mem_image.mp hv
obtain ⟨hil, hih⟩ := Finset.mem_Icc.mp hi
simp only [ends, Finset.mem_insert, Finset.mem_singleton] at hw
rcases hw with h | h
· have hh := p.simple ⟨by omega, by omega⟩ ⟨le_rfl, Nat.zero_le _⟩ h
omega
· have hh := p.simple ⟨by omega, by omega⟩ ⟨Nat.zero_le _, le_rfl⟩ h
omega
omit [DecidableEq E] in
lemma inside_union_ends : p.inside ∪ p.ends = p.span := by
ext v
simp only [inside, ends, span, Finset.mem_union, Finset.mem_image,
Finset.mem_Icc, Finset.mem_insert, Finset.mem_singleton]
constructor
· rintro (⟨i, hi, rfl⟩ | rfl | rfl)
· exact ⟨i, ⟨by omega, by omega⟩, rfl⟩
· exact ⟨0, ⟨le_rfl, Nat.zero_le _⟩, rfl⟩
· exact ⟨p.length, ⟨Nat.zero_le _, le_rfl⟩, rfl⟩
· rintro ⟨i, hi, rfl⟩
by_cases h0 : i = 0
· exact Or.inr (Or.inl (congrArg p.vertex h0))
by_cases hh : i = p.length
· exact Or.inr (Or.inr (congrArg p.vertex hh))
· exact Or.inl ⟨i, ⟨by omega, by omega⟩, rfl⟩
omit [DecidableEq V] [DecidableEq E] in
lemma edge_injective : Set.InjOn p.edge (Set.Ico 0 p.length) := by
intro i hi j hj heq
simp only [Set.mem_Ico] at hi hj
have hiinc : inc (p.edge i) (p.vertex i) := (p.incidence i hi.2 _).mpr (Or.inl rfl)
rw [heq] at hiinc
have hjinc : inc (p.edge j) (p.vertex (i+1)) := by
rw [← heq]
exact (p.incidence i hi.2 _).mpr (Or.inr rfl)
have hi₁ := (p.incidence j hj.2 _).mp hiinc
have hi₂ := (p.incidence j hj.2 _).mp hjinc
have hs₁ : i = j ∨ i = j + 1 := hi₁.imp
(p.simple ⟨by omega, by omega⟩ ⟨by omega, by omega⟩)
(p.simple ⟨by omega, by omega⟩ ⟨by omega, by omega⟩)
have hs₂ : i+1 = j ∨ i+1 = j+1 := hi₂.imp
(p.simple ⟨by omega, by omega⟩ ⟨by omega, by omega⟩)
(p.simple ⟨by omega, by omega⟩ ⟨by omega, by omega⟩)
omega
omit [DecidableEq V] in
lemma boundary_card : p.boundary.card = if p.length = 1 then 1 else 2 := by
by_cases h : p.length = 1
· simp [boundary, h]
· have hpos := p.positive
have hodd := p.odd
have hneq : p.edge 0 ≠ p.edge (p.length - 1) := by
intro heq
have hh := p.edge_injective ⟨le_rfl, hpos⟩ ⟨by omega, by omega⟩ heq
omega
simp [boundary, h, hneq]
end OddPath
structure CellPaths where
side : Fin 4 → OddPath inc
joins : ∀ i, (side i).vertex (side i).length = (side (i+1)).vertex 0
corners_injective : Function.Injective fun i => (side i).vertex 0
interiors_disjoint : Pairwise fun i j => Disjoint (side i).inside (side j).inside
interior_ends_disjoint : ∀ i j, Disjoint (side i).inside (side j).ends
chord : Fin 4 → E
chord_incidence : ∀ i v, inc (chord i) v ↔
v = (side i).vertex 0 ∨ v = (side i).vertex (side i).length
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Corner
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V L : Type*} [DecidableEq V]
variable {E : Type*} [DecidableEq E] (inc : E → V → Prop)
namespace CellPaths
variable {inc} (c : CellPaths inc)
def corner (i : Fin 4) : V := (c.side i).vertex 0
def vertices : Finset V :=
((c.side 0).inside ∪ (c.side 1).inside) ∪ ((c.side 2).inside ∪ (c.side 3).inside) ∪
{c.corner 0, c.corner 1, c.corner 2, c.corner 3}
omit [DecidableEq E] in
lemma ends_eq (i : Fin 4) : (c.side i).ends = {c.corner i, c.corner (i+1)} := by
simp only [OddPath.ends, c.joins, corner]
omit [DecidableEq E] in
lemma inside_disjoint_span (i j : Fin 4) (hij : i ≠ j) :
Disjoint (c.side i).inside (c.side j).span := by
rw [← (c.side j).inside_union_ends]
exact Finset.disjoint_union_right.mpr
⟨c.interiors_disjoint hij, c.interior_ends_disjoint i j⟩
omit [DecidableEq E] in
lemma opposite_ends_even : Disjoint (c.side 0).ends (c.side 2).ends := by
rw [c.ends_eq, c.ends_eq]
apply Finset.disjoint_left.mpr
intro v hv hw
simp only [Finset.mem_insert, Finset.mem_singleton] at hv hw
rcases hv with h | h <;> rcases hw with k | k
all_goals have hh := c.corners_injective (h.symm.trans k)
all_goals exact absurd hh (by decide)
omit [DecidableEq E] in
lemma opposite_ends_odd : Disjoint (c.side 1).ends (c.side 3).ends := by
rw [c.ends_eq, c.ends_eq]
apply Finset.disjoint_left.mpr
intro v hv hw
simp only [Finset.mem_insert, Finset.mem_singleton] at hv hw
rcases hv with h | h <;> rcases hw with k | k
all_goals have hh := c.corners_injective (h.symm.trans k)
all_goals exact absurd hh (by decide)
omit [DecidableEq E] in
lemma opposite_span_even : Disjoint (c.side 0).span (c.side 2).span := by
rw [← (c.side 0).inside_union_ends]
apply Finset.disjoint_union_left.mpr
refine ⟨c.inside_disjoint_span 0 2 (by decide), ?_⟩
rw [← (c.side 2).inside_union_ends]
exact Finset.disjoint_union_right.mpr ⟨(c.interior_ends_disjoint 2 0).symm,
c.opposite_ends_even⟩
omit [DecidableEq E] in
lemma opposite_span_odd : Disjoint (c.side 1).span (c.side 3).span := by
rw [← (c.side 1).inside_union_ends]
apply Finset.disjoint_union_left.mpr
refine ⟨c.inside_disjoint_span 1 3 (by decide), ?_⟩
rw [← (c.side 3).inside_union_ends]
exact Finset.disjoint_union_right.mpr ⟨(c.interior_ends_disjoint 3 1).symm,
c.opposite_ends_odd⟩
omit [DecidableEq E] in
lemma even_blocks_union :
((c.side 0).span ∪ (c.side 2).span) ∪
((c.side 1).inside ∪ (c.side 3).inside) = c.vertices := by
rw [← (c.side 0).inside_union_ends, ← (c.side 2).inside_union_ends,
c.ends_eq, c.ends_eq]
ext v
simp only [vertices, Finset.mem_union, Finset.mem_insert, Finset.mem_singleton]
tauto
omit [DecidableEq E] in
lemma odd_blocks_union :
((c.side 1).span ∪ (c.side 3).span) ∪
((c.side 0).inside ∪ (c.side 2).inside) = c.vertices := by
rw [← (c.side 1).inside_union_ends, ← (c.side 3).inside_union_ends,
c.ends_eq, c.ends_eq]
ext v
simp only [vertices, Finset.mem_union, Finset.mem_insert, Finset.mem_singleton]
tauto
def assemble (M : Fin 4 → Finset E) : Finset E := (M 0 ∪ M 2) ∪ (M 1 ∪ M 3)
def sideBit (i : Fin 4) : Bool := decide (i.val % 2 = 0)
def blocks (b : Bool) (i : Fin 4) : Finset V :=
if sideBit i = b then (c.side i).span else (c.side i).inside
def pieces (b : Bool) (full inner : Fin 4 → Finset E) (i : Fin 4) : Finset E :=
if sideBit i = b then full i else inner i
omit [DecidableEq E] in
lemma same_bit_spans (i j : Fin 4) (hij : i ≠ j) (hbit : sideBit i = sideBit j) :
Disjoint (c.side i).span (c.side j).span := by
fin_cases i <;> fin_cases j
all_goals try exact (hij rfl).elim
all_goals norm_num [sideBit] at hbit
· exact c.opposite_span_even
· exact c.opposite_span_odd
· exact c.opposite_span_even.symm
· exact c.opposite_span_odd.symm
def orientationPieces (b : Bool) : Fin 4 → Finset E :=
pieces b (fun i => (c.side i).through) (fun i => (c.side i).interior)
def switchPieces (b : Bool) : Fin 4 → Finset E :=
pieces b (fun i => (c.side i).closed (c.chord i)) (fun i => (c.side i).interior)
def repairPieces (b : Bool) (repair : Fin 4 → E) : Fin 4 → Finset E :=
pieces b (fun i => (c.side i).through) (fun i => (c.side i).repaired (repair i))
def guidePieces (b : Bool) (repair : Fin 4 → E) : Fin 4 → Finset E :=
pieces b (fun i => (c.side i).closed (c.chord i)) (fun i => (c.side i).repaired (repair i))
def Repairs (b : Bool) (repair : Fin 4 → E) : Prop :=
∀ i, sideBit i ≠ b → (c.side i).length ≠ 1 → ∀ v,
inc (repair i) v ↔ v = (c.side i).vertex 1 ∨ v = (c.side i).vertex ((c.side i).length - 1)
def orientation (b : Bool) : Finset E := assemble (c.orientationPieces b)
def switched (b : Bool) : Finset E := assemble (c.switchPieces b)
def repaired (b : Bool) (repair : Fin 4 → E) : Finset E := assemble (c.repairPieces b repair)
def guide (b : Bool) (repair : Fin 4 → E) : Finset E := assemble (c.guidePieces b repair)
lemma component_subset_assemble (M : Fin 4 → Finset E) (i : Fin 4) : M i ⊆ assemble M := by
intro e he
fin_cases i <;> simp only [assemble, Finset.mem_union]
· exact Or.inl (Or.inl he)
· exact Or.inr (Or.inl he)
· exact Or.inl (Or.inr he)
· exact Or.inr (Or.inr he)
def drops (r : Bool) : Multiset E :=
∑ i, if sideBit i = r then 0 else (c.side i).boundary.val
def additions (b r : Bool) (repair : Fin 4 → E) : Multiset E :=
(∑ i, if sideBit i = b then {c.chord i} else 0) +
∑ i, if sideBit i = r then 0 else (c.side i).repairAdded (repair i)
lemma two_orientation_pieces (i : Fin 4) :
(c.orientationPieces true i).val + (c.orientationPieces false i).val =
(c.side i).through.val + (c.side i).interior.val := by
cases h : sideBit i <;> simp [orientationPieces, pieces, h, add_comm]
lemma boundary_card_eq (i : Fin 4) (repair : Fin 4 → E) :
(c.side i).boundary.card = 1 + ((c.side i).repairAdded (repair i)).card := by
rw [(c.side i).boundary_card]
by_cases h : (c.side i).length = 1 <;> simp [OddPath.repairAdded, h]
omit [DecidableEq E] in
lemma additions_card (b r : Bool) (repair : Fin 4 → E) :
(c.additions b r repair).card = 2 +
∑ i, if sideBit i = r then 0 else ((c.side i).repairAdded (repair i)).card := by
simp only [additions, Multiset.card_add, Multiset.card_sum]
have h1 : (∑ i : Fin 4, (if sideBit i = b then ({c.chord i} : Multiset E) else 0).card) = 2 := by
cases b <;> norm_num [Fin.sum_univ_four, sideBit]
rw [h1]
congr 1
apply Finset.sum_congr rfl
intro i _
split <;> simp
lemma modification_cards (b r : Bool) (repair : Fin 4 → E) :
(c.drops r).card = (c.additions b r repair).card ∧ (c.drops r).card ≤ 4 := by
have hd : (c.drops r).card = 2 +
∑ i, if sideBit i = r then 0 else ((c.side i).repairAdded (repair i)).card := by
simp only [drops, Multiset.card_sum]
have hb := c.boundary_card_eq
cases r <;> norm_num [Fin.sum_univ_four, sideBit]
all_goals rw [hb _ repair, hb _ repair]; omega
refine ⟨hd.trans (c.additions_card b r repair).symm, ?_⟩
rw [hd]
have hle (i : Fin 4) : ((c.side i).repairAdded (repair i)).card ≤ 1 := by
by_cases h : (c.side i).length = 1 <;> simp [OddPath.repairAdded, h]
have h0 := hle 0
have h1 := hle 1
have h2 := hle 2
have h3 := hle 3
cases r <;> norm_num [Fin.sum_univ_four, sideBit]
all_goals omega
omit [DecidableEq E] in
lemma span_subset_vertices (i : Fin 4) : (c.side i).span ⊆ c.vertices := by
rw [← (c.side i).inside_union_ends, c.ends_eq]
intro v hv
fin_cases i <;> simp only [vertices, Finset.mem_union, Finset.mem_insert,
Finset.mem_singleton] at hv ⊢ <;> tauto
def contextOne (b : Bool) (Y : Fin 4) : Finset E :=
(c.orientation b \ (c.side Y).through) ∪ (c.side Y).closed (c.chord Y)
def guideOne (b : Bool) (repair : Fin 4 → E) (Y : Fin 4) : Finset E :=
(c.guide b repair \ (c.side Y).closed (c.chord Y)) ∪ (c.side Y).through
end CellPaths
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_IndexedCycle
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V E : Type*}
variable (inc : E → V → Prop)
structure IndexedCycle where
size : ℕ
four_le : 4 ≤ size
even : size % 2 = 0
vertex : Fin size → V
simple : Function.Injective vertex
edge : Fin size → E
incidence : ∀ i v, inc (edge i) v ↔ v = vertex i ∨ v = vertex ⟨(i.val + 1) % size, Nat.mod_lt _ (by omega)⟩
namespace IndexedCycle
variable {inc} (c : IndexedCycle inc)
def index (i : ℕ) : Fin c.size := ⟨i % c.size, Nat.mod_lt i (by have := c.four_le; omega)⟩
def vertexAt (i : ℕ) : V := c.vertex (c.index i)
def edgeAt (i : ℕ) : E := c.edge (c.index i)
lemma index_succ (i : ℕ) : c.index (i + 1) = ⟨((c.index i).val + 1) % c.size, Nat.mod_lt _ (by have := c.four_le; omega)⟩ := by
apply Fin.ext
simp only [index, Nat.add_mod, Nat.mod_mod]
lemma vertexAt_periodic (i : ℕ) : c.vertexAt (i + c.size) = c.vertexAt i := by
simp [vertexAt, index]
lemma edgeAt_incidence (i : ℕ) (v : V) :
inc (c.edgeAt i) v ↔ v = c.vertexAt i ∨ v = c.vertexAt (i + 1) := by
simpa [edgeAt, vertexAt, c.index_succ] using c.incidence (c.index i) v
lemma mod_of_lt_twice {m x : ℕ} (hx : x < 2 * m) :
x % m = if x < m then x else x - m := by
split_ifs with h
· exact Nat.mod_eq_of_lt h
· rw [Nat.mod_eq_sub_mod (by omega), Nat.mod_eq_of_lt (by omega)]
lemma vertexAt_eq_iff {a x y : ℕ} (ha : a < c.size)
(hx : a ≤ x ∧ x < a + c.size) (hy : a ≤ y ∧ y < a + c.size) :
c.vertexAt x = c.vertexAt y ↔ x = y := by
constructor
· intro h
have hm : x % c.size = y % c.size := congrArg Fin.val (c.simple h)
rw [mod_of_lt_twice (by omega), mod_of_lt_twice (by omega)] at hm
split_ifs at hm <;> omega
· exact congrArg c.vertexAt
def arc (start length : ℕ) (hstart : start < c.size) (hpos : 0 < length)
(hlt : length < c.size) (hodd : length % 2 = 1) : OddPath inc where
length := length
positive := hpos
odd := hodd
vertex i := c.vertexAt (start + i)
edge i := c.edgeAt (start + i)
simple := by
intro i hi j hj h
change 0 ≤ i ∧ i ≤ length at hi
change 0 ≤ j ∧ j ≤ length at hj
have := (c.vertexAt_eq_iff hstart
(x := start + i) (y := start + j) (by constructor <;> omega)
(by constructor <;> omega)).mp h
omega
incidence := by
intro i hi v
simpa [Nat.add_assoc] using c.edgeAt_incidence (start + i) v
structure Corners where
a₀ : ℕ
a₁ : ℕ
a₂ : ℕ
a₃ : ℕ
lt₀ : a₀ < a₁
lt₁ : a₁ < a₂
lt₂ : a₂ < a₃
lt₃ : a₃ < c.size
odd₀ : (a₁ - a₀) % 2 = 1
odd₁ : (a₂ - a₁) % 2 = 1
odd₂ : (a₃ - a₂) % 2 = 1
odd₃ : (c.size + a₀ - a₃) % 2 = 1
namespace Corners
variable {c} (k : c.Corners)
def start : Fin 4 → ℕ := ![k.a₀, k.a₁, k.a₂, k.a₃]
def stop : Fin 4 → ℕ := ![k.a₁, k.a₂, k.a₃, c.size + k.a₀]
def length (i : Fin 4) : ℕ := k.stop i - k.start i
lemma bounds (i : Fin 4) :
k.a₀ ≤ k.start i ∧ k.start i < c.size ∧
k.start i < k.stop i ∧ k.stop i ≤ k.a₀ + c.size ∧
k.stop i < k.start i + c.size := by
have h₀ := k.lt₀
have h₁ := k.lt₁
have h₂ := k.lt₂
have h₃ := k.lt₃
fin_cases i <;> simp [start, stop] <;> omega
lemma length_pos (i : Fin 4) : 0 < k.length i := by
have := k.bounds i
dsimp [length]
omega
lemma length_lt (i : Fin 4) : k.length i < c.size := by
have := k.bounds i
dsimp [length]
omega
lemma length_odd (i : Fin 4) : k.length i % 2 = 1 := by
fin_cases i
· exact k.odd₀
· exact k.odd₁
· exact k.odd₂
· exact k.odd₃
def side (i : Fin 4) : OddPath inc :=
c.arc (k.start i) (k.length i) (k.bounds i).2.1 (k.length_pos i)
(k.length_lt i) (k.length_odd i)
lemma side_vertex (i : Fin 4) (j : ℕ) :
(k.side i).vertex j = c.vertexAt (k.start i + j) := rfl
lemma side_length (i : Fin 4) : (k.side i).length = k.length i := rfl
lemma side_first (i : Fin 4) : (k.side i).vertex 0 = c.vertexAt (k.start i) := by
simp [side_vertex]
lemma side_last (i : Fin 4) : (k.side i).vertex (k.side i).length =
c.vertexAt (k.stop i) := by
rw [side_vertex, side_length]
congr 1
dsimp [length]
have := k.bounds i
omega
lemma joins (i : Fin 4) : (k.side i).vertex (k.side i).length =
(k.side (i + 1)).vertex 0 := by
rw [side_last, side_first]
fin_cases i <;> simp [start, stop]
simpa only [Nat.add_comm] using c.vertexAt_periodic k.a₀
lemma starts_injective : Function.Injective k.start := by
have h₀ := k.lt₀
have h₁ := k.lt₁
have h₂ := k.lt₂
intro i j h
fin_cases i <;> fin_cases j <;> simp_all [start] <;> omega
lemma corners_injective : Function.Injective fun i => (k.side i).vertex 0 := by
intro i j h
simp only [side_first] at h
have hi := k.bounds i
have hj := k.bounds j
have ha : k.a₀ < c.size := by have := k.lt₀; omega
apply k.starts_injective
exact (c.vertexAt_eq_iff ha ⟨hi.1, by omega⟩ ⟨hj.1, by omega⟩).mp h
variable [DecidableEq V]
lemma inside_iff (i : Fin 4) (v : V) :
v ∈ (k.side i).inside ↔
∃ t, k.start i < t ∧ t < k.stop i ∧ c.vertexAt t = v := by
simp only [OddPath.inside, Finset.mem_image, Finset.mem_Icc, side_length, side_vertex]
constructor
· rintro ⟨j, hj, h⟩
refine ⟨k.start i + j, by omega, ?_, h⟩
have := k.bounds i
dsimp [length] at hj
omega
· rintro ⟨t, hlow, hhigh, h⟩
refine ⟨t - k.start i, ?_, ?_⟩
· dsimp [length]
constructor <;> omega
· have he : k.start i + (t - k.start i) = t := by omega
simpa [he] using h
omit [DecidableEq V] in
lemma interior_ranges_disjoint (i j : Fin 4) (hij : i ≠ j) (t : ℕ)
(hi : k.start i < t ∧ t < k.stop i) :
¬ (k.start j < t ∧ t < k.stop j) := by
have h₀ := k.lt₀
have h₁ := k.lt₁
have h₂ := k.lt₂
have h₃ := k.lt₃
fin_cases i <;> fin_cases j <;> simp_all [start, stop] <;> omega
lemma interiors_disjoint : Pairwise fun i j => Disjoint (k.side i).inside (k.side j).inside := by
intro i j hij
apply Finset.disjoint_left.mpr
intro v hv hw
obtain ⟨x, hx₁, hx₂, hx⟩ := (k.inside_iff i v).mp hv
obtain ⟨y, hy₁, hy₂, hy⟩ := (k.inside_iff j v).mp hw
have hi := k.bounds i
have hj := k.bounds j
have ha : k.a₀ < c.size := by have := k.lt₀; omega
have hxy := (c.vertexAt_eq_iff ha (x := x) (y := y)
⟨by omega, by omega⟩ ⟨by omega, by omega⟩).mp (hx.trans hy.symm)
subst y
exact k.interior_ranges_disjoint i j hij x ⟨hx₁, hx₂⟩ ⟨hy₁, hy₂⟩
omit [DecidableEq V] in
lemma interior_not_corner_index (i j : Fin 4) (t : ℕ)
(ht : k.start i < t ∧ t < k.stop i) : t ≠ k.start j := by
have h₀ := k.lt₀
have h₁ := k.lt₁
have h₂ := k.lt₂
have h₃ := k.lt₃
fin_cases i <;> fin_cases j <;> simp_all [start, stop] <;> omega
lemma interior_ne_corner (i j : Fin 4) {v : V} (hv : v ∈ (k.side i).inside) :
v ≠ (k.side j).vertex 0 := by
intro heq
obtain ⟨t, ht₁, ht₂, ht⟩ := (k.inside_iff i v).mp hv
have hi := k.bounds i
have hj := k.bounds j
have ha : k.a₀ < c.size := by have := k.lt₀; omega
have h := (c.vertexAt_eq_iff ha (x := t) (y := k.start j)
⟨by omega, by omega⟩ ⟨hj.1, by omega⟩).mp (ht.trans (by simpa [side_first] using heq))
exact k.interior_not_corner_index i j t ⟨ht₁, ht₂⟩ h
lemma interior_ends_disjoint (i j : Fin 4) : Disjoint (k.side i).inside (k.side j).ends := by
apply Finset.disjoint_left.mpr
intro v hv hw
simp only [OddPath.ends, Finset.mem_insert, Finset.mem_singleton, k.joins] at hw
exact hw.elim (k.interior_ne_corner i j hv) (k.interior_ne_corner i (j+1) hv)
def cellPaths (chord : Fin 4 → E)
(hchord : ∀ i v, inc (chord i) v ↔
v = (k.side i).vertex 0 ∨ v = (k.side i).vertex (k.side i).length) : CellPaths inc where
side := k.side
joins := k.joins
corners_injective := k.corners_injective
interiors_disjoint := k.interiors_disjoint
interior_ends_disjoint := k.interior_ends_disjoint
chord := chord
chord_incidence := hchord
end Corners
end IndexedCycle
end
variable {V E : Type*}
variable {inc : E → V → Prop}
namespace IndexedCycle
variable (c : IndexedCycle inc)
lemma edgeAt_mod (i : ℕ) : c.edgeAt (i % c.size) = c.edgeAt i := by
exact congrArg c.edge (Fin.ext (Nat.mod_mod i c.size))
lemma consecutive_ne (i : ℕ) (hi : i < c.size) : c.edgeAt i ≠ c.edgeAt (i+1) := by
intro he
have hm : inc (c.edgeAt (i+1)) (c.vertexAt i) := he ▸
(c.edgeAt_incidence i _).mpr (Or.inl rfl)
rcases (c.edgeAt_incidence (i+1) _).mp hm with h | h
· have := (c.vertexAt_eq_iff hi (x := i) (y := i+1)
(by have := c.four_le; omega) (by have := c.four_le; omega)).mp h
omega
· have := (c.vertexAt_eq_iff hi (x := i) (y := i+1+1)
(by have := c.four_le; omega) (by have := c.four_le; omega)).mp h
omega
lemma edges_reachable (U : Finset E) (hU : ∀ i, c.edgeAt i ∈ U) (i : ℕ) :
(overlayLineGraph inc U).Reachable (c.edgeAt 0) (c.edgeAt i) := by
suffices hs : ∀ j, j < c.size →
(overlayLineGraph inc U).Reachable (c.edgeAt 0) (c.edgeAt j) by
simpa only [c.edgeAt_mod] using hs (i % c.size)
(Nat.mod_lt i (by have := c.four_le; omega))
intro j hj
induction j with
| zero => exact SimpleGraph.Reachable.refl _
| succ j ih =>
apply (ih (by omega)).trans
apply SimpleGraph.Adj.reachable
refine ⟨c.consecutive_ne j (by omega), hU j, hU (j+1), ?_⟩
exact ⟨c.vertexAt (j+1), (c.edgeAt_incidence j _).mpr (Or.inr rfl),
(c.edgeAt_incidence (j+1) _).mpr (Or.inl rfl)⟩
namespace Corners
variable {c} (k : c.Corners)
lemma parity_start (i : Fin 4) :
k.start i % 2 = if CellPaths.sideBit i then k.a₀ % 2 else 1 - k.a₀ % 2 := by
have h₀ := k.lt₀
have h₁ := k.lt₁
have h₂ := k.lt₂
have ho₀ := k.odd₀
have ho₁ := k.odd₁
have ho₂ := k.odd₂
fin_cases i <;> simp [start, CellPaths.sideBit] <;> omega
variable [DecidableEq V] [DecidableEq E]
lemma cell_orientation_subset (chord : Fin 4 → E)
(hc : ∀ i v, inc (chord i) v ↔
v = (k.side i).vertex 0 ∨ v = (k.side i).vertex (k.side i).length)
(S : Finset E) (a : ℕ) (ha : a < 2)
(hS : ∀ t, t % 2 = a → c.edgeAt t ∈ S) :
(k.cellPaths chord hc).orientation (decide (k.a₀ % 2 = a)) ⊆ S := by
have hh : ∀ i, (k.cellPaths chord hc).orientationPieces (decide (k.a₀ % 2 = a)) i ⊆ S := by
intro i e he
simp only [CellPaths.orientationPieces, CellPaths.pieces] at he
split_ifs at he with hi
· obtain ⟨j, hj, rfl⟩ := Finset.mem_image.mp he
obtain ⟨hb, hp⟩ := Finset.mem_filter.mp hj
obtain ⟨hjl, hjr⟩ := Finset.mem_Ico.mp hb
apply hS
have hs := k.parity_start i
have hp' : j % 2 = 0 := hp
change CellPaths.sideBit i = decide (k.a₀ % 2 = a) at hi
change (k.start i + j) % 2 = a
rw [Nat.add_mod, hs, hp']
cases hbit : CellPaths.sideBit i <;> simp_all
omega
· obtain ⟨j, hj, rfl⟩ := Finset.mem_image.mp he
obtain ⟨hb, hp⟩ := Finset.mem_filter.mp hj
obtain ⟨hjl, hjr⟩ := Finset.mem_Ico.mp hb
apply hS
have hs := k.parity_start i
have hp' : j % 2 = 1 := hp
change CellPaths.sideBit i ≠ decide (k.a₀ % 2 = a) at hi
change (k.start i + j) % 2 = a
rw [Nat.add_mod, hs, hp']
cases hbit : CellPaths.sideBit i <;> simp_all <;> omega
intro e he
change e ∈ CellPaths.assemble _ at he
simp only [CellPaths.assemble, Finset.mem_union] at he
rcases he with (he | he) | (he | he)
· exact hh 0 he
· exact hh 2 he
· exact hh 1 he
· exact hh 3 he
lemma cell_orientation_reachable (chord : Fin 4 → E)
(hc : ∀ i v, inc (chord i) v ↔
v = (k.side i).vertex 0 ∨ v = (k.side i).vertex (k.side i).length)
(U : Finset E) (hU : ∀ i, c.edgeAt i ∈ U) (b : Bool) :
∀ e ∈ (k.cellPaths chord hc).orientation b,
(overlayLineGraph inc U).Reachable (c.edgeAt 0) e := by
have hh : ∀ i e, e ∈ (k.cellPaths chord hc).orientationPieces b i →
(overlayLineGraph inc U).Reachable (c.edgeAt 0) e := by
intro i e he
simp only [CellPaths.orientationPieces, CellPaths.pieces] at he
split_ifs at he <;>
obtain ⟨j, _, rfl⟩ := Finset.mem_image.mp he <;>
exact c.edges_reachable U hU (k.start i + j)
intro e he
change e ∈ CellPaths.assemble _ at he
simp only [CellPaths.assemble, Finset.mem_union] at he
rcases he with (he | he) | (he | he)
· exact hh 0 e he
· exact hh 2 e he
· exact hh 1 e he
· exact hh 3 e he
end Corners
end IndexedCycle
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Sets
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V E L : Type*}
namespace IndexedCycle
variable {inc : E → V → Prop} (c : IndexedCycle inc)
def zindex (i : ℤ) : Fin c.size :=
⟨(i % (c.size : ℤ)).toNat, (Int.toNat_lt (Int.emod_nonneg _ (by
have := c.four_le; omega))).mpr (Int.emod_lt_of_pos _ (by have := c.four_le; omega))⟩
def vertexAtZ (i : ℤ) : V := c.vertex (c.zindex i)
def edgeAtZ (i : ℤ) : E := c.edge (c.zindex i)
lemma zindex_nat (i : ℕ) : c.zindex i = c.index i := by
apply Fin.ext
change ((i : ℤ) % (c.size : ℤ)).toNat = i % c.size
rw [← Int.natCast_emod, Int.toNat_natCast]
lemma zindex_periodic (i : ℤ) : c.zindex (i + c.size) = c.zindex i := by
apply Fin.ext
simp [zindex]
lemma vertexAtZ_nat (i : ℕ) : c.vertexAtZ i = c.vertexAt i := by
simp [vertexAtZ, vertexAt, c.zindex_nat]
lemma edgeAtZ_nat (i : ℕ) : c.edgeAtZ i = c.edgeAt i := by
simp [edgeAtZ, edgeAt, c.zindex_nat]
lemma edgeAtZ_periodic (i : ℤ) : c.edgeAtZ (i + c.size) = c.edgeAtZ i := by
simp [edgeAtZ, c.zindex_periodic]
lemma zindex_succ (i : ℤ) : c.zindex (i + 1) =
⟨((c.zindex i).val + 1) % c.size, Nat.mod_lt _ (by have := c.four_le; omega)⟩ := by
have hsz : (c.size : ℤ) ≠ 0 := by have := c.four_le; omega
apply Fin.ext
apply Int.natCast_inj.mp
change (((i + 1) % (c.size : ℤ)).toNat : ℤ) =
(((((i % (c.size : ℤ)).toNat + 1) % c.size) : ℕ) : ℤ)
rw [Int.toNat_of_nonneg (Int.emod_nonneg _ hsz), Int.natCast_emod,
Nat.cast_add, Nat.cast_one, Int.toNat_of_nonneg (Int.emod_nonneg _ hsz)]
simp only [Int.add_emod, Int.emod_emod]
lemma edgeAtZ_incidence (i : ℤ) (v : V) :
inc (c.edgeAtZ i) v ↔ v = c.vertexAtZ i ∨ v = c.vertexAtZ (i+1) := by
simpa [edgeAtZ, vertexAtZ, c.zindex_succ] using c.incidence (c.zindex i) v
end IndexedCycle
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_LabelCycle
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V E L : Type*}
namespace IndexedCycle
variable {bags : V → Finset L}
variable {G : SimpleGraph L}
variable (hbags : ∀ v, ∀ a ∈ bags v, ∀ b ∈ bags v, a = b ∨ G.Adj a b)
variable [DecidableEq L]
variable (height : L → ℝ) (hheight : ∀ l, 0 < height l)
variable (hstep : ∀ a b, G.Adj a b → height a ≤ 2 * height b)
lemma common_clamp_ratio {lo hi A x y : ℝ} (hlo : 0 ≤ lo) (hA : 1 ≤ A)
(hxy : x ≤ A * y) :
max lo (min hi x) ≤ A * max lo (min hi y) := by
have hnonneg : 0 ≤ max lo (min hi y) := le_trans hlo (le_max_left _ _)
have hupper : max lo (min hi y) ≤ A * max lo (min hi y) := by nlinarith
apply max_le
· exact le_trans (le_max_left _ _) hupper
· by_cases hy : y ≤ hi
· have hm : y ≤ max lo (min hi y) := by rw [min_eq_right hy]; exact le_max_right _ _
exact le_trans (min_le_right _ _) (le_trans hxy (mul_le_mul_of_nonneg_left hm (by linarith)))
· have hm : hi ≤ max lo (min hi y) := by rw [min_eq_left (le_of_not_ge hy)]; exact le_max_right _ _
exact le_trans (min_le_left _ _) (le_trans hm hupper)
end IndexedCycle
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_PM
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V E : Type*} [Fintype V] [DecidableEq E]
variable (inc : E → V → Prop)
abbrev DemandTag := E × (Fin 4 → V) × Fin 64 × Bool × (Fin 4 → Option E) × (Fin 4 → Option E)
noncomputable def padOccurrences (m : Multiset E) : Fin 4 → Option E :=
fun i => m.toList[i.val]?
end
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_IntervalPattern
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V E : Type*}
variable {inc : E → V → Prop}
namespace IndexedCycle
variable (c : IndexedCycle inc)
lemma edgeAt_periodic (i : ℕ) : c.edgeAt (i + c.size) = c.edgeAt i := by
simp [edgeAt, index]
variable [DecidableEq E]
def intervalPattern (x y a : ℕ) : Finset E :=
((Finset.Ico x y).filter (fun i => i % 2 = a)).image c.edgeAt
def parityPattern (a : ℕ) : Finset E := c.intervalPattern 0 c.size a
lemma mem_intervalPattern (e : E) (x y a : ℕ) :
e ∈ c.intervalPattern x y a ↔ ∃ i, x ≤ i ∧ i < y ∧ i % 2 = a ∧ c.edgeAt i = e := by
simp only [intervalPattern, Finset.mem_image, Finset.mem_filter, Finset.mem_Ico]
aesop
lemma intervalPattern_union {x y z : ℕ} (hxy : x ≤ y) (hyz : y ≤ z) (a : ℕ) :
c.intervalPattern x y a ∪ c.intervalPattern y z a = c.intervalPattern x z a := by
ext e
simp only [Finset.mem_union, c.mem_intervalPattern]
constructor
· rintro (⟨i,hi,hj,hp,he⟩ | ⟨i,hi,hj,hp,he⟩)
· exact ⟨i,hi,by omega,hp,he⟩
· exact ⟨i,by omega,hj,hp,he⟩
· rintro ⟨i,hi,hj,hp,he⟩
by_cases h : i < y
· exact Or.inl ⟨i,hi,h,hp,he⟩
· exact Or.inr ⟨i,by omega,hj,hp,he⟩
lemma intervalPattern_periodic {x y : ℕ} (a : ℕ) :
c.intervalPattern (x + c.size) (y + c.size) a = c.intervalPattern x y a := by
ext e
simp only [c.mem_intervalPattern]
constructor
· rintro ⟨i,hi,hj,hp,he⟩
have hn : c.size ≤ i := by omega
refine ⟨i-c.size,by omega,by omega,?_,?_⟩
· have hh := c.even
omega
· have eq : i - c.size + c.size = i := by omega
rw [← c.edgeAt_periodic, eq]
exact he
· rintro ⟨i,hi,hj,hp,he⟩
refine ⟨i+c.size,by omega,by omega,?_,?_⟩
· have hh := c.even
omega
· rw [c.edgeAt_periodic]; exact he
lemma rotatedPattern {x : ℕ} (hx : x ≤ c.size) (a : ℕ) :
c.intervalPattern x (x+c.size) a = c.parityPattern a := by
rw [← c.intervalPattern_union hx (by omega) a]
have hh : c.intervalPattern c.size (x+c.size) a = c.intervalPattern 0 x a := by
simpa only [zero_add] using (c.intervalPattern_periodic (x := 0) (y := x) a)
rw [hh, Finset.union_comm, c.intervalPattern_union (by omega) hx a]
rfl
lemma arc_through (x l : ℕ) (hx : x < c.size) (hl : 0 < l)
(hlt : l < c.size) (ho : l % 2 = 1) :
(c.arc x l hx hl hlt ho).through = c.intervalPattern x (x+l) (x%2) := by
ext e
simp only [OddPath.through, pathPattern, Finset.mem_image, Finset.mem_filter,
Finset.mem_Ico, c.mem_intervalPattern]
dsimp only [arc]
constructor
· rintro ⟨j,⟨⟨_,hj⟩,hp⟩,he⟩
exact ⟨x+j,by omega,by omega,by omega,he⟩
· rintro ⟨i,hi,hj,hp,he⟩
refine ⟨i-x,⟨⟨by omega,by omega⟩,by omega⟩,?_⟩
simpa only [Nat.add_sub_of_le hi] using he
lemma arc_interior (x l : ℕ) (hx : x < c.size) (hl : 0 < l)
(hlt : l < c.size) (ho : l % 2 = 1) :
(c.arc x l hx hl hlt ho).interior = c.intervalPattern x (x+l) (1-x%2) := by
ext e
simp only [OddPath.interior, pathPattern, Finset.mem_image, Finset.mem_filter,
Finset.mem_Ico, c.mem_intervalPattern]
dsimp only [arc]
constructor
· rintro ⟨j,⟨⟨hj₀,hj₁⟩,hp⟩,he⟩
exact ⟨x+j,by omega,by omega,by omega,he⟩
· rintro ⟨i,hi,hj,hp,he⟩
refine ⟨i-x,⟨⟨by omega,by omega⟩,by omega⟩,?_⟩
simpa only [Nat.add_sub_of_le hi] using he
end IndexedCycle
end
open scoped symmDiff
variable {V E : Type*} [DecidableEq E]
variable {inc : E → V → Prop}
def exchange (M N S : Finset E) : Finset E := (M \ S) ∪ (N ∩ S)
lemma mem_exchange (M N S : Finset E) (e : E) :
e ∈ exchange M N S ↔ (e ∈ M ∧ e ∉ S) ∨ (e ∈ N ∧ e ∈ S) := by
simp only [exchange, Finset.mem_union, Finset.mem_sdiff, Finset.mem_inter]
lemma exchange_union (M N S : Finset E) :
exchange M N S ∪ exchange N M S = M ∪ N := by
ext e
simp only [Finset.mem_union, mem_exchange]
tauto
lemma exchange_involution (M N S : Finset E) :
exchange (exchange M N S) (exchange N M S) S = M := by
ext e
simp only [mem_exchange]
tauto
def ExchangeCompatible (M N S : Finset E) : Prop :=
∀ e ∈ M, ∀ f ∈ N, ∀ v, inc e v → inc f v → (e ∈ S ↔ f ∈ S)
omit [DecidableEq E] in
lemma ExchangeCompatible.symm {M N S : Finset E} (h : ExchangeCompatible (inc := inc) M N S) :
ExchangeCompatible (inc := inc) N M S := by
intro f hf e he v hfv hev
exact (h e he f hf v hev hfv).symm
noncomputable def componentEdges (U : Finset E) (anchor : E) : Finset E := by
classical
exact U.filter ((overlayLineGraph inc U).Reachable anchor)
omit [DecidableEq E] in
lemma mem_componentEdges (U : Finset E) (a e : E) :
e ∈ componentEdges (inc := inc) U a ↔ e ∈ U ∧ (overlayLineGraph inc U).Reachable a e := by
classical
simp only [componentEdges, Finset.mem_filter]
lemma shares_reachable {U : Finset E} {e f : E} (he : e ∈ U) (hf : f ∈ U)
{v : V} (hev : inc e v) (hfv : inc f v) :
(overlayLineGraph inc U).Reachable e f := by
by_cases h : e = f
· subst f; exact SimpleGraph.Reachable.refl e
· exact (show (overlayLineGraph inc U).Adj e f from ⟨h,he,hf,v,hev,hfv⟩).reachable
lemma component_compatible (M N : Finset E) (anchor : E) :
ExchangeCompatible (inc := inc) M N (componentEdges (inc := inc) (M ∪ N) anchor) := by
intro e he f hf v hev hfv
have heu := Finset.mem_union_left N he
have hfu := Finset.mem_union_right M hf
have hr := shares_reachable heu hfu hev hfv
simp only [mem_componentEdges, heu, hfu, true_and]
exact ⟨fun h => h.trans hr, fun h => h.trans hr.symm⟩
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Components
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V E : Type*} [DecidableEq E]
variable {inc : E → V → Prop}
noncomputable def components (U : Finset E) : Finset (Finset E) := by
classical
exact U.image (componentEdges (inc := inc) U)
lemma mem_components {U S : Finset E} :
S ∈ components (inc := inc) U ↔ ∃ a ∈ U, componentEdges (inc := inc) U a = S := by
classical
simp only [components, Finset.mem_image]
omit [DecidableEq E] in
lemma componentEdges_self {U : Finset E} {a : E} (ha : a ∈ U) :
a ∈ componentEdges (inc := inc) U a :=
(mem_componentEdges U a a).mpr ⟨ha,SimpleGraph.Reachable.refl a⟩
lemma component_nonempty {U S : Finset E} (hS : S ∈ components (inc := inc) U) : S.Nonempty := by
obtain ⟨a,ha,rfl⟩ := mem_components.mp hS
exact ⟨a,componentEdges_self ha⟩
lemma component_exists_vertex (hinc : ∀ e, ∃ v, inc e v)
{U S : Finset E} (hS : S ∈ components (inc := inc) U) :
∃ v, ∃ e ∈ S, inc e v := by
obtain ⟨e,he⟩ := component_nonempty hS
obtain ⟨v,hv⟩ := hinc e
exact ⟨v,e,he,hv⟩
noncomputable def componentVertex (hinc : ∀ e, ∃ v, inc e v)
{U : Finset E} (S : ↥(components (inc := inc) U)) : V :=
(component_exists_vertex hinc S.property).choose
lemma component_exchange_compatible {M N S : Finset E}
(hS : S ∈ components (inc := inc) (M ∪ N)) : ExchangeCompatible (inc := inc) M N S := by
obtain ⟨a,_,rfl⟩ := mem_components.mp hS
exact component_compatible M N a
namespace IndexedCycle
variable (c : IndexedCycle inc)
noncomputable def edgeSet : Finset E := Finset.univ.image c.edge
lemma mem_edgeSet (e : E) : e ∈ c.edgeSet ↔ ∃ i, i < c.size ∧ c.edgeAt i = e := by
simp only [edgeSet, Finset.mem_image, Finset.mem_univ, true_and]
constructor
· rintro ⟨i,rfl⟩
exact ⟨i.val,i.isLt,by simp [edgeAt,index,Nat.mod_eq_of_lt i.isLt]⟩
· rintro ⟨i,hi,rfl⟩
exact ⟨c.index i,rfl⟩
end IndexedCycle
end
variable {V E : Type*} [DecidableEq V] [DecidableEq E]
variable {inc : E → V → Prop}
namespace CellPaths
variable (c : CellPaths inc)
def conversionPieces (b : Bool) (S : Finset (Fin 4)) (i : Fin 4) : Finset E :=
if i ∈ S then (c.side i).closed (c.chord i) else c.orientationPieces b i
def converted (b : Bool) (S : Finset (Fin 4)) : Finset E :=
assemble (c.conversionPieces b S)
def canonicalGain (R : Finset E) (f : Finset E → ℝ) (b : Bool) (i : Fin 4) : ℝ :=
f (R ∪ c.orientation b) - f (R ∪ c.contextOne b i)
def contextError (R : Finset E) (f : Finset E → ℝ) (b : Bool) (X Y : Fin 4) : ℝ :=
(f (R ∪ c.contextOne b Y) -
f (R ∪ ((c.contextOne b Y \ (c.side X).through) ∪ (c.side X).closed (c.chord X)))) -
(f (R ∪ c.orientation b) - f (R ∪ c.contextOne b X))
end CellPaths
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Sewn
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V E : Type*}
variable {inc : E → V → Prop}
namespace IndexedCycle
variable (c : IndexedCycle inc)
variable [DecidableEq E]
def sewn (x y : ℕ) (e : E) : Finset E :=
(c.intervalPattern x y (1-x%2) ∪ c.intervalPattern y (x+c.size) (x%2)) ∪ {e}
end IndexedCycle
end
variable {V E : Type*} [DecidableEq E]
variable {inc : E → V → Prop}
namespace IndexedCycle
variable (c : IndexedCycle inc)
def signedGain (R : Finset E) (f : Finset E → ℝ) (x y : ℕ) (e : E) : ℝ :=
if x%2=0 then f (R ∪ c.parityPattern 0) - f (R ∪ c.sewn x y e)
else f (R ∪ c.sewn x y e) - f (R ∪ c.parityPattern 1)
namespace Corners
variable {c} (k : c.Corners)
def cornerSewn (chord : Fin 4 → E) : Fin 4 → Finset E :=
![c.sewn k.a₀ k.a₁ (chord 0), c.sewn k.a₁ k.a₂ (chord 1),
c.sewn k.a₂ k.a₃ (chord 2), c.sewn k.a₀ k.a₃ (chord 3)]
variable [DecidableEq V]
def signedLocalTerm (chord : Fin 4 → E)
(hc : ∀ i v, inc (chord i) v ↔
v = (k.side i).vertex 0 ∨ v = (k.side i).vertex (k.side i).length)
(R : Finset E) (f : Finset E → ℝ) : ℝ :=
let P := k.cellPaths chord hc
let t := (f (R ∪ P.switched true) - f (R ∪ P.switched false)) +
P.contextError R f true 2 0 - P.contextError R f false 3 1
if k.a₀%2=0 then t else -t
end Corners
end IndexedCycle
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Cycle
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V E : Type*} [Fintype V] [DecidableEq V] [DecidableEq E]
variable {inc : E → V → Prop}
abbrev PatternCode (inc : E → V → Prop) :=
{s : Finset E × Finset E // ∃ c : IndexedCycle inc,
c.parityPattern 0 = s.1 ∧ c.parityPattern 1 = s.2}
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Through
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V E : Type*} [Fintype V] [DecidableEq V] [DecidableEq E]
variable {inc : E → V → Prop}
namespace PatternCode
variable (x : PatternCode inc)
def through : Finset E := x.val.1
def closed : Finset E := x.val.2
def total : Finset E := x.through ∪ x.closed
variable [Fintype E]
noncomputable instance instFintype : Fintype (PatternCode inc) := Fintype.ofFinite _
end PatternCode
end MatchingFPRAS.Transport
namespace MatchingFPRAS.PairEnergy
open scoped BigOperators
structure Law (Ω : Type*) [Fintype Ω] where
weight : Ω → ℝ
nonneg : ∀ x, 0 ≤ weight x
total : ∑ x, weight x = 1
variable {ι Ω Δ : Type*} [Fintype ι] [Fintype Ω] [Fintype Δ]
noncomputable def guideMass (π : Law Ω) (closed : ι → Finset Ω) (X : ι) : ℝ :=
∑ B ∈ closed X, π.weight B
noncomputable def guideMean (π : Law Ω) (closed : ι → Finset Ω)
(derivative : ι → Ω → ℝ) (X : ι) : ℝ :=
(∑ B ∈ closed X, π.weight B * derivative X B) / guideMass π closed X
noncomputable def contextMass (ρ : Δ → ℝ) (arc : Δ → ι) (context : Δ → Ω)
(X : ι) (A : Ω) : ℝ := by
classical
exact ∑ d with arc d = X ∧ context d = A, ρ d
noncomputable def swapSum (π : Law Ω) (through closed : ι → Finset Ω)
(d₁ d₂ : ι → Ω → ℝ) : ℝ :=
∑ X, ∑ A ∈ through X, ∑ B ∈ closed X,
π.weight A * π.weight B * (d₁ X A - d₂ X B) ^ 2
end MatchingFPRAS.PairEnergy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_SafeSwitch
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable {inc : E → V → Prop}
namespace CellPaths
variable (c : CellPaths inc)
def commonInterior : Finset E := assemble fun i => (c.side i).interior
end CellPaths
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Underlying
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
variable {V E : Type*} [Fintype V] [DecidableEq V] [DecidableEq E]
namespace Overlay
variable (ends : E → Sym2 V) (hloop : ∀ e, ¬ (ends e).IsDiag)
def underlying (M : Finset E) : SimpleGraph V where
Adj v w := ∃ e ∈ M, ends e = s(v, w)
symm := ⟨by
rintro v w ⟨e, he, h⟩
exact ⟨e, he, h.trans Sym2.eq_swap⟩⟩
loopless := ⟨by
rintro v ⟨e, he, h⟩
exact hloop e (by rw [h]; simp)⟩
omit [Fintype V] [DecidableEq V] [DecidableEq E] in
lemma exists_partner {e : E} {v : V} (hv : v ∈ ends e) :
∃ w, ends e = s(v,w) := by
exact hv
open scoped symmDiff
def discrepancy (M N : Finset E) : SimpleGraph V :=
underlying ends hloop M ∆ underlying ends hloop N
omit [Fintype V] [DecidableEq V] [DecidableEq E] in
lemma discrepancy_adj_iff [Fintype V] [DecidableEq V] [DecidableEq E] (M N : Finset E) (v w : V) :
(discrepancy ends hloop M N).Adj v w ↔
((underlying ends hloop M).Adj v w ∧ ¬ (underlying ends hloop N).Adj v w) ∨
((underlying ends hloop N).Adj v w ∧ ¬ (underlying ends hloop M).Adj v w) := by
rfl
omit [Fintype V] [DecidableEq V] in
lemma alternating_cycle_parity [Fintype V] [DecidableEq V] {G H : SimpleGraph V} {v : V}
(p : G.Walk v v) (hp : p.IsCycle) (halt : G.IsAlternating H) :
p.length % 2 = 0 := by
let Q : ℕ → Prop := fun i => H.Adj (p.getVert i) (p.getVert (i + 1))
have recur : ∀ i, i + 1 < p.length → (Q (i + 1) ↔ ¬ Q i) := by
intro i hi
have hn : p.getVert i ≠ p.getVert (i + 2) := by
simpa using hp.getVert_sub_one_ne_getVert_add_one (i := i + 1) (by omega)
have h := halt hn (p.adj_getVert_succ (i := i) (by omega)).symm
(p.adj_getVert_succ (i := i + 1) hi)
dsimp [Q]
have hsym := H.adj_comm (u := p.getVert (i + 1)) (v := p.getVert i)
tauto
have parity : ∀ i, i < p.length →
(Q i ↔ if i % 2 = 0 then Q 0 else ¬ Q 0) := by
intro i
induction i with
| zero => simp
| succ i ih =>
intro hi
rw [recur i hi, ih (by omega)]
split_ifs <;> first | omega | tauto
have hn : p.getVert 1 ≠ p.getVert (p.length - 1) := by
simpa [SimpleGraph.Walk.snd, SimpleGraph.Walk.penultimate] using hp.snd_ne_penultimate
have hfirst := p.adj_getVert_succ (i := 0) (by have := hp.three_le_length; omega)
have hlast := p.adj_getVert_succ (i := p.length - 1) (by have := hp.three_le_length; omega)
have he : p.length - 1 + 1 = p.length := by have := hp.three_le_length; omega
have hclose : Q 0 ↔ ¬ Q (p.length - 1) := by
have h := halt hn (by simpa using hfirst) (by simpa [he] using hlast.symm)
simpa [Q, he, H.adj_comm] using h
have hr := parity (p.length - 1) (by have := hp.three_le_length; omega)
split_ifs at hr
· tauto
· have := hp.three_le_length
omega
def cyclicVertex {G : SimpleGraph V} {v : V} (p : G.Walk v v) (i : ℕ) : V :=
p.getVert (i % p.length)
omit [Fintype V] [DecidableEq V] in
lemma cyclicVertex_injOn [Fintype V] [DecidableEq V] {G : SimpleGraph V} {v : V} (p : G.Walk v v)
(hp : p.IsCycle) : Set.InjOn (cyclicVertex p) (Set.Ico 0 p.length) := by
intro i hi j hj h
have hi' := hi.2
have hj' := hj.2
simp only [cyclicVertex, Nat.mod_eq_of_lt hi', Nat.mod_eq_of_lt hj'] at h
exact hp.getVert_injOn' (by change i ≤ p.length - 1; omega)
(by change j ≤ p.length - 1; omega) h
omit [Fintype V] [DecidableEq V] in
lemma cyclicVertex_next [Fintype V] [DecidableEq V] {G : SimpleGraph V} {v : V} (p : G.Walk v v)
(i : ℕ) (hi : i < p.length) : cyclicVertex p (i + 1) = p.getVert (i + 1) := by
by_cases h : i + 1 < p.length
· simp [cyclicVertex, Nat.mod_eq_of_lt h]
· have he : i + 1 = p.length := by omega
simp [he, cyclicVertex]
lemma cyclicVertex_adj {G : SimpleGraph V} {v : V} (p : G.Walk v v)
(hp : p.IsCycle) (i : ℕ) : G.Adj (cyclicVertex p i) (cyclicVertex p (i + 1)) := by
have hm : i % p.length < p.length := Nat.mod_lt i (by have := hp.three_le_length; omega)
have he : cyclicVertex p (i + 1) = cyclicVertex p (i % p.length + 1) := by
simp only [cyclicVertex, Nat.add_mod, Nat.mod_mod]
rw [he, cyclicVertex_next p _ hm]
exact p.adj_getVert_succ hm
end Overlay
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_ComponentOrder
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V E : Type*} [Fintype V] [DecidableEq V] [DecidableEq E]
variable {inc : E → V → Prop}
noncomputable def componentOrder (U : Finset E) :
Fin (components (inc := inc) U).card ≃ ↥(components (inc := inc) U) :=
(Fintype.equivFinOfCardEq (Fintype.card_coe _)).symm
noncomputable def componentPrefix (U : Finset E) (i : ℕ) : Finset E := by
classical
exact (Finset.univ.filter (fun j : Fin (components (inc := inc) U).card => j.val < i)).biUnion
(fun j => (componentOrder (inc := inc) U j).val)
omit [Fintype V] [DecidableEq V] in
lemma mem_componentPrefix (U : Finset E) (i : ℕ) (e : E) :
e ∈ componentPrefix (inc := inc) U i ↔
∃ j : Fin (components (inc := inc) U).card, j.val < i ∧ e ∈ (componentOrder (inc := inc) U j).val := by
classical
simp only [componentPrefix, Finset.mem_biUnion, Finset.mem_filter, Finset.mem_univ,
true_and]
omit [Fintype V] [DecidableEq V] in
lemma componentPrefix_compatible (M N : Finset E) (i : ℕ) :
ExchangeCompatible (inc := inc) M N (componentPrefix (inc := inc) (M ∪ N) i) := by
intro e he f hf v hev hfv
simp only [mem_componentPrefix]
constructor
· rintro ⟨j,hj,he'⟩
exact ⟨j,hj,(component_exchange_compatible (componentOrder (M ∪ N) j).property
e he f hf v hev hfv).mp he'⟩
· rintro ⟨j,hj,hf'⟩
exact ⟨j,hj,(component_exchange_compatible (componentOrder (M ∪ N) j).property
e he f hf v hev hfv).mpr hf'⟩
end
section
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable {inc : E → V → Prop}
noncomputable def componentAt (U : Finset E) (i : ℕ) : Finset E :=
if h : i < (components (inc := inc) U).card then (componentOrder (inc := inc) U ⟨i,h⟩).val else ∅
omit [Fintype V] [DecidableEq V] [Fintype E] in
lemma componentAt_compatible (M N : Finset E) (i : ℕ) :
ExchangeCompatible (inc := inc) M N (componentAt (inc := inc) (M ∪ N) i) := by
classical
unfold componentAt
split_ifs with h
· exact component_exchange_compatible (componentOrder (M ∪ N) ⟨i,h⟩).property
· intro e he f hf v hev hfv
simp
end
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_EndpointPair
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
variable {V L : Type*} [Fintype V] [DecidableEq V] [Fintype L] [DecidableEq L]
variable {bags : V → Finset L} {G : SimpleGraph L}
variable (hbags : ∀ v, ∀ a ∈ bags v, ∀ b ∈ bags v, a = b ∨ G.Adj a b)
variable (hG : G.IsAcyclic)
include hbags hG in
omit [Fintype V] [DecidableEq V] [Fintype L] [DecidableEq L] in
lemma label_memberships_le_two (v : V) : (bags v).card ≤ 2 := by
by_contra h
have hc : G.IsNClique ((bags v).card) (bags v) := by
constructor
· intro a ha b hb hab
exact (hbags v a ha b hb).resolve_left hab
· rfl
exact hc.not_cliqueFree (hG.cliqueFree (by omega))
end
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable {inc : E → V → Prop}
noncomputable def cycleSquare (f g : Finset E → ℝ) (A B : Finset E) (S : Finset E) : ℝ :=
((f A+g B)-(f (exchange A B S)+g (exchange B A S)))^2
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Probability_Variance
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FiniteVariance
variable {Ω : Type*} [Fintype Ω]
noncomputable def variance (π f : Ω → ℝ) : ℝ :=
∑ x, π x * (f x - ∑ y, π y * f y)^2
end MatchingFPRAS.FiniteVariance
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Arithmetic_ArithmeticSize
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.StackComposition
open Turing MachineCost
variable {K Λ P σ : Type*} {Γ : K → Type*} [DecidableEq K]
variable [Inhabited Λ] [Inhabited P]
omit [DecidableEq K] in
lemma supports_univ [Fintype Λ] (M : Λ → TM2.Stmt Γ Λ σ) : TM2.Supports M Finset.univ := by
constructor
· simp
· intro l _
induction M l with
| push k a q ih | peek k a q ih | pop k a q ih | load a q ih => exact ih
| branch p q r ihq ihr => exact ⟨ihq,ihr⟩
| goto l => simp [TM2.SupportsStmt]
| halt => trivial
open Turing MachineCost
end MatchingFPRAS.StackComposition
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_ThresholdGraph
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Switching
open Finset
variable {V : Type*}
inductive ChargeTrace [DecidableEq V] (B : V → V → ℝ) :
Finset V → Finset V → ℝ → Prop
| done (U) : ChargeTrace B U U 1
| remove (U W : Finset V) (j k : V) (hj : j ∈ U) (hk : k ∈ U) (hjk : j ≠ k)
(Tj Tk f F : ℝ) (hj0 : 0 < Tj) (hk0 : 0 < Tk) (hf0 : 0 ≤ f) (hF0 : 0 ≤ F)
(hTj : ∀ a, a ≠ j → B j a ≤ Tj) (hTk : ∀ a, a ≠ k → B k a ≤ Tk)
(hf : f*Tj*Tk ≤ B j k) (next : ChargeTrace B (U \ {j,k}) W F) :
ChargeTrace B U W (f*F)
| replace (U W : Finset V) (j u : V) (hj : j ∈ U) (hu : u ∉ U)
(T f F : ℝ) (hT0 : 0 < T) (hf0 : 0 ≤ f) (hF0 : 0 ≤ F)
(hT : ∀ a, a ≠ j → B j a ≤ T) (hf : f*T ≤ B j u)
(next : ChargeTrace B (insert u (U.erase j)) W F) :
ChargeTrace B U W (f*F)
def pairVertices (xs : List (V × V)) : List V := xs.flatMap (fun q => [q.1,q.2])
end MatchingFPRAS.Switching
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_SumLiftMate
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Subdivision
open Finset
def wordWeight (a : Bool) : List ℝ → ℝ
| [] => 1
| x::xs => (if a then x else 1) * wordWeight (!a) xs
@[simp] theorem wordWeight_nil (a : Bool) : wordWeight a [] = 1 := rfl
@[simp] theorem wordWeight_pair (a : Bool) (x : ℝ) (xs : List ℝ) :
wordWeight a (x::x::xs) = x * wordWeight a xs := by
cases a <;> simp [wordWeight]
end MatchingFPRAS.Subdivision
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_HoleBlocks
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Subdivision
open Finset
noncomputable def vertexPotential (p : ℕ) (B Hu Hv lam : ℝ) (k : ℕ) : ℝ :=
if k ≤ 2*p then
if Even k then 1 else max B (Hu/2^(k/2))
else if Even k then max B (Hv/2^((4*p+1-k)/2))/lam else lam
@[simp] lemma vertexPotential_zero (p : ℕ) (B Hu Hv lam : ℝ) :
vertexPotential p B Hu Hv lam 0 = 1 := by simp [vertexPotential]
@[simp] lemma vertexPotential_last (p : ℕ) (B Hu Hv lam : ℝ) :
vertexPotential p B Hu Hv lam (4*p+1) = lam := by
have hn : ¬ Even (4*p+1) := by simp [Nat.even_iff]; omega
simp [vertexPotential,show ¬ 4*p+1 ≤ 2*p by omega,hn]
end MatchingFPRAS.Subdivision
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Related
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Hierarchy
theorem acyclic_of_unique_lower {L : Type*} (G : SimpleGraph L) (rank : L → ℕ)
(hdiff : ∀ {a b}, G.Adj a b → rank a ≠ rank b)
(hparent : ∀ a b c, G.Adj a b → G.Adj a c → rank b < rank a → rank c < rank a → b=c) :
G.IsAcyclic := by
classical
intro a p hp
obtain ⟨b,hb,hmax⟩ := p.support.toFinset.exists_max_image rank
⟨a,by simp⟩
have hb' : b ∈ p.support := List.mem_toFinset.mp hb
let q := p.rotate b hb'
have hq : q.IsCycle := hp.rotate hb'
have hqs : q.snd ∈ p.support := (p.mem_support_rotate_iff b hb').mp (q.getVert_mem_support 1)
have hqt : q.penultimate ∈ p.support :=
(p.mem_support_rotate_iff b hb').mp (q.getVert_mem_support (q.length-1))
have hs : rank q.snd < rank b := lt_of_le_of_ne
(hmax q.snd (List.mem_toFinset.mpr hqs)) (hdiff (q.adj_snd hq.not_nil)).symm
have ht : rank q.penultimate < rank b := lt_of_le_of_ne
(hmax q.penultimate (List.mem_toFinset.mpr hqt)) (hdiff (q.adj_penultimate hq.not_nil))
exact hq.snd_ne_penultimate (hparent b q.snd q.penultimate (q.adj_snd hq.not_nil)
(q.adj_penultimate hq.not_nil).symm hs ht)
end MatchingFPRAS.Hierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_EdgeLow
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
open Finset MatchingFPRAS.Switching
variable {V E : Type*} [Fintype V] [LinearOrder V]
variable (edge : E → Sym2 V) (hnd : ∀ e, ¬(edge e).IsDiag)
noncomputable def edgeLow (s : Sym2 V) : V := Sym2.lift ⟨min,min_comm⟩ s
noncomputable def edgeHigh (s : Sym2 V) : V := Sym2.lift ⟨max,max_comm⟩ s
omit [Fintype V] in
@[simp] lemma edgeLow_mk (x y : V) : edgeLow s(x,y)=min x y := rfl
omit [Fintype V] in
@[simp] lemma edgeHigh_mk (x y : V) : edgeHigh s(x,y)=max x y := rfl
omit [Fintype V] in
lemma edgeLow_mem (s : Sym2 V) : edgeLow s ∈ s := by
induction s using Sym2.inductionOn with
| hf x y => by_cases h : x≤y <;> simp [min_def,h]
omit [Fintype V] in
lemma edge_low_high (s : Sym2 V) : s(edgeLow s,edgeHigh s)=s := by
induction s using Sym2.inductionOn with
| hf x y => by_cases h : x≤y <;> simp [min_def,max_def,h,Sym2.eq_swap]
omit [Fintype V] in
lemma edgeLow_lt_high (s : Sym2 V) (hs : ¬s.IsDiag) : edgeLow s < edgeHigh s := by
induction s using Sym2.inductionOn with
| hf x y =>
have hxy : x ≠ y := by simpa using hs
rcases hxy.lt_or_gt with h | h <;> simp [h.le,h]
end
open Finset MatchingFPRAS.Switching
variable {V L : Type*} [Fintype V] [Fintype L] [LinearOrder V] [DecidableEq L]
variable (bags : V → Finset L)
def inflationScale (D₀ : ℝ) : ℝ := 100*(Fintype.card V : ℝ)^2*D₀
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Density
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω]
noncomputable def density (p : I → Ω → ℝ) (s : I → Ω) : ℝ := ∏ i, p i (s i)
noncomputable def dot (p : I → Ω → ℝ) (f g : (I → Ω) → ℝ) : ℝ :=
∑ s, density p s * f s * g s
noncomputable def average (p : I → Ω → ℝ) (i : I) :
(((I → Ω) → ℝ) →ₗ[ℝ] ((I → Ω) → ℝ)) where
toFun f s := ∑ a, p i a * f (Function.update s i a)
map_add' f g := by funext s; simp [mul_add, Finset.sum_add_distrib]
map_smul' c f := by funext s; simp [Finset.mul_sum,mul_left_comm]
omit [Fintype I] in
lemma average_apply (p : I → Ω → ℝ) (i : I) (f : (I → Ω) → ℝ) (s : I → Ω) :
average p i f s = ∑ a, p i a * f (Function.update s i a) := rfl
omit [Fintype I] in
lemma average_idem (p : I → Ω → ℝ) (hp : ∀ i, ∑ a, p i a = 1) (i : I)
(f : (I → Ω) → ℝ) : average p i (average p i f) = average p i f := by
funext s
simp only [average_apply, Function.update_idem]
rw [← Finset.sum_mul, hp i, one_mul]
omit [Fintype I] in
lemma average_comm (p : I → Ω → ℝ) (i j : I) (f : (I → Ω) → ℝ) :
average p i (average p j f) = average p j (average p i f) := by
classical
by_cases h : i = j
· subst j; rfl
funext s
simp only [average_apply, Finset.mul_sum]
rw [Finset.sum_comm]
apply Finset.sum_congr rfl
intro b _
apply Finset.sum_congr rfl
intro a _
rw [Function.update_comm h]
ring
noncomputable def swapDraw (i : I) : ((I → Ω) × Ω) ≃ ((I → Ω) × Ω) where
toFun z := (Function.update z.1 i z.2, z.1 i)
invFun z := (Function.update z.1 i z.2, z.1 i)
left_inv z := by simp [Function.update_idem]
right_inv z := by simp [Function.update_idem]
omit [Fintype Ω] in
lemma density_swap (p : I → Ω → ℝ) (i : I) (s : I → Ω) (a : Ω) :
density p s * p i a = density p (Function.update s i a) * p i (s i) := by
classical
unfold density
rw [← Finset.mul_prod_erase _ _ (Finset.mem_univ i),
← Finset.mul_prod_erase _ _ (Finset.mem_univ i)]
simp only [Function.update_self]
have he : (∏ j ∈ Finset.univ.erase i, p j (Function.update s i a j)) =
∏ j ∈ Finset.univ.erase i, p j (s j) := by
apply Finset.prod_congr rfl
intro j hj
rw [Function.update_of_ne (Finset.ne_of_mem_erase hj)]
rw [he]
ring
lemma average_adjoint (p : I → Ω → ℝ) (i : I) (f g : (I → Ω) → ℝ) :
dot p (average p i f) g = dot p f (average p i g) := by
classical
unfold dot
simp only [average_apply, Finset.mul_sum, Finset.sum_mul]
rw [← Fintype.sum_prod_type', ← Fintype.sum_prod_type']
have h := Equiv.sum_comp (swapDraw (Ω := Ω) i)
(fun z : (I → Ω) × Ω => density p z.1 * f z.1 * (p i z.2 * g (Function.update z.1 i z.2)))
rw [← h]
apply Finset.sum_congr rfl
intro z _
simp only [swapDraw, Equiv.coe_fn_mk, Function.update_idem,
Function.update_eq_self]
have hz := density_swap p i z.1 z.2
nlinarith [congrArg (fun t : ℝ => t * f (Function.update z.1 i z.2) * g z.1) hz]
variable (p : I → Ω → ℝ)
lemma dot_sub_left (f g h : (I → Ω) → ℝ) :
dot p (f-g) h = dot p f h - dot p g h := by
simp [dot, mul_sub, sub_mul, Finset.sum_sub_distrib]
lemma dot_sub_right (f g h : (I → Ω) → ℝ) :
dot p f (g-h) = dot p f g - dot p f h := by
simp [dot, mul_sub, Finset.sum_sub_distrib]
structure Projection where
op : (((I → Ω) → ℝ) →ₗ[ℝ] ((I → Ω) → ℝ))
idem : ∀ f, op (op f) = op f
adj : ∀ f g, dot p (op f) g = dot p f (op g)
namespace Projection
variable {p}
noncomputable def complement (P : Projection p) : Projection p where
op := LinearMap.id - P.op
idem f := by
change f-P.op f-P.op (f-P.op f) = f-P.op f
rw [map_sub, P.idem]
abel
adj f g := by
change dot p (f-P.op f) g = dot p f (g-P.op g)
rw [dot_sub_left, dot_sub_right, P.adj]
noncomputable def comp (P Q : Projection p)
(hc : ∀ f, P.op (Q.op f) = Q.op (P.op f)) : Projection p where
op := P.op.comp Q.op
idem f := by
change P.op (Q.op (P.op (Q.op f))) = P.op (Q.op f)
rw [← hc, Q.idem, P.idem]
adj f g := by
change dot p (P.op (Q.op f)) g = dot p f (P.op (Q.op g))
rw [P.adj, Q.adj, hc]
end Projection
noncomputable def avgProjection (hp : ∀ i, ∑ a, p i a = 1) (i : I) : Projection p where
op := average p i
idem := average_idem p hp i
adj := average_adjoint p i
noncomputable def avgList : List I → (((I → Ω) → ℝ) →ₗ[ℝ] ((I → Ω) → ℝ))
| [] => LinearMap.id
| i::l => (average p i).comp (avgList l)
omit [Fintype I] in
lemma avgList_cons (i : I) (l : List I) (f : (I → Ω) → ℝ) :
avgList p (i::l) f = average p i (avgList p l f) := rfl
omit [Fintype I] in
lemma average_comm_list (i : I) (l : List I) (f : (I → Ω) → ℝ) :
average p i (avgList p l f) = avgList p l (average p i f) := by
induction l with
| nil => rfl
| cons j l ih =>
rw [avgList_cons, average_comm, ih, avgList_cons]
omit [Fintype I] in
lemma avgList_idem (hp : ∀ i, ∑ a, p i a = 1) (l : List I) (f : (I → Ω) → ℝ) :
avgList p l (avgList p l f) = avgList p l f := by
induction l with
| nil => rfl
| cons i l ih =>
simp only [avgList_cons]
rw [← average_comm_list, ih, average_idem p hp]
lemma avgList_adjoint (l : List I) (f g : (I → Ω) → ℝ) :
dot p (avgList p l f) g = dot p f (avgList p l g) := by
induction l generalizing g with
| nil => rfl
| cons i l ih =>
rw [avgList_cons, average_adjoint, ih, ← average_comm_list, avgList_cons]
noncomputable def listProjection (hp : ∀ i, ∑ a, p i a = 1) (l : List I) : Projection p where
op := avgList p l
idem := avgList_idem p hp l
adj := avgList_adjoint p l
end
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [LinearOrder I]
[Fintype Ω]
variable (p : I → Ω → ℝ)
noncomputable def outside (x y : I) : List I :=
(Finset.univ.filter (fun i => x < i ∧ i ≠ y)).toList
noncomputable def pairCondition (x y : I) :
(((I → Ω) → ℝ) →ₗ[ℝ] ((I → Ω) → ℝ)) := avgList p (outside x y)
noncomputable def residual (x y : I) :
(((I → Ω) → ℝ) →ₗ[ℝ] ((I → Ω) → ℝ)) :=
(LinearMap.id-average p x).comp
((LinearMap.id-average p y).comp (pairCondition p x y))
end
open Finset
end MatchingFPRAS.Replica
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Probability_Mean
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω]
variable (p : I → Ω → ℝ)
noncomputable def mean (f : (I → Ω) → ℝ) : ℝ := ∑ s, density p s*f s
noncomputable def variance (f : (I → Ω) → ℝ) : ℝ :=
dot p (f-(fun _ => mean p f)) (f-(fun _ => mean p f))
end
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [LinearOrder I]
[Fintype Ω]
variable (p : I → Ω → ℝ)
noncomputable def future (S : Finset I) (x : I) := avgList p ((S.filter (x < ·)).toList)
noncomputable def increment (S : Finset I) (x : I) (f : (I → Ω) → ℝ) : (I → Ω) → ℝ :=
future p S x f-average p x (future p S x f)
end
section
open Finset
variable {Ω A : Type*} [Fintype Ω] [Fintype A]
noncomputable def localEnergy (q : Ω → Ω → ℝ) (f : Ω → ℝ) : ℝ :=
(∑ a, ∑ b, q a b * (f a-f b)^2)/2
end
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω]
variable (p : I → Ω → ℝ)
structure PairCapacity (x y : I) where
q : (Ω × Ω) → (Ω × Ω) → ℝ
nonneg : ∀ a b, 0 ≤ q a b
row : ∀ a, ∑ b, q a b = p x a.1*p y a.2
col : ∀ b, ∑ a, q a b = p x b.1*p y b.2
def replacePair (x y : I) (s : I → Ω) (a : Ω × Ω) : I → Ω :=
Function.update (Function.update s x a.1) y a.2
def slice (x y : I) (f : (I → Ω) → ℝ) (s : I → Ω) (a : Ω × Ω) : ℝ :=
f (replacePair x y s a)
noncomputable def pairEnergy (x y : I) (Q : PairCapacity p x y) (f : (I → Ω) → ℝ) : ℝ :=
mean p (fun s => localEnergy Q.q (slice x y f s))
end MatchingFPRAS.Replica
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TierClamp
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
noncomputable def tierClamp (c : ℝ) (t : ℕ) (w : ℝ) : ℝ :=
max (c^t)⁻¹ (min (c^t) w)
lemma tierClamp_pos {c : ℝ} (hc : 0 < c) (t : ℕ) (w : ℝ) : 0 < tierClamp c t w :=
lt_of_lt_of_le (inv_pos.mpr (pow_pos hc t)) (le_max_left _ _)
end
section
open Finset
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable {inc : E → V → Prop}
omit [Fintype E] in
lemma exchange_inter (M N S : Finset E) :
exchange M N S ∩ exchange N M S = M ∩ N := by
ext e
simp only [Finset.mem_inter,mem_exchange]
tauto
end
open Finset
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_RelationDestinations
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
section
open Finset
variable {Ω : Type*} [Fintype Ω] [DecidableEq Ω]
noncomputable def relationDestinations (R : Ω → Ω → Prop) (a : Ω) : Finset Ω := by
classical
exact Finset.univ.filter (fun b => a ≠ b ∧ R a b)
noncomputable def relationOff (R : Ω → Ω → Prop) (d : ℕ) (a b : Ω) : ℝ := by
classical
exact if b ∈ relationDestinations R a then (d:ℝ)⁻¹ else 0
noncomputable def relationProposal (R : Ω → Ω → Prop) (d : ℕ) (a b : Ω) : ℝ := by
classical
exact if a = b then 1-∑ z, relationOff R d a z else relationOff R d a b
lemma relationOff_self (R : Ω → Ω → Prop) (d : ℕ) (a : Ω) : relationOff R d a a = 0 := by
classical
simp [relationOff,relationDestinations]
lemma relationOff_nonneg (R : Ω → Ω → Prop) (d : ℕ) (a b : Ω) : 0 ≤ relationOff R d a b := by
classical
unfold relationOff; split_ifs <;> positivity
lemma relationOff_sum (R : Ω → Ω → Prop) (d : ℕ) (a : Ω) :
(∑ b, relationOff R d a b) = (relationDestinations R a).card / (d:ℝ) := by
classical
unfold relationOff
rw [← Finset.sum_filter]
simp [div_eq_mul_inv]
lemma relationOff_sum_le_one (R : Ω → Ω → Prop) (d : ℕ) (a : Ω)
(hd : (relationDestinations R a).card ≤ d) : (∑ b, relationOff R d a b) ≤ 1 := by
rw [relationOff_sum]
by_cases h : d = 0
· simp [h]
· apply (div_le_one (by positivity)).mpr
exact_mod_cast hd
lemma relationProposal_nonneg (R : Ω → Ω → Prop) (d : ℕ)
(hd : ∀ a, (relationDestinations R a).card ≤ d) (a b : Ω) : 0 ≤ relationProposal R d a b := by
classical
unfold relationProposal; split_ifs
· exact sub_nonneg.mpr (relationOff_sum_le_one R d a (hd a))
· exact relationOff_nonneg _ _ _ _
lemma relationProposal_symmetric (R : Ω → Ω → Prop) (d : ℕ)
(hR : ∀ a b, R a b ↔ R b a) (a b : Ω) : relationProposal R d a b = relationProposal R d b a := by
classical
by_cases h : a = b
· subst b; rfl
· simp [relationProposal,h,Ne.symm h,relationOff,relationDestinations,hR a b]
end
section
open Finset
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable {inc : E → V → Prop}
variable (ends : E → Sym2 V)
noncomputable def edgeEndpoints (e : E) : V × V :=
Classical.choose (show ∃ p : V × V, ends e = s(p.1,p.2) from
Sym2.inductionOn (ends e) (fun a b => ⟨(a,b),rfl⟩))
omit [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E] in
lemma edgeEndpoints_spec (e : E) : ends e = s((edgeEndpoints ends e).1,(edgeEndpoints ends e).2) :=
Classical.choose_spec (show ∃ p : V × V, ends e = s(p.1,p.2) from
Sym2.inductionOn (ends e) (fun a b => ⟨(a,b),rfl⟩))
noncomputable def pairRep (I : Finset E) (h : I.card = 2) : E × E :=
Classical.choose (show ∃ p : E × E, p.1 ≠ p.2 ∧ I = {p.1,p.2} from by
obtain ⟨a,b,hab,he⟩ := Finset.card_eq_two.mp h
exact ⟨(a,b),hab,he⟩)
omit [Fintype E] in
lemma pairRep_spec (I : Finset E) (h : I.card = 2) :
(pairRep I h).1 ≠ (pairRep I h).2 ∧ I = {(pairRep I h).1,(pairRep I h).2} :=
Classical.choose_spec (show ∃ p : E × E, p.1 ≠ p.2 ∧ I = {p.1,p.2} from by
obtain ⟨a,b,hab,he⟩ := Finset.card_eq_two.mp h
exact ⟨(a,b),hab,he⟩)
noncomputable def withEnds (a b : V) : Finset E := by
classical
exact Finset.univ.filter (fun e => ends e = s(a,b))
omit [Fintype V] [DecidableEq E] in
lemma mem_withEnds (a b : V) (e : E) : e ∈ withEnds ends a b ↔ ends e = s(a,b) := by
classical
simp [withEnds]
omit [Fintype V] [DecidableEq E] in
lemma withEnds_card_le (hpar : ∀ e, (Finset.univ.filter (fun f => ends f = ends e)).card ≤ 2)
(a b : V) : (withEnds ends a b).card ≤ 2 := by
classical
by_cases h : (withEnds ends a b).Nonempty
· obtain ⟨e,he⟩ := h
have hh : withEnds ends a b = Finset.univ.filter (fun f => ends f = ends e) := by
unfold withEnds
rw [(mem_withEnds ends a b e).mp he]
rw [hh]; exact hpar e
· simp [Finset.not_nonempty_iff_eq_empty.mp h]
noncomputable def edgePairOptions (R : Finset E) (a b c d : V) : Finset (Finset E) := by
classical
exact (withEnds ends a b).biUnion fun e =>
(withEnds ends c d).image fun f => R ∪ {e,f}
omit [Fintype V] in
lemma mem_edgePairOptions (R : Finset E) (a b c d : V) (e f : E)
(he : ends e = s(a,b)) (hf : ends f = s(c,d)) :
R ∪ {e,f} ∈ edgePairOptions ends R a b c d := by
classical
exact Finset.mem_biUnion.mpr ⟨e,(mem_withEnds ends a b e).mpr he,
Finset.mem_image.mpr ⟨f,(mem_withEnds ends c d f).mpr hf,rfl⟩⟩
omit [Fintype V] in
lemma edgePairOptions_card_le
(hpar : ∀ e, (Finset.univ.filter (fun f => ends f = ends e)).card ≤ 2)
(R : Finset E) (a b c d : V) : (edgePairOptions ends R a b c d).card ≤ 4 := by
classical
calc
_ ≤ ∑ e ∈ withEnds ends a b, ((withEnds ends c d).image (fun f => R ∪ {e,f})).card := Finset.card_biUnion_le
_ ≤ ∑ e ∈ withEnds ends a b, 2 := Finset.sum_le_sum (fun _ _ =>
Finset.card_image_le.trans (withEnds_card_le ends hpar c d))
_ ≤ 4 := by simp only [Finset.sum_const,smul_eq_mul]; have := withEnds_card_le ends hpar a b; omega
noncomputable def switchOptions (A : Finset E) (I : Finset E) : Finset (Finset E) := by
classical
exact if h : I.card = 2 then
let p := pairRep I h
let u := edgeEndpoints ends p.1
let v := edgeEndpoints ends p.2
edgePairOptions ends (A\I) u.1 v.1 u.2 v.2 ∪
edgePairOptions ends (A\I) u.1 v.2 u.2 v.1
else ∅
omit [Fintype V] in
lemma switchOptions_card_le
(hpar : ∀ e, (Finset.univ.filter (fun f => ends f = ends e)).card ≤ 2)
(A I : Finset E) : (switchOptions ends A I).card ≤ 8 := by
classical
unfold switchOptions
split_ifs with h
· exact (Finset.card_union_le _ _).trans (Nat.add_le_add
(edgePairOptions_card_le ends hpar _ _ _ _ _) (edgePairOptions_card_le ends hpar _ _ _ _ _))
· simp
end
section
open Finset
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable (ends : E → Sym2 V)
omit [Fintype V] in
lemma mem_pairOptions_of_endpoints (R : Finset E) (p q f g : E) (a b c d : V)
(hp : ends p = s(a,b)) (hq : ends q = s(c,d))
(hf : ends f = s(b,c)) (hg : ends g = s(d,a)) :
R ∪ {f,g} ∈
edgePairOptions ends R (edgeEndpoints ends p).1 (edgeEndpoints ends q).1
(edgeEndpoints ends p).2 (edgeEndpoints ends q).2 ∪
edgePairOptions ends R (edgeEndpoints ends p).1 (edgeEndpoints ends q).2
(edgeEndpoints ends p).2 (edgeEndpoints ends q).1 := by
classical
have hu := Sym2.eq_iff.mp ((edgeEndpoints_spec ends p).symm.trans hp)
have hv := Sym2.eq_iff.mp ((edgeEndpoints_spec ends q).symm.trans hq)
rcases hu with ⟨h1,h2⟩ | ⟨h1,h2⟩ <;> rcases hv with ⟨h3,h4⟩ | ⟨h3,h4⟩
· rw [h1,h2,h3,h4]
apply Finset.mem_union_right
rw [Finset.pair_comm f g]
exact mem_edgePairOptions ends R a d b c g f (hg.trans (Sym2.eq_swap)) hf
· rw [h1,h2,h3,h4]
apply Finset.mem_union_left
rw [Finset.pair_comm f g]
exact mem_edgePairOptions ends R a d b c g f (hg.trans (Sym2.eq_swap)) hf
· rw [h1,h2,h3,h4]
apply Finset.mem_union_left
exact mem_edgePairOptions ends R b c a d f g hf (hg.trans (Sym2.eq_swap))
· rw [h1,h2,h3,h4]
apply Finset.mem_union_right
exact mem_edgePairOptions ends R b c a d f g hf (hg.trans (Sym2.eq_swap))
omit [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E] in
lemma inc_eq_ends (e : E) (a b : V) (hab : a ≠ b)
(h : ∀ x, x ∈ ends e ↔ x = a ∨ x = b) : ends e = s(a,b) := by
exact (Sym2.mem_and_mem_iff hab).mp ⟨(h a).mpr (Or.inl rfl),(h b).mpr (Or.inr rfl)⟩
end
open Finset
attribute [local instance] Classical.propDecidable
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Probability_LocalVariance
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω] [DecidableEq Ω]
variable (p : I → Ω → ℝ)
noncomputable def localVariance (π : Ω → ℝ) (a : Ω → ℝ) : ℝ :=
∑ u, π u*(a u-∑ v, π v*a v)^2
def PairPoincare (x y : I) (Q : PairCapacity p x y) (C : ℝ) : Prop :=
∀ a b : Ω → ℝ, localVariance (p x) a ≤ C*localEnergy Q.q (fun z => a z.1+b z.2)
noncomputable def baseEnergy (i : I) (f : (I → Ω) → ℝ) : ℝ :=
dot p (f-average p i f) (f-average p i f)
end
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [LinearOrder I]
[Fintype Ω] [DecidableEq Ω]
variable (p : I → Ω → ℝ)
noncomputable def allowed (guides : I → Finset I) : Finset (I × I) :=
Finset.univ.filter (fun z => z.2 ∈ guides z.1)
noncomputable def pairTotal (guides : I → Finset I) (Q : ∀ x y, PairCapacity p x y)
(f : (I → Ω) → ℝ) : ℝ := ∑ x, ∑ y ∈ guides x, pairEnergy p x y (Q x y) f
noncomputable def baseTotal (base : Finset I) (f : (I → Ω) → ℝ) : ℝ :=
∑ x ∈ base, baseEnergy p x f
noncomputable def scanEnergy (guides : I → Finset I) (base : Finset I)
(Q : ∀ x y, PairCapacity p x y) (f : (I → Ω) → ℝ) : ℝ :=
(pairTotal p guides Q f+baseTotal p base f)/(2*((∑ x, (guides x).card)+base.card : ℕ))
end
open Finset
variable {Ω : Type*} [Fintype Ω] [DecidableEq Ω]
structure SymmetricProposal (Ω : Type*) [Fintype Ω] where
q : Ω → Ω → ℝ
nonneg : ∀ a b, 0 ≤ q a b
row : ∀ a, ∑ b, q a b = 1
symmetric : ∀ a b, q a b = q b a
noncomputable def offCapacity (P : SymmetricProposal Ω) (π : Ω → ℝ) (a b : Ω) : ℝ :=
min (π a) (π b)*P.q a b
noncomputable def metropolisCapacity (P : SymmetricProposal Ω) (π : Ω → ℝ) (a b : Ω) : ℝ :=
if a = b then π a - ∑ z ∈ Finset.univ.erase a, offCapacity P π a z
else offCapacity P π a b
omit [DecidableEq Ω] in
lemma offCapacity_nonneg (P : SymmetricProposal Ω) (π : Ω → ℝ)
(hπ : ∀ a, 0 ≤ π a) (a b : Ω) : 0 ≤ offCapacity P π a b :=
mul_nonneg (le_min (hπ a) (hπ b)) (P.nonneg a b)
omit [DecidableEq Ω] in
lemma offCapacity_le (P : SymmetricProposal Ω) (π : Ω → ℝ)
(a b : Ω) : offCapacity P π a b ≤ π a*P.q a b :=
mul_le_mul_of_nonneg_right (min_le_left _ _) (P.nonneg a b)
omit [DecidableEq Ω] in
lemma offCapacity_symmetric (P : SymmetricProposal Ω) (π : Ω → ℝ)
(a b : Ω) : offCapacity P π a b = offCapacity P π b a := by
simp only [offCapacity,min_comm (π a),P.symmetric]
lemma offCapacity_sum_le (P : SymmetricProposal Ω) (π : Ω → ℝ)
(hπ : ∀ a, 0 ≤ π a) (a : Ω) :
(∑ z ∈ Finset.univ.erase a, offCapacity P π a z) ≤ π a := by
calc
_ ≤ ∑ z, offCapacity P π a z := Finset.sum_le_sum_of_subset_of_nonneg
(Finset.erase_subset _ _) (fun z _ _ => offCapacity_nonneg P π hπ a z)
_ ≤ ∑ z, π a*P.q a z := Finset.sum_le_sum (fun z _ => offCapacity_le P π a z)
_ = π a := by rw [← Finset.mul_sum,P.row,mul_one]
lemma metropolisCapacity_nonneg (P : SymmetricProposal Ω) (π : Ω → ℝ)
(hπ : ∀ a, 0 ≤ π a) (a b : Ω) : 0 ≤ metropolisCapacity P π a b := by
unfold metropolisCapacity
split_ifs
· exact sub_nonneg.mpr (offCapacity_sum_le P π hπ a)
· exact offCapacity_nonneg P π hπ a b
noncomputable def metropolis (P : SymmetricProposal Ω) (π : Ω → ℝ) (a b : Ω) : ℝ :=
metropolisCapacity P π a b / π a
end MatchingFPRAS.Replica
namespace MatchingFPRAS.Transport
section
open Finset MatchingFPRAS.Replica
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable (ends : E → Sym2 V)
attribute [local instance] Classical.propDecidable
noncomputable def firstLift {Ω : Type*} [Fintype Ω] (q : Ω → Ω → ℝ)
(a b : Ω × Ω) : ℝ := if a.2 = b.2 then q a.1 b.1 else 0
lemma firstLift_row {Ω : Type*} [Fintype Ω] (q : Ω → Ω → ℝ)
(hq : ∀ a, ∑ b, q a b = 1) (a : Ω × Ω) : (∑ b, firstLift q a b) = 1 := by
classical
simp [Fintype.sum_prod_type,firstLift,hq]
lemma firstLift_symmetric {Ω : Type*} [Fintype Ω] (q : Ω → Ω → ℝ)
(hq : ∀ a b, q a b = q b a) (a b : Ω × Ω) : firstLift q a b = firstLift q b a := by
simp [firstLift,eq_comm,hq a.1 b.1]
end
open Finset MatchingFPRAS.Replica
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_PushedFlow
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica
section
open Finset
variable {R A S : Type*} [Fintype R] [Fintype A] [Fintype S] [DecidableEq S]
noncomputable def pushedFlow (ρ : R → ℝ) (F : R → A → S) (q : A → A → ℝ) (s t : S) : ℝ :=
∑ z : R × (A × A), if (F z.1 z.2.1,F z.1 z.2.2) = (s,t) then ρ z.1*q z.2.1 z.2.2 else 0
end
section
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω] [DecidableEq Ω]
variable (p : I → Ω → ℝ)
noncomputable def pairFlow (x y : I) (Q : PairCapacity p x y) : (I → Ω) → (I → Ω) → ℝ :=
pushedFlow (density p) (replacePair x y) Q.q
noncomputable def baseFlow (i : I) : (I → Ω) → (I → Ω) → ℝ :=
pushedFlow (density p) (fun s a => Function.update s i a) (fun a b => p i a*p i b)
noncomputable def updateCount (guides : I → Finset I) (base : Finset I) : ℕ :=
(∑ x, (guides x).card)+base.card
noncomputable def scanFlow (guides : I → Finset I) (base : Finset I)
(Q : ∀ x y, PairCapacity p x y) (s t : I → Ω) : ℝ :=
(if s=t then density p s else 0)/2+
((∑ x, ∑ y ∈ guides x, pairFlow p x y (Q x y) s t)+
∑ i ∈ base, baseFlow p i s t)/(2*(updateCount guides base:ℝ))
end
open Finset
end MatchingFPRAS.Replica
namespace MatchingFPRAS.FiniteChain
open Finset MatchingFPRAS.Replica
variable {Ω : Type*} [Fintype Ω] [DecidableEq Ω]
noncomputable def sqNorm (π f : Ω → ℝ) : ℝ := ∑ a, π a*(f a)^2
noncomputable def massMean (π f : Ω → ℝ) : ℝ := ∑ a, π a*f a
noncomputable def stepDensity (π : Ω → ℝ) (C : Ω → Ω → ℝ) (f : Ω → ℝ) (b : Ω) : ℝ :=
(∑ a, C a b*f a)/π b
noncomputable def unlazyFlow (π : Ω → ℝ) (C : Ω → Ω → ℝ) (a b : Ω) : ℝ :=
2*C a b-(if a=b then π a else 0)
end MatchingFPRAS.FiniteChain
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreePairProposal
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica.Ladder
open Finset
abbrev Slot (T q : ℕ) := Lex (Fin (T+1) × Fin q)
def rank {T q : ℕ} (x : Slot T q) : ℕ := (ofLex x).1.val
def tier {T q : ℕ} (x : Slot T q) : ℕ := T-rank x
def base (T q : ℕ) : Finset (Slot T q) := Finset.univ.image (fun j => toLex (⟨T,by omega⟩,j))
def guides {T q : ℕ} (x : Slot T q) : Finset (Slot T q) :=
if h : rank x < T then Finset.univ.image (fun j => toLex (⟨rank x+1,by omega⟩,j)) else ∅
lemma base_card (T q : ℕ) : (base T q).card = q := by
rw [base,Finset.card_image_of_injective]
· simp
· intro j k h
exact congrArg (fun x : Slot T q => (ofLex x).2) h
lemma base_nonempty (T q : ℕ) (hq : 0 < q) : (base T q).Nonempty := by
rw [← Finset.card_pos,base_card]
exact hq
end MatchingFPRAS.Replica.Ladder
namespace MatchingFPRAS.Transport
section
open Finset MatchingFPRAS.Replica MatchingFPRAS.Replica.Ladder
variable {V J : Type*} [Fintype V] [DecidableEq V] [Fintype J] [DecidableEq J]
variable {bags : V → Finset J} {G : SimpleGraph J}
noncomputable def tierBase (V : Type*) [Fintype V] : ℝ := 1+((Fintype.card V:ℝ)^2)⁻¹
lemma tierBase_pos (V : Type*) [Fintype V] : 0 < tierBase V := by
unfold tierBase; positivity
end
open Finset MatchingFPRAS.Replica MatchingFPRAS.Replica.Ladder
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Evolve
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FiniteChain
open Finset MatchingFPRAS.Replica
variable {Ω : Type*} [Fintype Ω] [DecidableEq Ω]
noncomputable def evolve (π : Ω → ℝ) (C : Ω → Ω → ℝ) : ℕ → (Ω → ℝ) → (Ω → ℝ)
| 0, f => f
| n+1, f => stepDensity π C (evolve π C n f)
noncomputable def deltaDensity (π : Ω → ℝ) (z a : Ω) : ℝ := if a=z then (π z)⁻¹ else 0
noncomputable def kernel (π : Ω → ℝ) (C : Ω → Ω → ℝ) (a b : Ω) : ℝ := C a b/π a
noncomputable def walk (π : Ω → ℝ) (C : Ω → Ω → ℝ) (z : Ω) : ℕ → Ω → ℝ
| 0, a => if a=z then 1 else 0
| n+1, b => ∑ a, walk π C z n a*kernel π C a b
end MatchingFPRAS.FiniteChain
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_LadderL
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
def ladderL (N D : ℕ) : ℕ := (10^4*N*D)^100
def ladderQ (N D : ℕ) : ℕ := 32*ladderL N D
def ladderM (N D T : ℕ) : ℕ := T*(ladderQ N D)^2+ladderQ N D
def ladderLambda (N D K T : ℕ) : ℕ :=
10*N*ladderQ N D*(T+1)*(K+Nat.clog 2 (N*D+2)+1)
noncomputable def ladderSteps (N D K T : ℕ) (ξ : ℝ) : ℕ :=
20*ladderL N D*ladderM N D T*(ladderLambda N D K T+⌈Real.logb 2 ξ⁻¹⌉₊+1)
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_PM
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Subdivision
open Finset
def probeHoles (p : ℕ) (hp : 1≤p) : Finset (Fin (4*p)) :=
{⟨2*p-1,by omega⟩,⟨2*p,by omega⟩}
variable {V E : Type*} [Fintype V] [Fintype E] [DecidableEq V] [DecidableEq E]
variable (u v : E → V) (p : ℕ) (hp : 1≤p) (e₀ : E)
def singleProbeHoles (e : E) : Finset (Fin (4*p)) :=
if e=e₀ then probeHoles p hp else ∅
end MatchingFPRAS.Subdivision
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Probability_Tv
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Variation
open Finset
open scoped Classical
variable {Ω Ψ : Type*} [Fintype Ω] [Fintype Ψ]
noncomputable def tv (p q : Ω → ℝ) : ℝ := (∑ s,|p s-q s|)/2
noncomputable def event (p : Ω → ℝ) (P : Ω → Prop) : ℝ := ∑ x,if P x then p x else 0
noncomputable def bind (p : Ω → ℝ) (k : Ω → Ψ → ℝ) (y : Ψ) : ℝ := ∑ x,p x*k x y
noncomputable def push (p : Ω → ℝ) (f : Ω → Ψ) (y : Ψ) : ℝ :=
∑ x,if f x=y then p x else 0
omit [Fintype Ψ] in
lemma push_nonneg (p : Ω → ℝ) (hp : ∀ x,0 ≤ p x) (f : Ω → Ψ) (y : Ψ) :
0 ≤ push p f y := by
unfold push; apply sum_nonneg; intro x _; split_ifs
· exact hp x
· exact le_rfl
lemma push_sum (p : Ω → ℝ) (hs : ∑ x,p x=1) (f : Ω → Ψ) : ∑ y,push p f y=1 := by
unfold push; rw [sum_comm]; simpa using hs
noncomputable def tensor (p : Ω → ℝ) (q : Ψ → ℝ) (x : Ω×Ψ) : ℝ := p x.1*q x.2
section Product
variable {I : Type*} [Fintype I] [DecidableEq I]
noncomputable def product (p : I → Ω → ℝ) (x : I → Ω) : ℝ := ∏ i,p i (x i)
end Product
variable {B : Ω → Type*} [∀ a,Fintype (B a)]
noncomputable def sigmaLift (p : Ω → ℝ) (k : ∀ a,B a → ℝ) (s : Sigma B) : ℝ :=
p s.1*k s.1 s.2
end MatchingFPRAS.Variation
namespace MatchingFPRAS.Transport
def tierBound (N D K : ℕ) : ℕ := N^2*(Nat.clog 2 D+2*K+2)
lemma base_block (N : ℕ) (hN : 0<N) : 2 ≤ (1+((N:ℝ)^2)⁻¹)^(N^2) := by
have hp : (0:ℝ)<N := by exact_mod_cast hN
have ha : -(2:ℝ)≤((N:ℝ)^2)⁻¹ := by
have : (0:ℝ)≤((N:ℝ)^2)⁻¹ := by positivity
linarith
have h := one_add_mul_le_pow (a:=((N:ℝ)^2)⁻¹) ha (N^2)
norm_cast at h
have he : (N^2:ℝ)*((N:ℝ)^2)⁻¹=1 := mul_inv_cancel₀ (by positivity)
norm_num only [Nat.cast_pow, he] at h
linarith
lemma tierBound_reaches (N D K : ℕ) (hN : 0<N) :
max (D:ℝ) (3*4^K) ≤ (1+((N:ℝ)^2)⁻¹)^(tierBound N D K) := by
have hb := base_block N hN
have hp : 0≤(1+((N:ℝ)^2)⁻¹)^(N^2) := by positivity
have hD : (D:ℝ) ≤ 2^(Nat.clog 2 D) := by exact_mod_cast Nat.le_pow_clog (by decide : 1<2) D
have hk : (3:ℝ)*4^K ≤ 2^(2*K+2) := by
rw [pow_add,pow_mul]
norm_num
nlinarith [pow_pos (by norm_num : (0:ℝ)<4) K]
have eD : Nat.clog 2 D ≤ Nat.clog 2 D+2*K+2 := by omega
have eK : 2*K+2 ≤ Nat.clog 2 D+2*K+2 := by omega
calc
max (D:ℝ) (3*4^K) ≤ 2^(Nat.clog 2 D+2*K+2) := max_le
(hD.trans (pow_le_pow_right₀ (by norm_num) eD))
(hk.trans (pow_le_pow_right₀ (by norm_num) eK))
_ ≤ _ := by
unfold tierBound
rw [pow_mul]
exact pow_le_pow_left₀ (by norm_num) hb _
noncomputable def ladderTier (N D K : ℕ) (hN : 0<N) : ℕ :=
Nat.find (⟨tierBound N D K,tierBound_reaches N D K hN⟩ :
∃ t : ℕ,max (D:ℝ) (3*4^K) ≤ (1+((N:ℝ)^2)⁻¹)^t)
lemma ladderTier_spec (N D K : ℕ) (hN : 0<N) :
max (D:ℝ) (3*4^K) ≤ (1+((N:ℝ)^2)⁻¹)^(ladderTier N D K hN) := by
exact Nat.find_spec (p:=fun t : ℕ => max (D:ℝ) (3*4^K) ≤ (1+((N:ℝ)^2)⁻¹)^t)
⟨tierBound N D K,tierBound_reaches N D K hN⟩
lemma ladderTier_le (N D K : ℕ) (hN : 0<N) : ladderTier N D K hN ≤ tierBound N D K :=
Nat.find_min' _ (tierBound_reaches N D K hN)
end MatchingFPRAS.Transport
namespace MatchingFPRAS.Transport
open Finset MatchingFPRAS.Replica MatchingFPRAS.Replica.Ladder
variable {V J : Type*} [Fintype V] [DecidableEq V] [Fintype J] [DecidableEq J]
variable {bags : V → Finset J}
def topSlot (T q : ℕ) (hq : 0<q) : Slot T q := toLex (0,⟨0,hq⟩)
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_EnlargementRun
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh
structure Pairing (α : Type*) where
mate : α → α
involutive : Function.Involutive mate
no_fixed : ∀ x, mate x ≠ x
instance instFinitePairing {α : Type*} [Finite α] : Finite (Pairing α) := by
apply Finite.of_injective Pairing.mate
intro p q h
cases p; cases q
simp only [Pairing.mk.injEq] at *
exact h
noncomputable instance instFintypePairing {α : Type*} [Fintype α] : Fintype (Pairing α) := Fintype.ofFinite _
@[ext] lemma Pairing.ext {α : Type*} {p q : Pairing α} (h : ∀ x, p.mate x=q.mate x) : p=q := by
cases p; cases q
simp only [Pairing.mk.injEq]
exact funext h
variable {α β : Type*}
def Pairing.map (e : α ≃ β) (p : Pairing α) : Pairing β where
mate y := e (p.mate (e.symm y))
involutive y := by simp [p.involutive (e.symm y)]
no_fixed y := by
intro h
apply p.no_fixed (e.symm y)
have := congrArg e.symm h
simpa using this
lemma Pairing.subtype_hext {P Q : α → Prop} (p : Pairing {x // P x}) (q : Pairing {x // Q x})
(hPQ : ∀ x, P x ↔ Q x)
(h : ∀ (x : {x // P x}) (y : {x // Q x}), x.val=y.val →
(p.mate x).val=(q.mate y).val) : HEq p q := by
have he : P=Q := funext fun x => propext (hPQ x)
subst Q
apply heq_of_eq
ext x
exact h x x rfl
variable [DecidableEq α]
def Pairing.remove (p : Pairing α) (a : α) : Pairing {x : α // x≠a ∧ x≠p.mate a} where
mate x := ⟨p.mate x,by
constructor
· intro h
have := congrArg p.mate h
exact x.property.2 (by rw [p.involutive] at this; exact this)
· intro h
exact x.property.1 (p.involutive.injective h)⟩
involutive x := Subtype.ext (p.involutive x)
no_fixed x h := p.no_fixed x (congrArg Subtype.val h)
def pairingCount : ℕ → ℕ
| 0 => 1
| 1 => 0
| n+2 => (n+1)*pairingCount n
@[simp] lemma pairingCount_zero : pairingCount 0=1 := rfl
@[simp] lemma pairingCount_one : pairingCount 1=0 := rfl
@[simp] lemma pairingCount_add_two (n : ℕ) : pairingCount (n+2)=(n+1)*pairingCount n := rfl
lemma pairingCount_pos_recurrence {n : ℕ} (hn : 0<n) :
pairingCount n = (n-1)*pairingCount (n-2) := by
match n with
| 0 => omega
| 1 => rfl
| n+2 => simp only [pairingCount_add_two,Nat.add_sub_cancel,show n+2-1=n+1 by omega]
lemma card_except_two [Fintype α] (a b : α) (hab : b≠a) :
Fintype.card {x : α // x≠a ∧ x≠b}=Fintype.card α-2 := by
classical
calc
_ = Fintype.card {x : α // ¬ (x=a ∨ x=b)} :=
Fintype.card_congr (Equiv.subtypeEquivRight fun x => not_or.symm)
_ = Fintype.card α-Fintype.card {x : α // x=a ∨ x=b} := Fintype.card_subtype_compl _
_ = _ := by rw [Fintype.card_subtype_eq_or_eq_of_ne hab.symm]
universe u
end MatchingFPRAS.UnitRefresh
namespace MatchingFPRAS.Initializer
open Finset MatchingFPRAS.Switching MatchingFPRAS.UnitRefresh
variable {V : Type*} [Fintype V] [LinearOrder V]
lemma pairingCount_pos_of_even (n : ℕ) (h : Even n) : 0 < pairingCount n := by
obtain ⟨k,rfl⟩ := h
induction k with
| zero => norm_num
| succ k ih =>
rw [show k+1+(k+1)=(k+k)+2 by omega,pairingCount_add_two]
exact Nat.mul_pos (by omega) ih
def initialScale (n : ℕ) : ℚ := 1/(Nat.sqrt (n-1):ℚ)
lemma sqrt_square_bounds (n : ℕ) (hn : 2 ≤ n) :
(n-1:ℝ)/4 ≤ (Nat.sqrt (n-1):ℝ)^2 ∧ (Nat.sqrt (n-1):ℝ)^2 ≤ n-1 := by
have hpos : 1 ≤ Nat.sqrt (n-1) := Nat.le_sqrt.mpr (by omega)
have hlow := Nat.lt_succ_sqrt' (n-1)
have hup := Nat.sqrt_le' (n-1)
have hncast : ((n-1:ℕ):ℝ)=(n:ℝ)-1 := by rw [Nat.cast_sub (by omega : 1≤n),Nat.cast_one]
have hlow' : (n:ℝ)-1 < ((Nat.sqrt (n-1):ℝ)+1)^2 := by
rw [←hncast]
exact_mod_cast hlow
have hup' : (Nat.sqrt (n-1):ℝ)^2 ≤ (n:ℝ)-1 := by
rw [←hncast]
exact_mod_cast hup
have hs : (1:ℝ) ≤ Nat.sqrt (n-1) := by exact_mod_cast hpos
constructor
· nlinarith [sq_nonneg ((Nat.sqrt (n-1):ℝ)-1)]
· exact hup'
lemma initialScale_pos (n : ℕ) (hn : 2 ≤ n) : 0 < initialScale n := by
unfold initialScale
have hs : 0 < Nat.sqrt (n-1) := by have := Nat.le_sqrt.mpr (by omega : 1*1≤n-1); omega
positivity
end MatchingFPRAS.Initializer
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Cumulative
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FiniteChoice
open Finset
def cumulative {r : ℕ} (p : Fin r → ℚ) (i : ℕ) : ℚ := ∑ j, if j.val < i then p j else 0
lemma cumulative_zero {r : ℕ} (p : Fin r → ℚ) : cumulative p 0 = 0 := by simp [cumulative]
lemma cumulative_total {r : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1) : cumulative p r = 1 := by
simp only [cumulative,Fin.isLt,ite_true]; exact hs
lemma options_pos {r : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1) : 0 < r := by
by_contra h
have hr : r=0 := by omega
subst r
simp at hs
def candidates {r K : ℕ} (p : Fin r → ℚ) (J : Fin K) : Finset (Fin r) :=
Finset.univ.filter (fun i => (J.val:ℚ)/K < cumulative p (i.val+1))
lemma candidates_nonempty {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1)
(hK : 0 < K) (J : Fin K) : (candidates p J).Nonempty := by
have hr := options_pos p hs
refine ⟨⟨r-1,by omega⟩,?_⟩
simp only [candidates,Finset.mem_filter,Finset.mem_univ,true_and]
have he : r-1+1=r := by omega
rw [he,cumulative_total p hs]
apply (div_lt_one (by exact_mod_cast hK : (0:ℚ)<K)).mpr
exact_mod_cast J.isLt
def choose {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1) (hK : 0 < K) (J : Fin K) : Fin r :=
(candidates p J).min' (candidates_nonempty p hs hK J)
def outputLaw {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1) (hK : 0 < K) (i : Fin r) : ℚ :=
((Finset.univ.filter (fun J : Fin K => choose p hs hK J=i)).card:ℚ)/K
def gridInterval (K : ℕ) (a b : ℚ) : Finset ℕ :=
(Finset.range K).filter (fun j => a ≤ (j:ℚ)/K ∧ (j:ℚ)/K < b)
lemma cumulative_step {r : ℕ} (p : Fin r → ℚ) (i : Fin r) :
cumulative p (i.val+1)-cumulative p i.val = p i := by
unfold cumulative
rw [← Finset.sum_sub_distrib]
have he (j : Fin r) : (if j.val < i.val+1 then p j else 0)-(if j.val < i.val then p j else 0) =
if j=i then p j else 0 := by
by_cases h : j=i
· subst j; simp
· have hn : j.val ≠ i.val := fun hval => h (Fin.ext hval)
by_cases hj : j.val < i.val
· simp [h,hj,show j.val < i.val+1 by omega]
· simp [h,hj,show ¬j.val < i.val+1 by omega]
simp_rw [he]
simp
lemma choose_upper {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1)
(hK : 0 < K) (J : Fin K) :
(J.val:ℚ)/K < cumulative p ((choose p hs hK J).val+1) := by
have hm := Finset.min'_mem (candidates p J) (candidates_nonempty p hs hK J)
exact (Finset.mem_filter.mp hm).2
lemma choose_le {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1)
(hK : 0 < K) (J : Fin K) (i : Fin r)
(hi : (J.val:ℚ)/K < cumulative p (i.val+1)) : choose p hs hK J ≤ i := by
exact Finset.min'_le (candidates p J) i (Finset.mem_filter.mpr ⟨Finset.mem_univ _,hi⟩)
lemma choose_lower {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ j, p j = 1)
(hK : 0 < K) (J : Fin K) :
cumulative p (choose p hs hK J).val ≤ (J.val:ℚ)/K := by
let i := choose p hs hK J
by_cases hi : i.val=0
· rw [show (choose p hs hK J).val=0 from hi,cumulative_zero]
positivity
· by_contra hh
have hx : (J.val:ℚ)/K < cumulative p i.val := lt_of_not_ge hh
let j : Fin r := ⟨i.val-1,by have := i.isLt; omega⟩
have he : j.val+1=i.val := by dsimp [j]; omega
have hj : (J.val:ℚ)/K < cumulative p (j.val+1) := by rw [he]; exact hx
have hm := choose_le p hs hK J j hj
have hv : i.val ≤ j.val := hm
dsimp [j] at hv
omega
end MatchingFPRAS.FiniteChoice
namespace MatchingFPRAS.FiniteChoice
open Finset
def tapeIndex (k : ℕ) : (Fin k → Bool) ≃ Fin (2^k) :=
(Equiv.piCongrRight (fun _ : Fin k => finTwoEquiv.symm)).trans finFunctionFinEquiv
def chooseBits {r : ℕ} (p : Fin r → ℚ) (hs : ∑ i, p i = 1) (k : ℕ)
(bits : Fin k → Bool) : Fin r :=
choose p hs (pow_pos (by norm_num : 0 < (2:ℕ)) k) (tapeIndex k bits)
def tapeLaw {r : ℕ} (p : Fin r → ℚ) (hs : ∑ i, p i = 1) (k : ℕ) (i : Fin r) : ℚ :=
((univ.filter (fun bits : Fin k → Bool => chooseBits p hs k bits=i)).card:ℚ)/(2:ℚ)^k
end MatchingFPRAS.FiniteChoice
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Certify
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport.Sparse
open Finset
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable (ends : E → Sym2 V)
def colorRaw (A : Finset E) : Finset (Finset E) :=
A.biUnion fun e => (univ.filter (fun f => ends f = ends e)).image
(fun f => insert f (A.erase e))
omit [Fintype V] in
@[simp] lemma mem_colorRaw [Fintype V] (A B : Finset E) :
B ∈ colorRaw ends A ↔ ∃ e ∈ A, ∃ f, ends f = ends e ∧ B = insert f (A.erase e) := by
simp only [colorRaw,mem_biUnion,mem_image,mem_filter,mem_univ,true_and]
constructor
· rintro ⟨e,he,f,hf,h⟩
exact ⟨e,he,f,hf,h.symm⟩
· rintro ⟨e,he,f,hf,h⟩
exact ⟨e,he,f,hf,h.symm⟩
def switchPatterns (A : Finset E) : Finset ((Fin 4 → V) × (Fin 4 → E)) :=
univ.filter fun p => Function.Injective p.1 ∧
(∀ i x, x ∈ ends (p.2 i) ↔ x = p.1 i ∨ x = p.1 (i+1)) ∧
p.2 0 ≠ p.2 2 ∧ {p.2 0,p.2 2} ⊆ A
def switchRaw (A : Finset E) : Finset (Finset E) :=
(switchPatterns ends A).image fun p => (A \ {p.2 0,p.2 2}) ∪ {p.2 1,p.2 3}
end MatchingFPRAS.Transport.Sparse
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Component
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport.Sparse
open Finset
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [DecidableEq E]
variable (ends : E → Sym2 V)
instance decideOverlay (U : Finset E) :
DecidableRel (overlayLineGraph (fun e v => v ∈ ends e) U).Adj := by
intro e f
change Decidable (e ≠ f ∧ e ∈ U ∧ f ∈ U ∧ ∃ v, v ∈ ends e ∧ v ∈ ends f)
infer_instance
end MatchingFPRAS.Transport.Sparse
namespace MatchingFPRAS
structure WeightedOptions (Ω : Type*) where
size : ℕ
out : Fin size → Ω
mass : Fin size → ℚ
nonneg : ∀ i, 0 ≤ mass i
total : ∑ i, mass i = 1
namespace WeightedOptions
open Finset
variable {Ω Ψ : Type*}
def pure (a : Ω) : WeightedOptions Ω where
size := 1
out := fun _ => a
mass := fun _ => 1
nonneg := by simp
total := by simp
def map (f : Ω → Ψ) (c : WeightedOptions Ω) : WeightedOptions Ψ where
size := c.size
out := f ∘ c.out
mass := c.mass
nonneg := c.nonneg
total := c.total
def mix (p : ℚ) (hp : 0 ≤ p) (hp1 : p ≤ 1)
(a b : WeightedOptions Ω) : WeightedOptions Ω where
size := a.size+b.size
out := Fin.addCases a.out b.out
mass := Fin.addCases (fun i => p*a.mass i) (fun i => (1-p)*b.mass i)
nonneg i := by
refine Fin.addCases (fun i => ?_) (fun i => ?_) i
· simp only [Fin.addCases_left]
exact mul_nonneg hp (a.nonneg i)
· simp only [Fin.addCases_right]
exact mul_nonneg (sub_nonneg.mpr hp1) (b.nonneg i)
total := by
simp only [Fin.sum_univ_add,Fin.addCases_left,Fin.addCases_right,←mul_sum,a.total,b.total]
ring
variable [DecidableEq Ω]
def law (c : WeightedOptions Ω) (b : Ω) : ℚ := ∑ i, if c.out i=b then c.mass i else 0
@[simp] lemma pure_law (a b : Ω) : (pure a).law b=if a=b then 1 else 0 := by
change (∑ _i : Fin 1, if a=b then (1:ℚ) else 0)=_
simp
def accept (c : WeightedOptions Ω) (hold : Ω) (p : Ω → ℚ)
(hp : ∀ a, 0 ≤ p a) (hp1 : ∀ a, p a ≤ 1) : WeightedOptions Ω where
size := c.size+c.size
out := Fin.addCases c.out (fun _ => hold)
mass := Fin.addCases (fun i => c.mass i*p (c.out i))
(fun i => c.mass i*(1-p (c.out i)))
nonneg i := by
refine Fin.addCases (fun i => ?_) (fun i => ?_) i
· simp only [Fin.addCases_left]
exact mul_nonneg (c.nonneg i) (hp _)
· simp only [Fin.addCases_right]
exact mul_nonneg (c.nonneg i) (sub_nonneg.mpr (hp1 _))
total := by
simp only [Fin.sum_univ_add,Fin.addCases_left,Fin.addCases_right,←sum_add_distrib]
simp only [←mul_add,add_sub_cancel,mul_one,c.total]
variable [LinearOrder Ω]
def numbering (s : Finset Ω) : Fin s.card ≃ ↥s := (s.orderIsoOfFin rfl).toEquiv
def uniform (s : Finset Ω) (hs : s.Nonempty) : WeightedOptions Ω where
size := s.card
out := fun i => (numbering s i).val
mass := fun _ => (s.card:ℚ)⁻¹
nonneg := by intro i; positivity
total := by
have h : (s.card:ℚ) ≠ 0 := by exact_mod_cast hs.card_pos.ne'
simp [h]
def neighbors (a : Ω) (s : Finset Ω) (d : ℕ) (hd : s.card ≤ d) : WeightedOptions Ω where
size := s.card+1
out := Fin.lastCases a (fun i => (numbering s i).val)
mass := Fin.lastCases (1-(s.card:ℚ)/d) (fun _ => (d:ℚ)⁻¹)
nonneg i := by
refine Fin.lastCases ?_ (fun j => ?_) i
· simp only [Fin.lastCases_last]
by_cases h : d=0
· simp [h]
· have hh : (0:ℚ)<d := by exact_mod_cast Nat.pos_of_ne_zero h
exact sub_nonneg.mpr ((div_le_one hh).mpr (by exact_mod_cast hd))
· simp only [Fin.lastCases_castSucc]
positivity
total := by
rw [Fin.sum_univ_castSucc]
simp only [Fin.lastCases_castSucc,Fin.lastCases_last,sum_const,card_fin,nsmul_eq_mul]
ring
end WeightedOptions
end MatchingFPRAS
namespace MatchingFPRAS.Transport.Sparse
open Finset WeightedOptions
variable {Ω : Type*} [Fintype Ω] [LinearOrder Ω] [DecidableEq Ω]
variable {V E : Type*} [Fintype V] [DecidableEq V] [Fintype E] [LinearOrder E]
variable (ends : E → Sym2 V)
local instance finsetOrder : LinearOrder (Finset E) :=
LinearOrder.lift' toColex toColex.injective
end MatchingFPRAS.Transport.Sparse
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_MetropolisChoice
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.WeightedOptions
open Finset
variable {Ω : Type*} [Fintype Ω] [DecidableEq Ω]
def metropolisChoice (c : WeightedOptions Ω) (w : Ω → ℚ) (hw : ∀ a, 0 < w a) (a : Ω) :
WeightedOptions Ω := c.accept a (fun b => min 1 (w b / w a))
(fun b => le_min zero_le_one (div_nonneg (hw b).le (hw a).le))
(fun _ => min_le_left _ _)
end MatchingFPRAS.WeightedOptions
namespace MatchingFPRAS.Variation
open Finset
open scoped Classical
variable {A B C : Type*} [Fintype A] [Fintype B] [Fintype C]
noncomputable def uniform (A : Type*) [Fintype A] (_ : A) : ℝ := 1/Fintype.card A
lemma uniform_nonneg (a : A) : 0≤uniform A a := by unfold uniform; positivity
lemma uniform_sum [Nonempty A] : ∑ a : A,uniform A a=1 := by
simp only [uniform,sum_const,nsmul_eq_mul]
exact mul_one_div_cancel (by exact_mod_cast Fintype.card_ne_zero : (Fintype.card A:ℝ)≠0)
noncomputable def imageLaw (f : A → B) : B → ℝ := push (uniform A) f
omit [Fintype B] in
lemma imageLaw_nonneg (f : A → B) (b : B) : 0 ≤ imageLaw f b := push_nonneg _ uniform_nonneg _ _
lemma imageLaw_sum [Nonempty A] (f : A → B) : ∑ b,imageLaw f b=1 := push_sum _ uniform_sum _
open Finset
open scoped Classical
open scoped Classical
end MatchingFPRAS.Variation
namespace MatchingFPRAS.WeightedOptions
open Finset Variation FiniteChoice
variable {Ω : Type*} [Fintype Ω] [DecidableEq Ω]
def draw (c : WeightedOptions Ω) (k : ℕ) (bits : Fin k → Bool) : Ω :=
c.out (chooseBits c.mass c.total k bits)
end MatchingFPRAS.WeightedOptions
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_PairStep
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica
open Finset
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω] [DecidableEq Ω]
variable (p : I → Ω → ℝ)
noncomputable def pairStep (x y : I) (Q : PairCapacity p x y) (s t : I → Ω) : ℝ :=
∑ b : Ω×Ω, if replacePair x y s b=t then Q.q (s x,s y) b/(p x (s x)*p y (s y)) else 0
noncomputable def baseStep (i : I) (s t : I → Ω) : ℝ :=
∑ a : Ω, if Function.update s i a=t then p i a else 0
noncomputable def localScan (guides : I → Finset I) (base : Finset I)
(Q : ∀ x y,PairCapacity p x y) (s t : I → Ω) : ℝ :=
(if s=t then (1:ℝ) else 0)/2+
((∑ x,∑ y ∈ guides x,pairStep p x y (Q x y) s t)+∑ i ∈ base,baseStep p i s t)/
(2*(updateCount guides base:ℝ))
end MatchingFPRAS.Replica
namespace MatchingFPRAS.WeightedOptions
open Finset Variation
variable {J Ω B : Type*} [Fintype J] [DecidableEq J] [Fintype Ω] [DecidableEq Ω]
variable [Fintype B] [Nonempty B]
def drawThen (c : WeightedOptions J) (g : J → B → Ω) (k : ℕ)
(bits : (Fin k → Bool) × B) : Ω := g (c.draw k bits.1) bits.2
end MatchingFPRAS.WeightedOptions
namespace MatchingFPRAS.Replica
open Finset Variation
variable {I Ω : Type*} [Fintype I] [DecidableEq I] [Fintype Ω] [DecidableEq Ω]
abbrev Update (I : Type*) := (I×I) ⊕ I
def updates (guides : I → Finset I) (base : Finset I) : Finset (Update I) :=
((univ : Finset (I×I)).filter (fun ij=>ij.2∈guides ij.1)).disjSum base
lemma updates_nonempty (guides : I → Finset I) (base : Finset I) (hb : base.Nonempty) :
(updates guides base).Nonempty := by
obtain ⟨i,hi⟩:=hb
exact ⟨Sum.inr i,by simp [updates,hi]⟩
variable (p : I → Ω → ℝ)
noncomputable def updateKernel (Q : ∀ x y,PairCapacity p x y) (s : I → Ω) :
Option (Update I) → (I → Ω) → ℝ
| none,t => if s=t then 1 else 0
| some (.inl ij),t => pairStep p ij.1 ij.2 (Q ij.1 ij.2) s t
| some (.inr i),t => baseStep p i s t
variable [LinearOrder (Update I)]
def scanChoice (guides : I → Finset I) (base : Finset I) (hb : base.Nonempty) :
WeightedOptions (Option (Update I)) :=
WeightedOptions.mix (1/2) (by norm_num) (by norm_num) (WeightedOptions.pure none)
((WeightedOptions.uniform (updates guides base) (updates_nonempty guides base hb)).map some)
open Finset Variation
variable {I Ω B : Type*} [Fintype I] [DecidableEq I] [Fintype Ω] [DecidableEq Ω]
variable [Fintype B] [Nonempty B]
def localSampler (pair : I → I → (Ω×Ω) → B → Ω×Ω) (refresh : I → B → Ω)
(s : I → Ω) : Option (Update I) → B → (I → Ω)
| none,_ => s
| some (.inl ij),b => replacePair ij.1 ij.2 s (pair ij.1 ij.2 (s ij.1,s ij.2) b)
| some (.inr i),b => Function.update s i (refresh i b)
variable [LinearOrder (Update I)]
def sampleScan (guides : I → Finset I) (base : Finset I) (hb : base.Nonempty)
(pair : I → I → (Ω×Ω) → B → Ω×Ω) (refresh : I → B → Ω) (k : ℕ) (s : I → Ω) :
((Fin k → Bool) × B) → (I → Ω) :=
(scanChoice guides base hb).drawThen (localSampler pair refresh s) k
end MatchingFPRAS.Replica
namespace MatchingFPRAS.Variation
open Finset
variable {Ω B : Type*} [Fintype Ω] [DecidableEq Ω] [Fintype B] [Nonempty B]
def runSample (g : Ω → B → Ω) (z : Ω) : (n : ℕ) → (Fin n → B) → Ω
| 0,_ => z
| n+1,bits => g (runSample g z n (Fin.init bits)) (bits (Fin.last n))
end MatchingFPRAS.Variation
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Admissible
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Replica
open Finset Variation
variable {I Ω B : Type*} [Fintype I] [DecidableEq I] [Fintype Ω] [DecidableEq Ω]
variable [Fintype B] [Nonempty B] [LinearOrder (Update I)]
def admissible (guides : I → Finset I) (base : Finset I) : Option (Update I) → Prop
| none => True
| some (.inl ij) => ij.2∈guides ij.1
| some (.inr i) => i∈base
open Finset
end MatchingFPRAS.Replica
namespace MatchingFPRAS.FiniteChoice
lemma choose_pos {r K : ℕ} (p : Fin r → ℚ) (hs : ∑ i,p i=1)
(hK : 0<K) (J : Fin K) : 0<p (choose p hs hK J) := by
have hl := choose_lower p hs hK J
have hu := choose_upper p hs hK J
have hd := cumulative_step p (choose p hs hK J)
linarith
lemma chooseBits_pos {r : ℕ} (p : Fin r → ℚ) (hs : ∑ i,p i=1)
(k : ℕ) (bits : Fin k → Bool) : 0<p (chooseBits p hs k bits) :=
choose_pos p hs _ _
end MatchingFPRAS.FiniteChoice
namespace MatchingFPRAS.UnitRefresh
variable {α β : Type*}
variable [DecidableEq α]
universe u
open Finset Polynomial
variable {I : Type*} [Fintype I] [DecidableEq I]
open Finset Polynomial
variable {I : Type*} [Fintype I] [DecidableEq I]
variable {V L : Type*} [Fintype V] [Fintype L] [DecidableEq V] [DecidableEq L]
abbrev Assignment (bags : V → Finset L) := {f : V → L // ∀ x, f x ∈ bags x}
end MatchingFPRAS.UnitRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Edge2
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh
open Finset MatchingFPRAS.Transport
variable {V L : Type*} [Fintype V] [Fintype L] [DecidableEq V] [DecidableEq L]
variable {bags : V → Finset L}
open Finset
variable {U S W L : Type*} [Fintype U] [Fintype S] [Fintype W] [Fintype L]
[DecidableEq U] [DecidableEq S] [DecidableEq W] [DecidableEq L]
def leafBags (l p : L) (b : W → Finset L) : U ⊕ S ⊕ W → Finset L
| Sum.inl _ => {l}
| Sum.inr (Sum.inl _) => {l,p}
| Sum.inr (Sum.inr x) => b x
noncomputable def fiberCount {V : Type*} [Fintype V] (f : V → L) (l : L) : ℕ :=
Fintype.card {x : V // f x=l}
noncomputable def assignmentPartition {V : Type*} [Fintype V] [DecidableEq V]
(b : V → Finset L) (w : L → ℕ → ℕ) : ℕ :=
by classical exact ∑ f : Assignment b, ∏ l,w l (fiberCount f.val l)
def leafAssignment (l p : L) (b : W → Finset L) (T : Finset S) (f : Assignment b) :
Assignment (leafBags (U := U) (S := S) l p b) :=
⟨Sum.elim (fun _ => l) (Sum.elim (fun x => if x∈T then l else p) f.val),by
intro x
rcases x with x | (x | x)
· simp [leafBags]
· by_cases hx : x∈T <;> simp [leafBags,hx]
· exact f.property x⟩
noncomputable def leafAssignmentEquiv (l p : L) (hlp : l≠p) (b : W → Finset L) :
Assignment (leafBags (U := U) (S := S) l p b) ≃ (Finset S) × Assignment b where
toFun f := (univ.filter fun x => f.val (Sum.inr (Sum.inl x))=l,
⟨fun x => f.val (Sum.inr (Sum.inr x)),fun x => f.property _⟩)
invFun q := leafAssignment l p b q.1 q.2
left_inv f := by
apply Subtype.ext
funext x
rcases x with x | (x | x)
· have hf := f.property (Sum.inl x)
have hfl : f.val (Sum.inl x)=l := by simpa [leafBags] using hf
simpa [leafAssignment] using hfl.symm
· by_cases h : f.val (Sum.inr (Sum.inl x))=l
· simp [leafAssignment,h]
· have hf := f.property (Sum.inr (Sum.inl x))
simp only [leafBags,mem_insert,mem_singleton] at hf
simp [leafAssignment,hf.resolve_left h,hlp.symm]
· rfl
right_inv q := by
apply Prod.ext
· ext x
by_cases hx : x∈q.1 <;> simp [leafAssignment,hx,hlp.symm]
· rfl
omit [Fintype L] in
lemma fiberCount_sum [Fintype L] {A B : Type*} [Fintype A] [Fintype B] (f : A ⊕ B → L) (l : L) :
fiberCount f l = fiberCount (fun x : A => f (Sum.inl x)) l +
fiberCount (fun x : B => f (Sum.inr x)) l := by
unfold fiberCount
rw [Fintype.card_congr Equiv.subtypeSum,Fintype.card_sum]
omit [Fintype L] [DecidableEq U] in
lemma fiberCount_const [Fintype L] [DecidableEq U]
(a l : L) : fiberCount (fun _ : U => a) l = if a=l then Fintype.card U else 0 := by
classical
by_cases h : a=l <;> simp [fiberCount,h]
omit [Fintype L] in
lemma fiberCount_zero [Fintype L] {A : Type*} [Fintype A] (f : A → L) (l : L) (h : ∀ x,f x≠l) :
fiberCount f l=0 := by
classical
simp [fiberCount,h]
lemma prod_split_two (l p : L) (hlp : l≠p) (f : L → ℕ) :
(∏ a,f a)=f l*f p*(∏ a∈(univ.erase l).erase p,f a) := by
rw [←prod_erase_mul univ f (mem_univ l),
←prod_erase_mul (univ.erase l) f (mem_erase.mpr ⟨hlp.symm,mem_univ p⟩)]
ac_rfl
omit [DecidableEq S] in
lemma sum_finset_card [DecidableEq S] (g : ℕ → ℕ) :
(∑ T : Finset S,g T.card)=∑ k∈range (Fintype.card S+1),(Fintype.card S).choose k*g k := by
classical
have hu : (univ : Finset (Finset S))=(univ : Finset S).powerset := by ext T; simp
rw [hu,sum_powerset]
apply sum_congr rfl
intro k hk
simpa using (sum_powersetCard k (univ : Finset S) g)
noncomputable def leafUpdate (u s : ℕ) (l p : L) (w : L → ℕ → ℕ) : L → ℕ → ℕ :=
fun a r => if a=l then 1 else if a=p then
∑ k∈range (s+1),s.choose k*w l (u+k)*w p (s-k+r) else w a r
end MatchingFPRAS.UnitRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_AssignmentEquiv
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh
open Finset
variable {V W L : Type*} [Fintype V] [Fintype W] [Fintype L]
[DecidableEq V] [DecidableEq W] [DecidableEq L]
noncomputable def assignmentEquiv (b : V → Finset L) (c : W → Finset L)
(e : V ≃ W) (he : ∀ x,c (e x)=b x) : Assignment b ≃ Assignment c where
toFun f := ⟨fun y => f.val (e.symm y),fun y => by
have hy : c y=b (e.symm y) := by simpa using he (e.symm y)
rw [hy]; exact f.property (e.symm y)⟩
invFun f := ⟨fun x => f.val (e x),fun x => by rw [←he]; exact f.property _⟩
left_inv f := Subtype.ext (by funext x; simp)
right_inv f := Subtype.ext (by funext x; simp)
omit [Fintype L] [DecidableEq V] [DecidableEq W] in
lemma fiberCount_equiv [Fintype L] [DecidableEq V] [DecidableEq W]
(e : V ≃ W) (f : V → L) (g : W → L)
(h : ∀ x,g (e x)=f x) (l : L) : fiberCount f l=fiberCount g l := by
unfold fiberCount
exact Fintype.card_congr (e.subtypeEquiv (fun x => by rw [h]))
lemma assignmentPartition_equiv (b : V → Finset L) (c : W → Finset L)
(e : V ≃ W) (he : ∀ x,c (e x)=b x) (w : L → ℕ → ℕ) :
assignmentPartition b w = assignmentPartition c w := by
classical
unfold assignmentPartition
apply Fintype.sum_equiv (assignmentEquiv b c e he)
intro f
apply prod_congr rfl
intro l hl
congr 1
apply fiberCount_equiv e
intro x
simp [assignmentEquiv]
abbrev Private (b : V → Finset L) (l : L) := {x : V // b x={l}}
abbrev Shared (b : V → Finset L) (l : L) := {x : V // l∈b x ∧ b x≠{l}}
abbrev Outside (b : V → Finset L) (l : L) := {x : V // l∉b x}
noncomputable def splitLeaf (b : V → Finset L) (l : L) :
V ≃ Private b l ⊕ Shared b l ⊕ Outside b l where
toFun x := if h : b x={l} then .inl ⟨x,h⟩ else
if h' : l∈b x then .inr (.inl ⟨x,h',h⟩) else .inr (.inr ⟨x,h'⟩)
invFun := Sum.elim Subtype.val (Sum.elim Subtype.val Subtype.val)
left_inv x := by dsimp only; split_ifs <;> rfl
right_inv x := by
rcases x with x | (x | x)
· simp [x.property]
· simp [x.property.1,x.property.2]
· have hx : b x.val≠{l} := by intro h; exact x.property (by simp [h])
simp [hx,x.property]
def LeafAt (b : V → Finset L) (l p : L) : Prop :=
∀ x,l∈b x → b x={l} ∨ b x={l,p}
omit [Fintype V] [Fintype L] [DecidableEq V] in
lemma splitLeaf_bags [Fintype V] [Fintype L] [DecidableEq V]
(b : V → Finset L) (l p : L) (h : LeafAt b l p) (x : V) :
leafBags l p (fun y : Outside b l => b y.val) (splitLeaf b l x)=b x := by
classical
unfold splitLeaf
simp only [Equiv.coe_fn_mk]
split_ifs with he hm
· exact he.symm
· exact ((h x hm).resolve_left he).symm
· rfl
def rootBags {U : Type*} (l : L) (b : W → Finset L) : U ⊕ W → Finset L :=
Sum.elim (fun _ => {l}) b
noncomputable def rootAssignmentEquiv {U : Type*} [Fintype U] [DecidableEq U]
(l : L) (b : W → Finset L) : Assignment (rootBags (U:=U) l b) ≃ Assignment b where
toFun f := ⟨fun x => f.val (.inr x),fun x => f.property _⟩
invFun f := ⟨Sum.elim (fun _ => l) f.val,by
intro x; rcases x with x | x
· simp [rootBags]
· exact f.property x⟩
left_inv f := by
apply Subtype.ext
funext x
rcases x with x | x
· have h := f.property (.inl x)
have hx : f.val (.inl x)=l := by simpa [rootBags] using h
exact hx.symm
· rfl
right_inv f := rfl
noncomputable def rootUpdate (u : ℕ) (l : L) (w : L → ℕ → ℕ) : L → ℕ → ℕ :=
fun a r => if a=l then w l u else w a r
noncomputable def splitRoot (b : V → Finset L) (l : L) :
V ≃ {x : V // l∈b x} ⊕ Outside b l where
toFun x := if h : l∈b x then .inl ⟨x,h⟩ else .inr ⟨x,h⟩
invFun := Sum.elim Subtype.val Subtype.val
left_inv x := by dsimp only; split_ifs <;> rfl
right_inv x := by rcases x with x | x <;> simp [x.property]
open Finset
variable {V L : Type*} [Fintype V] [Fintype L] [DecidableEq V] [DecidableEq L]
noncomputable def activePartition (b : V → Finset L) (R : Finset V) (w : L → ℕ → ℕ) : ℕ :=
assignmentPartition (fun x : R => b x.val) w
def trim (b : V → Finset L) (R : Finset V) (l : L) : Finset V := R.filter fun x => l∉b x
def privateCount (b : V → Finset L) (R : Finset V) (l : L) : ℕ :=
(R.filter fun x => b x={l}).card
def sharedCount (b : V → Finset L) (R : Finset V) (l : L) : ℕ :=
(R.filter fun x => l∈b x ∧ b x≠{l}).card
noncomputable def activeFilterEquiv (R : Finset V) (P : V → Prop) [DecidablePred P] :
{x : R // P x.val} ≃ (R.filter P) where
toFun x := ⟨x.val.val,mem_filter.mpr ⟨x.val.property,x.property⟩⟩
invFun x := ⟨⟨x.val,(mem_filter.mp x.property).1⟩,(mem_filter.mp x.property).2⟩
left_inv _ := rfl
right_inv _ := rfl
omit [Fintype V] [DecidableEq V] in
lemma active_card_filter [Fintype V] [DecidableEq V]
(R : Finset V) (P : V → Prop) [DecidablePred P] :
Fintype.card {x : R // P x.val}=(R.filter P).card := by
rw [Fintype.card_congr (activeFilterEquiv R P),Fintype.card_coe]
omit [Fintype V] in
lemma active_outside [Fintype V]
(b : V → Finset L) (R : Finset V) (l : L) (w : L → ℕ → ℕ) :
assignmentPartition (fun x : Outside (fun y : R => b y.val) l => b x.val.val) w =
activePartition b (trim b R l) w := by
change assignmentPartition (fun x : {y : R // l∉b y.val} => b x.val.val) w =
assignmentPartition (fun x : R.filter (fun y => l∉b y) => b x.val) w
apply assignmentPartition_equiv _ _ (activeFilterEquiv R (fun x => l∉b x))
intro x
rfl
lemma partition_isEmpty {W : Type*} [Fintype W] [DecidableEq W] [IsEmpty W]
(b : W → Finset L) (w : L → ℕ → ℕ) : assignmentPartition b w=∏ l,w l 0 := by
classical
let : Unique (Assignment b) :=
{ default := ⟨isEmptyElim,fun x => isEmptyElim x⟩
uniq := fun f => Subtype.ext (by funext x; exact isEmptyElim x) }
simp [assignmentPartition,fiberCount]
omit [Fintype V] in
lemma active_empty [Fintype V] (b : V → Finset L) (w : L → ℕ → ℕ) :
activePartition b ∅ w=∏ l,w l 0 := partition_isEmpty _ _
def RankedBags (b : V → Finset L) (rank : L → ℕ) (parent : L → Option L) : Prop :=
∀ x a,a ∈ b x → ∀ a'∈b x,a≠a' →
(rank a < rank a' ∧ parent a'=some a) ∨ (rank a' < rank a ∧ parent a=some a')
noncomputable def advanceTable (b : V → Finset L) (R : Finset V) (parent : L → Option L)
(l : L) (w : L → ℕ → ℕ) : L → ℕ → ℕ :=
match parent l with
| some p => leafUpdate (privateCount b R l) (sharedCount b R l) l p w
| none => rootUpdate ((R.filter fun x => l∈b x).card) l w
noncomputable def tableDP (b : V → Finset L) (parent : L → Option L) :
List L → Finset V → (L → ℕ → ℕ) → (L → ℕ → ℕ)
| [],_,w => w
| l::ls,R,w => tableDP b parent ls (trim b R l) (advanceTable b R parent l w)
def LegalPlan (b : V → Finset L) (parent : L → Option L) : List L → Finset V → Prop
| [],R => R=∅
| l::ls,R =>
(match parent l with
| some p => l≠p ∧ LeafAt (fun x : R => b x.val) l p
| none => ∀ x : R,l∈b x.val → b x.val={l}) ∧
LegalPlan b parent ls (trim b R l)
omit [Fintype V] [Fintype L] [DecidableEq V] in
theorem rank_order_legal [Fintype V] [Fintype L] [DecidableEq V]
(b : V → Finset L) (rank : L → ℕ) (parent : L → Option L)
(hb : RankedBags b rank parent)
(hp : ∀ l p,parent l=some p → rank p < rank l)
(ls : List L) (hs : ls.Pairwise (fun a a' => rank a' ≤ rank a))
(R : Finset V) (hne : ∀ x∈R,(b x).Nonempty)
(hc : ∀ x∈R,∀ a∈b x,a∈ls) : LegalPlan b parent ls R := by
induction ls generalizing R with
| nil =>
apply eq_empty_iff_forall_notMem.mpr
intro x hx
obtain ⟨a,ha⟩ := hne x hx
exact List.not_mem_nil (hc x hx a ha)
| cons l ls ih =>
have hs' := List.pairwise_cons.mp hs
have hmax (x : R) (a : L) (ha : a∈b x.val) : rank a ≤ rank l := by
have h := hc x.val x.property a ha
rcases List.mem_cons.mp h with h | h
· exact h ▸ le_rfl
· exact hs'.1 a h
have hparent (x : R) (hl : l∈b x.val) (a : L) (ha : a∈b x.val) (hal : a≠l) :
parent l=some a := by
rcases hb x.val l hl a ha (Ne.symm hal) with h | h
· exact (Nat.not_lt_of_ge (hmax x a ha) h.1).elim
· exact h.2
constructor
· cases hpar : parent l with
| none =>
intro x hl
apply eq_singleton_iff_unique_mem.mpr
exact ⟨hl,fun a ha => by
by_contra hal
have h := hparent x hl a ha hal
rw [hpar] at h
cases h⟩
| some p =>
constructor
· intro h; subst p
exact Nat.lt_irrefl _ (hp l l hpar)
· intro x hl
by_cases h : b x.val={l}
· exact Or.inl h
· right
apply Subset.antisymm
· intro a ha
by_cases hal : a=l
· simp [hal]
· have hpa : p=a := Option.some.inj (hpar.symm.trans (hparent x hl a ha hal))
simp [hpa]
· intro a ha
simp only [mem_insert,mem_singleton] at ha
rcases ha with ha | ha
· simpa [ha] using hl
· rw [ha]
by_contra hpn
apply h
apply eq_singleton_iff_unique_mem.mpr
refine ⟨hl,fun a ha => ?_⟩
by_contra hal
have hpa : p=a := Option.some.inj (hpar.symm.trans (hparent x hl a ha hal))
exact hpn (hpa ▸ ha)
· apply ih hs'.2
· intro x hx
exact hne x (mem_filter.mp hx).1
· intro x hx a ha
have hx' := mem_filter.mp hx
have h := hc x hx'.1 a ha
rcases List.mem_cons.mp h with hh | hh
· exact (hx'.2 (hh ▸ ha)).elim
· exact hh
end MatchingFPRAS.UnitRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_RankOrder
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh
open Finset
variable {V L : Type*} [Fintype V] [Fintype L] [DecidableEq V] [DecidableEq L]
lemma active_univ (b : V → Finset L) (w : L → ℕ → ℕ) :
activePartition b univ w=assignmentPartition b w := by
change assignmentPartition (fun x : (univ : Finset V) => b x.val) w=assignmentPartition b w
let e : (univ : Finset V) ≃ V :=
{ toFun := Subtype.val
invFun := fun x => ⟨x,mem_univ x⟩
left_inv := fun x => rfl
right_inv := fun x => rfl }
apply assignmentPartition_equiv _ _ e
intro x; rfl
omit [Fintype L] [DecidableEq V] in
lemma shared_le_card [Fintype L] [DecidableEq V] (b : V → Finset L) (R : Finset V) (l : L) :
sharedCount b R l≤Fintype.card V := by
exact (card_filter_le _ _).trans (card_le_univ R)
omit [Fintype L] in
lemma private_add_shared [Fintype L] (b : V → Finset L) (R : Finset V) (l : L) :
privateCount b R l+sharedCount b R l≤Fintype.card V := by
classical
have he : (R.filter fun x => b x={l}) ∪ (R.filter fun x => l∈b x ∧ b x≠{l}) =
R.filter (fun x => l∈b x) := by
ext x
simp only [mem_union,mem_filter]
constructor
· rintro (⟨hx,hb⟩|⟨hx,hl,_⟩)
· exact ⟨hx,by simp [hb]⟩
· exact ⟨hx,hl⟩
· rintro ⟨hx,hl⟩
by_cases h : b x={l}
· exact Or.inl ⟨hx,h⟩
· exact Or.inr ⟨hx,hl,h⟩
have hd : Disjoint (R.filter fun x => b x={l}) (R.filter fun x => l∈b x ∧ b x≠{l}) := by
apply disjoint_left.mpr
intro x hx hx'
exact (mem_filter.mp hx').2.2 (mem_filter.mp hx).2
unfold privateCount sharedCount
rw [← card_union_of_disjoint hd,he]
exact (card_filter_le _ _).trans (card_le_univ R)
lemma advanceTable_congr (b : V → Finset L) (R : Finset V) (parent : L → Option L)
(l : L) (w z : L → ℕ → ℕ) (B : ℕ)
(h : ∀ a r,r≤B+Fintype.card V → w a r=z a r) (a : L) (r : ℕ) (hr : r≤B) :
advanceTable b R parent l w a r=advanceTable b R parent l z a r := by
classical
have hs := shared_le_card b R l
have hu := private_add_shared b R l
unfold advanceTable
cases hpar : parent l with
| some p =>
simp only
unfold leafUpdate
split_ifs
· rfl
· apply sum_congr rfl
intro k hk
have hk' : k ≤ sharedCount b R l := by simpa using (mem_range.mp hk)
rw [h l _ (by omega),h _ _ (by omega)]
· exact h a r (by omega)
| none =>
simp only
unfold rootUpdate
split_ifs
· apply h
have ht := (card_filter_le (s:=R) (p:=fun x => l∈b x)).trans (card_le_univ R)
omega
· exact h a r (by omega)
noncomputable def capTable (B : ℕ) (w : L → ℕ → ℕ) : L → ℕ → ℕ :=
fun a r => if r≤B then w a r else 0
noncomputable def finiteDP (b : V → Finset L) (parent : L → Option L) :
List L → Finset V → (L → ℕ → ℕ) → (L → ℕ → ℕ)
| [],_,w => w
| l::ls,R,w => finiteDP b parent ls (trim b R l)
(capTable (Fintype.card V*ls.length)
(advanceTable b R parent l w))
abbrev withoutPair (a b : V) := {x : V // x≠a ∧ x≠b}
abbrev residualBags (bags : V → Finset L) (a b : V) : withoutPair a b → Finset L :=
fun x => bags x.val
abbrev Partner (bags : V → Finset L) (a : V) :=
{bc : V × L // bc.1≠a ∧ bc.2∈bags a ∧ bc.2∈bags bc.1}
end MatchingFPRAS.UnitRefresh
namespace MatchingFPRAS.UnitRefresh.Materialized
open Finset
variable {V : Type*} [Fintype V] [DecidableEq V]
abbrev Table := List (List ℕ)
def read (t : Table) (a r : ℕ) : ℕ := (t.getD a []).getD r 0
def tabulate (m B : ℕ) (f : Fin m → ℕ → ℕ) : Table :=
List.ofFn fun a : Fin m => List.ofFn fun r : Fin (B+1) => f a r.val
def entry {m : ℕ} (bags : V → Finset (Fin m)) (R : Finset V)
(parent : Fin m → Option (Fin m)) (l a : Fin m) (t : Table) (r : ℕ) : ℕ :=
match parent l with
| none => if a=l then read t l.val ((R.filter fun x=>l∈bags x).card) else read t a.val r
| some p => if a=l then 1 else if a=p then
∑ k∈range (sharedCount bags R l+1),
(sharedCount bags R l).choose k * read t l.val (privateCount bags R l+k) *
read t p.val (sharedCount bags R l-k+r)
else read t a.val r
omit [Fintype V] [DecidableEq V] in
lemma entry_eq [Fintype V] [DecidableEq V] {m : ℕ} (bags : V → Finset (Fin m)) (R : Finset V)
(parent : Fin m → Option (Fin m)) (l a : Fin m) (t : Table) (r : ℕ) :
entry bags R parent l a t r =
advanceTable bags R parent l (fun a r => read t a.val r) a r := by
unfold entry advanceTable leafUpdate rootUpdate
cases parent l <;> rfl
def update {m : ℕ} (bags : V → Finset (Fin m)) (R : Finset V)
(parent : Fin m → Option (Fin m)) (l : Fin m) (B : ℕ) (t : Table) : Table :=
tabulate m B (fun a r=>entry bags R parent l a t r)
def run {m : ℕ} (bags : V → Finset (Fin m)) (parent : Fin m → Option (Fin m)) :
List (Fin m) → Finset V → Table → Table
| [],_,t => t
| l::ls,R,t => run bags parent ls (trim bags R l)
(update bags R parent l (Fintype.card V*ls.length) t)
def initial (m B : ℕ) : Table := tabulate m B (fun _=>pairingCount)
def count {m : ℕ} (bags : V → Finset (Fin m)) (parent : Fin m → Option (Fin m))
(plan : List (Fin m)) : ℕ :=
let t := run bags parent plan univ (initial m (Fintype.card V*m))
∏ a : Fin m,read t a.val 0
end MatchingFPRAS.UnitRefresh.Materialized
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeFold
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A B : Type}
namespace Fold
inductive Point where | loop | check | splitHead | pushTail | pushArgs | body | popTail | rebuild | halt
deriving DecidableEq, Inhabited
instance instFintypePoint : Fintype Point := ⟨{.loop,.check,.splitHead,.pushTail,.pushArgs,.body,.popTail,.rebuild,.halt},by
intro p; cases p <;> simp⟩
end Fold
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeList
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A B C : Type}
def mulStep (x : Bool×(ℕ×ℕ)) : ℕ×ℕ :=
(x.2.1,2*x.2.2+(if x.1 then x.2.1 else 0))
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Arithmetic_TreeNatDivision
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
def divStep (x : Bool×(ℕ×(ℕ×ℕ))) : ℕ×(ℕ×ℕ) :=
let n:=x.2.1
let q:=x.2.2.1
let r:=2*x.2.2.2+x.1.toNat
(n,if r<n then (2*q,r) else (2*q+1,r-n))
lemma divStep_first (b : Bool) (n q r : ℕ) : (divStep (b,(n,q,r))).1=n := rfl
lemma divStep_lt (b : Bool) (n q r : ℕ) (_ : 0<n) (hr : r<n) :
(divStep (b,(n,q,r))).2.2<n := by
have hb : b.toNat ≤ 1 := Bool.toNat_le b
simp only [divStep]
split_ifs <;> simp only
· assumption
· omega
lemma divStep_mass (b : Bool) (n q r : ℕ) :
n*(divStep (b,(n,q,r))).2.1+(divStep (b,(n,q,r))).2.2=
2*(n*q+r)+b.toNat := by
simp only [divStep]
split_ifs with h
· simp only; ring
· simp only
have hh : n ≤ 2*r+b.toNat := by omega
have hs:=Nat.sub_add_cancel hh
nlinarith
lemma divFold_first (A : List Bool) (n q r : ℕ) :
(A.foldl (fun z b=>divStep (b,z)) (n,q,r)).1=n := by
induction A generalizing q r with
| nil => rfl
| cons b A ih =>
change (A.foldl _ (divStep (b,(n,q,r)))).1=n
rw [←Prod.eta (divStep (b,(n,q,r))),divStep_first]
rw [←Prod.eta (divStep (b,(n,q,r))).2]
exact ih _ _
lemma divFold_lt (A : List Bool) (n q r : ℕ) (hn : 0<n) (hr : r<n) :
(A.foldl (fun z b=>divStep (b,z)) (n,q,r)).2.2<n := by
induction A generalizing q r with
| nil => exact hr
| cons b A ih =>
change (A.foldl _ (divStep (b,(n,q,r)))).2.2<n
rw [←Prod.eta (divStep (b,(n,q,r))),divStep_first]
rw [←Prod.eta (divStep (b,(n,q,r))).2]
exact ih _ _ (divStep_lt b n q r hn hr)
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeRepeat
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {B : Type}
def countDown (f : ℕ×B → B) : ℕ → B → B
| 0,b => b
| n+1,b => countDown f n (f (n+1,b))
namespace Repeat
inductive Point where | loop | check | rebuild | body | halt
deriving DecidableEq, Inhabited
instance instFintypePoint : Fintype Point := ⟨{.loop,.check,.rebuild,.body,.halt},by intro p; cases p <;> simp⟩
def next (f : ℕ×B → B) (nb : ℕ×B) : ℕ×B := (nb.1-1,f nb)
end Repeat
def rangeStep (x : ℕ×List ℕ) : List ℕ := (x.1-1)::x.2
lemma countDown_range (n : ℕ) (as : List ℕ) : countDown rangeStep n as=List.range n++as := by
induction n generalizing as with
| zero => rfl
| succ n ih => simp [countDown,rangeStep,ih,List.range_succ,List.append_assoc]
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeNaturalComb
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
def factStep (x : ℕ×ℕ) : ℕ := x.1*x.2
lemma fact_countDown (n a : ℕ) : countDown factStep n a=n.factorial*a := by
induction n generalizing a with
| zero => simp [countDown]
| succ n ih =>
rw [countDown,ih]
simp only [factStep,Nat.factorial_succ]
ring
def pairingStep (x : ℕ×(ℕ×ℕ)) : ℕ×ℕ := (x.2.2,(x.1+1)*x.2.1)
lemma pairing_range (n : ℕ) :
(List.range n).foldl (fun z i=>pairingStep (i,z)) (1,0)=
(UnitRefresh.pairingCount n,UnitRefresh.pairingCount (n+1)) := by
induction n with
| zero => rfl
| succ n ih =>
rw [List.range_succ,List.foldl_append,ih]
simp [pairingStep,UnitRefresh.pairingCount]
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeListOps
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A B X : Type}
def dropStep (x : ℕ×List A) : List A := x.2.tail
def mapStep (g : X×A → B) (z : A×(X×List B)) : X×List B :=
(z.2.1,g (z.2.1,z.1)::z.2.2)
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Arithmetic_TreeGCD
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
def sortedPair (x : ℕ×ℕ) : ℕ×ℕ := if x.1<x.2 then (x.2,x.1) else x
lemma sortedPair_order (x : ℕ×ℕ) : (sortedPair x).2≤(sortedPair x).1 := by
unfold sortedPair; split_ifs <;> (try dsimp only) <;> omega
lemma sortedPair_gcd (x : ℕ×ℕ) : (sortedPair x).1.gcd (sortedPair x).2=x.1.gcd x.2 := by
unfold sortedPair; split_ifs <;> simp [Nat.gcd_comm]
lemma sortedPair_size (x : ℕ×ℕ) : (sortedPair x).1.size+(sortedPair x).2.size=x.1.size+x.2.size := by
unfold sortedPair
split_ifs
· exact Nat.add_comm _ _
· rfl
def gcdStep (x : ℕ×ℕ) : ℕ×ℕ := if x.2=0 then x else (x.2,x.1%x.2)
lemma mod_size_lt {a b : ℕ} (hb : 0<b) (hab : b≤a) : (a%b).size<a.size := by
have ha : 0<a := hb.trans_le hab
have hr := Nat.mod_lt a hb
have hq : 1≤a/b := Nat.div_pos hab hb
have hd := Nat.mod_add_div a b
have hm : 2*(a%b)<a := by nlinarith [Nat.mul_le_mul_left b hq]
have hs := Nat.size_pos.mpr ha
obtain ⟨k,hk⟩ := Nat.exists_eq_succ_of_ne_zero (by omega : a.size≠0)
have hpow:=Nat.lt_size_self a
rw [hk,pow_succ] at hpow
have hh : a%b<2^k := by omega
have hsz := Nat.size_le.mpr hh
omega
lemma gcdStep_order {x : ℕ×ℕ} (h : x.2≤x.1) : (gcdStep x).2≤(gcdStep x).1 := by
unfold gcdStep; split_ifs with hz
· exact h
· exact (Nat.mod_lt _ (by omega)).le
lemma gcdStep_gcd (x : ℕ×ℕ) : (gcdStep x).1.gcd (gcdStep x).2=x.1.gcd x.2 := by
unfold gcdStep; split_ifs
· rfl
· simpa [Nat.gcd_comm] using (Nat.gcd_rec x.2 x.1).symm
lemma gcdStep_decrease {x : ℕ×ℕ} (h : x.2≤x.1) (hz : x.2≠0) :
(gcdStep x).1.size+(gcdStep x).2.size<x.1.size+x.2.size := by
simp only [gcdStep,hz,↓reduceIte]
have hh:=mod_size_lt (by omega : 0<x.2) h
omega
def gcdIterStep (x : ℕ×(ℕ×ℕ)) : ℕ×ℕ := gcdStep x.2
lemma gcdIter_zero (k a : ℕ) : countDown gcdIterStep k (a,0)=(a,0) := by
induction k with
| zero => rfl
| succ k ih => simpa only [countDown,gcdIterStep,gcdStep,↓reduceIte] using ih
lemma gcdIter_result (k : ℕ) (x : ℕ×ℕ) (h : x.2≤x.1) (hs : x.1.size+x.2.size≤k) :
countDown gcdIterStep k x=(x.1.gcd x.2,0) := by
induction k generalizing x with
| zero =>
have hsz : x.1.size=0 := by omega
have ha:=Nat.size_eq_zero.mp hsz
have hb : x.2=0 := by omega
simp [countDown,ha,hb]
exact Prod.ext ha hb
| succ k ih =>
by_cases hz : x.2=0
· obtain ⟨a,b⟩:=x; dsimp only at hz; subst b
simp only [gcdIter_zero,Nat.gcd_zero_right]
· rw [countDown]
change countDown gcdIterStep k (gcdStep x)=_
rw [ih _ (gcdStep_order h) (by have hd:=gcdStep_decrease h hz; omega),gcdStep_gcd]
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeCanonical
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
open Polynomial
variable {A : Type}
def dedupStep [DecidableEq A] (x : A×List A) : List A := if x.1∈x.2 then x.2 else x.1::x.2
variable (r : A → A → Prop) [DecidableRel r]
def insertStep (x : A×(A×(List A×List A))) : A×(List A×List A) :=
(x.2.1,(x.1::x.2.2.1,if r x.2.1 x.1 then x.2.1::x.1::x.2.2.1 else x.1::x.2.2.2))
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeDPEntry
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped
abbrev Table := List (List ℕ)
def read (x : Table×(ℕ×ℕ)) : ℕ := (x.1.getD x.2.1 []).getD x.2.2 0
abbrev EntryCtx := (Bool×ℕ) × (ℕ × (Table × (ℕ × (ℕ × ℕ))))
def term (x : (EntryCtx×ℕ)×ℕ) : ℕ :=
let c := x.1.1
let r := x.1.2
let k := x.2
c.2.2.2.2.1.choose k * read (c.2.2.1,(c.2.1,c.2.2.2.1+k)) *
read (c.2.2.1,(c.1.2,c.2.2.2.2.1-k+r))
def entry (x : EntryCtx×(ℕ×ℕ)) : ℕ :=
let c:=x.1
let a:=x.2.1
let r:=x.2.2
if c.1.1 then
if a=c.2.1 then 1 else if a=c.1.2 then
((List.range (c.2.2.2.2.1+1)).map fun k=>term ((c,r),k)).sum
else read (c.2.2.1,(a,r))
else if a=c.2.1 then read (c.2.2.1,(c.2.1,c.2.2.2.2.2))
else read (c.2.2.1,(a,r))
variable {X Y : Type}
def tabulate (f : X×(ℕ×ℕ) → Y) (x : X×(ℕ×ℕ)) : List (List Y) :=
(List.range x.2.1).map fun a=>(List.range (x.2.2+1)).map fun r=>f (x.1,(a,r))
lemma read_eq (t : Table) (a r : ℕ) : read (t,(a,r))=UnitRefresh.Materialized.read t a r := rfl
lemma entry_eq {V : Type} {m : ℕ}
(bags : V → Finset (Fin m)) (R : Finset V) (parent : Fin m → Option (Fin m))
(l a : Fin m) (t : Table) (r : ℕ) :
entry (((match parent l with | none=>(false,0) | some p=>(true,p.val)),
(l.val,(t,(UnitRefresh.privateCount bags R l,
(UnitRefresh.sharedCount bags R l,(R.filter fun x=>l∈bags x).card))))),(a.val,r))=
UnitRefresh.Materialized.entry bags R parent l a t r := by
have he : (a.val=l.val) ↔ a=l := Fin.val_inj
cases hp : parent l with
| none => simp only [entry,UnitRefresh.Materialized.entry,hp,Bool.false_eq_true,↓reduceIte,he,read_eq]
| some p =>
have he' : (a.val=p.val) ↔ a=p := Fin.val_inj
simp only [entry,UnitRefresh.Materialized.entry,hp,↓reduceIte,he,he']
split_ifs <;> try rfl
lemma tabulate_eq {m B : ℕ} (f : ℕ×ℕ → ℕ) :
(List.range m).map (fun a=>(List.range (B+1)).map fun r=>f (a,r))=
UnitRefresh.Materialized.tabulate m B (fun a r=>f (a.val,r)) := by
unfold UnitRefresh.Materialized.tabulate
apply List.ext_getElem
· simp
· intro i hi hi'
simp only [List.getElem_map,List.getElem_range,List.getElem_ofFn]
apply List.ext_getElem
· simp
· intro j hj hj'
simp only [List.getElem_map,List.getElem_range,List.getElem_ofFn]
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeDPCounts
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped
abbrev Bag := List ℕ
abbrev Bags := List Bag
abbrev Parents := List (Bool×ℕ)
def privateFlag (x : ℕ×Bag) : Bool := decide (x.2.length=1) && decide (x.1∈x.2)
def sharedFlag (x : ℕ×Bag) : Bool := decide (x.1∈x.2) && !(privateFlag x)
def totalFlag (x : ℕ×Bag) : Bool := decide (x.1∈x.2)
def privateNumber (bs : Bags) (l : ℕ) := (bs.filter fun b=>privateFlag (l,b)).length
def sharedNumber (bs : Bags) (l : ℕ) := (bs.filter fun b=>sharedFlag (l,b)).length
def totalNumber (bs : Bags) (l : ℕ) := (bs.filter fun b=>totalFlag (l,b)).length
def trim (bs : Bags) (l : ℕ) := bs.filter fun b=>!(totalFlag (l,b))
def context (x : (Bags×Parents)×(ℕ×Table)) : EntryCtx :=
(x.1.2.getD x.2.1 (false,0),
(x.2.1,(x.2.2,(privateNumber x.1.1 x.2.1,
(sharedNumber x.1.1 x.2.1,totalNumber x.1.1 x.2.1)))))
variable {V : Type} [Fintype V] [DecidableEq V] {m : ℕ}
noncomputable def bagRep (b : Finset (Fin m)) : Bag := b.toList.map Fin.val
noncomputable def activeRep (bags : V → Finset (Fin m)) (R : Finset V) : Bags := R.toList.map (bagRep ∘ bags)
@[simp] lemma mem_bagRep (b : Finset (Fin m)) (l : Fin m) : l.val∈bagRep b ↔ l∈b := by
simp [bagRep,Fin.val_inj]
@[simp] lemma length_bagRep (b : Finset (Fin m)) : (bagRep b).length=b.card := by
simp [bagRep]
lemma card_one_mem (b : Finset (Fin m)) (l : Fin m) : b.card=1 ∧ l∈b ↔ b={l} := by
constructor
· rintro ⟨h,hl⟩
obtain ⟨a,ha⟩ := Finset.card_eq_one.mp h
have e : l=a := by simpa [ha] using hl
simpa [e] using ha
· rintro rfl; simp
@[simp] lemma privateFlag_bagRep (b : Finset (Fin m)) (l : Fin m) :
privateFlag (l.val,bagRep b)=decide (b={l}) := by
apply Bool.eq_iff_iff.mpr
simp [privateFlag,card_one_mem]
@[simp] lemma sharedFlag_bagRep (b : Finset (Fin m)) (l : Fin m) :
sharedFlag (l.val,bagRep b)=decide (l∈b ∧ b≠{l}) := by
apply Bool.eq_iff_iff.mpr
simp [sharedFlag,privateFlag_bagRep]
@[simp] lemma totalFlag_bagRep (b : Finset (Fin m)) (l : Fin m) :
totalFlag (l.val,bagRep b)=decide (l∈b) := by simp [totalFlag]
omit [Fintype V] [DecidableEq V] in
lemma filter_length_toList [Fintype V] [DecidableEq V]
(R : Finset V) (P : V → Prop) [DecidablePred P] :
(R.toList.filter fun x=>decide (P x)).length=(R.filter P).card := by
rw [←List.toFinset_card_of_nodup ((Finset.nodup_toList R).filter _)]
simp
@[simp] lemma privateNumber_activeRep (bags : V → Finset (Fin m)) (R : Finset V) (l : Fin m) :
privateNumber (activeRep bags R) l.val=UnitRefresh.privateCount bags R l := by
simp only [privateNumber,activeRep,List.filter_map,List.length_map,Function.comp_def,privateFlag_bagRep]
exact filter_length_toList R (fun x=>bags x={l})
@[simp] lemma sharedNumber_activeRep (bags : V → Finset (Fin m)) (R : Finset V) (l : Fin m) :
sharedNumber (activeRep bags R) l.val=UnitRefresh.sharedCount bags R l := by
simp only [sharedNumber,activeRep,List.filter_map,List.length_map,Function.comp_def,sharedFlag_bagRep]
exact filter_length_toList R (fun x=>l∈bags x ∧ bags x≠{l})
@[simp] lemma totalNumber_activeRep (bags : V → Finset (Fin m)) (R : Finset V) (l : Fin m) :
totalNumber (activeRep bags R) l.val=(R.filter fun x=>l∈bags x).card := by
simp only [totalNumber,activeRep,List.filter_map,List.length_map,Function.comp_def,totalFlag_bagRep]
exact filter_length_toList R (fun x=>l∈bags x)
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeSum
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A B C D : Type}
def sumRep [Inhabited A] [Inhabited B] : A⊕B→Bool×(A×B)
| .inl a => (true,(a,default))
| .inr b => (false,(default,b))
def optionRep [Inhabited A] : Option A→Bool×A
| none => (false,default)
| some a => (true,a)
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Plan
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh.Materialized
open Finset
variable {V : Type*} [Fintype V] [DecidableEq V]
def plan {m : ℕ} (rank : Fin m → ℕ) : List (Fin m) :=
(List.ofFn (fun l : Fin m => l)).mergeSort (fun a b=>decide (rank b ≤ rank a))
lemma plan_mem {m : ℕ} (rank : Fin m → ℕ) (a : Fin m) : a∈plan rank := by
unfold plan
rw [(List.mergeSort_perm _ _).mem_iff]
simp
lemma plan_length {m : ℕ} (rank : Fin m → ℕ) : (plan rank).length=m := by
unfold plan
rw [(List.mergeSort_perm _ _).length_eq]
simp
lemma plan_sorted {m : ℕ} (rank : Fin m → ℕ) :
(plan rank).Pairwise (fun a b=>rank b ≤ rank a) := by
let r := fun a b : Fin m => rank b ≤ rank a
let : Std.Total r := ⟨fun a b => le_total (rank b) (rank a)⟩
let : IsTrans (Fin m) r := ⟨fun a b c hab hbc => hbc.trans hab⟩
exact List.pairwise_mergeSort' r _
lemma plan_legal {m : ℕ} (bags : V → Finset (Fin m)) (rank : Fin m → ℕ)
(parent : Fin m → Option (Fin m)) (hb : RankedBags bags rank parent)
(hne : ∀ x,(bags x).Nonempty) (hp : ∀ l p,parent l=some p → rank p < rank l) :
LegalPlan bags parent (plan rank) univ := by
apply rank_order_legal bags rank parent hb hp _ (plan_sorted rank)
· intro x _; exact hne x
· intro x _ a _; exact plan_mem rank a
open Finset MatchingFPRAS.FiniteChoice
variable {n m : ℕ}
def validBranch (bags : Fin n → Finset (Fin m)) (a : Fin n) (bc : Fin n × Fin m) : Prop :=
bc.1≠a ∧ bc.2∈bags a ∧ bc.2∈bags bc.1
instance instDecidableValidBranch (bags : Fin n → Finset (Fin m)) (a : Fin n) (bc : Fin n × Fin m) :
Decidable (validBranch bags a bc) := inferInstanceAs (Decidable (_ ∧ _ ∧ _))
end MatchingFPRAS.UnitRefresh.Materialized
namespace MatchingFPRAS.UnitRefresh
open Finset
variable {U V L : Type*} [Fintype U] [Fintype V] [Fintype L] [DecidableEq U] [DecidableEq V] [DecidableEq L]
def gapEquiv {n : ℕ} (a : Fin (n+1)) : Fin n ≃ {x : Fin (n+1) // x≠a} :=
Equiv.optionSubtype a ⟨(finSuccEquiv' a).symm,rfl⟩
end MatchingFPRAS.UnitRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_RemainingBags
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh
open Finset MatchingFPRAS.Variation
def orderedEnum (α : Type*) [Fintype α] [LinearOrder α] : Fin (Fintype.card α) ≃ α :=
((univ : Finset α).orderIsoOfFin (card_univ)).toEquiv.trans
(Equiv.subtypeUnivEquiv (fun _=>mem_univ _))
variable {V L J : Type*} [Fintype V] [DecidableEq V] [Fintype L] [Fintype J] [DecidableEq L] [DecidableEq J]
open Finset MatchingFPRAS.Variation
variable {V L : Type*} [Fintype V] [LinearOrder V] [Fintype L] [LinearOrder L]
def numberedBags (bags : V → Finset L) : Fin (Fintype.card V) → Finset (Fin (Fintype.card L)) :=
fun x=>(bags (orderedEnum V x)).map (orderedEnum L).symm.toEmbedding
lemma mem_numberedBags (bags : V → Finset L) (x : Fin (Fintype.card V)) (l : Fin (Fintype.card L)) :
l∈numberedBags bags x ↔ orderedEnum L l∈bags (orderedEnum V x) := by
simp [numberedBags]
def numberedRank (rank : L → ℕ) : Fin (Fintype.card L) → ℕ := fun l=>rank (orderedEnum L l)
def numberedParent (parent : L → Option L) : Fin (Fintype.card L) → Option (Fin (Fintype.card L)) :=
fun l=>(parent (orderedEnum L l)).map (orderedEnum L).symm
lemma numberedParent_iff (parent : L → Option L) (l p : Fin (Fintype.card L)) :
numberedParent parent l=some p ↔ parent (orderedEnum L l)=some (orderedEnum L p) := by
simp [numberedParent,Equiv.symm_apply_eq]
lemma numberedRanked (bags : V → Finset L) (rank : L → ℕ) (parent : L → Option L)
(hb : RankedBags bags rank parent) :
RankedBags (numberedBags bags) (numberedRank rank) (numberedParent parent) := by
intro x a ha b hb' hab
rcases hb (orderedEnum V x) (orderedEnum L a) ((mem_numberedBags bags x a).mp ha)
(orderedEnum L b) ((mem_numberedBags bags x b).mp hb')
(fun h=>hab ((orderedEnum L).injective h)) with ⟨hlt,hp⟩|⟨hlt,hp⟩
· exact Or.inl ⟨hlt,(numberedParent_iff parent b a).mpr hp⟩
· exact Or.inr ⟨hlt,(numberedParent_iff parent a b).mpr hp⟩
lemma numberedNonempty (bags : V → Finset L) (hne : ∀ x,(bags x).Nonempty) :
∀ x,(numberedBags bags x).Nonempty := fun x=>(hne (orderedEnum V x)).map
lemma numberedDecreasing (rank : L → ℕ) (parent : L → Option L)
(hp : ∀ l p,parent l=some p → rank p < rank l) :
∀ l p,numberedParent parent l=some p → numberedRank rank p<numberedRank rank l := by
intro l p h; exact hp _ _ ((numberedParent_iff parent l p).mp h)
open MatchingFPRAS.Transport
end MatchingFPRAS.UnitRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Sym2Order
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
open Finset Replica Replica.Ladder Variation
variable {V L : Type*} [Fintype V] [LinearOrder V] [Fintype L] [LinearOrder L]
def rationalTierBase (V : Type*) [Fintype V] : ℚ := 1+((Fintype.card V:ℚ)^2)⁻¹
omit [LinearOrder V] in
lemma rationalTierBase_cast : (rationalTierBase V:ℝ)=tierBase V := by
simp [rationalTierBase,tierBase]
end MatchingFPRAS.Transport
namespace MatchingFPRAS.Transport
open Finset Replica Replica.Ladder Variation
variable {V L : Type*} [Fintype V] [LinearOrder V] [Fintype L] [LinearOrder L]
variable {bags : V → Finset L}
open Finset Replica Replica.Ladder Variation
variable {V L : Type*} [Fintype V] [LinearOrder V] [Fintype L] [LinearOrder L]
variable {bags : V → Finset L} {G : SimpleGraph L}
@[instance_reducible] def prodOrder {A B : Type*} [LinearOrder A] [LinearOrder B] :
LinearOrder (A×B) := LinearOrder.lift' toLex toLex.injective
@[instance_reducible] def sumOrder {A B : Type*} [LinearOrder A] [LinearOrder B] :
LinearOrder (A⊕B) := LinearOrder.lift' toLex toLex.injective
attribute [local instance] prodOrder sumOrder
variable (hbags : ∀ v,∀ a∈bags v,∀ b∈bags v,a=b ∨ G.Adj a b) (hG : G.IsAcyclic)
variable (rank : L → ℕ) (parent : L → Option L)
variable (hb : UnitRefresh.RankedBags bags rank parent) (hne : ∀ v,(bags v).Nonempty)
variable (hp : ∀ l p,parent l=some p → rank p < rank l)
abbrev LocalBits (V : Type*) [Fintype V] (k : ℕ) :=
(Fin k → Bool) × (Fin (Fintype.card V) → Fin k → Bool)
abbrev ScanBits (V : Type*) [Fintype V] (k : ℕ) := (Fin k → Bool) × LocalBits V k
open Finset Replica Replica.Ladder Variation
def bitPrecision (R : ℕ) (η : ℚ) : ℕ := Nat.clog 2 (R*⌈η⁻¹⌉₊)
def pairBitsEquiv (m n : ℕ) : (Fin (m+n) → Bool) ≃ ((Fin m → Bool) × (Fin n → Bool)) :=
(Equiv.arrowCongr finSumFinEquiv.symm (Equiv.refl Bool)).trans
(Equiv.sumArrowEquivProdArrow _ _ _)
def matrixBitsEquiv (m n : ℕ) : (Fin (m*n) → Bool) ≃ (Fin m → Fin n → Bool) :=
(Equiv.arrowCongr finProdFinEquiv.symm (Equiv.refl Bool)).trans (Equiv.curry _ _ _)
def scanBitCount (N k : ℕ) : ℕ := k+(k+N*k)
def scanBitsEquiv (V : Type*) [Fintype V] (k : ℕ) :
(Fin (scanBitCount (Fintype.card V) k) → Bool) ≃ ScanBits V k :=
(pairBitsEquiv k (k+Fintype.card V*k)).trans
(Equiv.prodCongr (Equiv.refl _) ((pairBitsEquiv k (Fintype.card V*k)).trans
(Equiv.prodCongr (Equiv.refl _) (matrixBitsEquiv (Fintype.card V) k))))
def runBitsEquiv (V : Type*) [Fintype V] (k n : ℕ) :
(Fin (n*scanBitCount (Fintype.card V) k) → Bool) ≃ (Fin n → ScanBits V k) :=
(matrixBitsEquiv n _).trans (Equiv.piCongrRight fun _=>scanBitsEquiv V k)
attribute [local instance] prodOrder sumOrder
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_DiscreteLadderSteps
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
open Finset Replica Replica.Ladder Variation
def discreteLadderSteps (N D K T m : ℕ) : ℕ :=
20*ladderL N D*ladderM N D T*(ladderLambda N D K T+Nat.clog 2 m+1)
attribute [local instance] prodOrder sumOrder
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_OnlineScheduleNat
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A : Type}
lemma clog_two_size_pred (n : ℕ) : Nat.clog 2 n=Nat.size (n-1) := by
apply Nat.le_antisymm
· apply Nat.clog_le_of_le_pow
have hp:=Nat.lt_size_self (n-1)
omega
· apply Nat.size_le.mpr
have hp:=Nat.le_pow_clog (by decide : 1<2) n
have hpos:=Nat.two_pow_pos (Nat.clog 2 n)
omega
end MatchingFPRAS.TreeTyped
namespace MatchingFPRAS.OnlineSchedule
open TreeTyped Transport
abbrev ScanInput := ((ℕ×ℕ)×(ℕ×ℕ))×ℕ
end MatchingFPRAS.OnlineSchedule
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_AdaptiveStream
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.PhysicalStream
open Finset
abbrev Bits (n : ℕ) := Fin n → Bool
abbrev Stream := ℕ → Bool
def shift (n : ℕ) (b : Stream) : Stream := fun i => b (n+i)
@[simp] lemma shift_zero (b : Stream) : shift 0 b=b := by funext i; simp [shift]
def extend {n : ℕ} (b : Bits n) : Stream := fun i => if h : i<n then b ⟨i,h⟩ else false
def concat {n m : ℕ} (a : Bits n) (b : Bits m) : Bits (n+m) := Fin.append a b
def split (n m : ℕ) : Bits (n+m) ≃ Bits n × Bits m where
toFun b := (fun i=>b (Fin.castAdd m i), fun j=>b (Fin.natAdd n j))
invFun b := concat b.1 b.2
left_inv b := by funext i; exact Fin.addCases (by simp [concat]) (by simp [concat]) i
right_inv b := by ext i <;> simp [concat]
@[simp] lemma concat_left {n m : ℕ} (a : Bits n) (b : Bits m) (i : Fin n) :
concat a b (Fin.castAdd m i)=a i := by simp [concat]
@[simp] lemma concat_right {n m : ℕ} (a : Bits n) (b : Bits m) (i : Fin m) :
concat a b (Fin.natAdd n i)=b i := by simp [concat]
noncomputable def average {n : ℕ} (f : Bits n → ℚ) : ℚ :=
(∑ b,f b)/(2:ℚ)^n
inductive Experiment (α : Type) where
| done (a : α)
| read (next : Bool → Experiment α)
| delay (ticks : ℕ) (next : Experiment α)
namespace Experiment
variable {α β : Type}
def cost : Experiment α → ℕ
| .done _ => 0
| .read f => 1+max (cost (f false)) (cost (f true))
| .delay n p => n+cost p
def run : Experiment α → Stream → α × ℕ
| .done a,_ => (a,0)
| .read f,b => let r := run (f (b 0)) (shift 1 b); (r.1,1+r.2)
| .delay n p,b => let r := run p (shift n b); (r.1,n+r.2)
def mean : Experiment α → (α → ℚ) → ℚ
| .done a,f => f a
| .read p,f => (mean (p false) f+mean (p true) f)/2
| .delay _ p,f => mean p f
def bind : Experiment α → (α → Experiment β) → Experiment β
| .done a,f => f a
| .read p,f => .read (fun b=>(p b).bind f)
| .delay n p,f => .delay n (p.bind f)
lemma mean_bind (p : Experiment α) (q : α → Experiment β) (f : β → ℚ) :
(p.bind q).mean f=p.mean (fun a=>(q a).mean f) := by
induction p with
| done a => rfl
| read p ih => simp [bind,mean,ih]
| delay n p ih => exact ih
lemma cost_bind_le (p : Experiment α) (q : α → Experiment β) (N : ℕ)
(hq : ∀ a,(q a).cost ≤ N) : (p.bind q).cost ≤ p.cost+N := by
induction p with
| done a => simpa only [bind,cost,Nat.zero_add] using hq a
| read p ih =>
simp only [bind,cost]
have h0:=ih false
have h1:=ih true
omega
| delay n p ih => simpa only [bind,cost,Nat.add_assoc] using Nat.add_le_add_left ih n
def map (f : α → β) (p : Experiment α) : Experiment β := p.bind (fun a=>.done (f a))
@[simp] lemma cost_map (f : α → β) (p : Experiment α) : (p.map f).cost=p.cost := by
induction p with
| done a => rfl
| read p ih => simp only [map,bind,cost]; change 1+max ((p false).map f).cost ((p true).map f).cost=_; rw [ih false,ih true]
| delay n p ih => change n+(p.map f).cost=n+p.cost; rw [ih]
lemma mean_map (f : α → β) (p : Experiment α) (g : β → ℚ) :
(p.map f).mean g=p.mean (fun a=>g (f a)) := by simp [map,mean_bind,mean]
def word : (n : ℕ) → Experiment (Bits n)
| 0 => .done Fin.elim0
| n+1 => .read (fun b=>(word n).map (Fin.cons b))
@[simp] lemma cost_word (n : ℕ) : (word n).cost=n := by
induction n with
| zero => rfl
| succ n ih => simp only [word,cost,cost_map,ih,max_self]; omega
end Experiment
end MatchingFPRAS.PhysicalStream
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_PhysicalPost
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.PhysicalPost
open Turing PhysicalStream
variable {Γ Q R : Type} [Inhabited Γ]
variable [Fintype Q] [Inhabited Q]
noncomputable def enumeration : Q ≃ Fin (Fintype.card Q-1+1) := by
let e : Q ≃ Fin (Fintype.card Q-1+1) := Fintype.equivFinOfCardEq
(Nat.sub_add_cancel Fintype.card_pos).symm
exact e.trans (Equiv.swap (e default) 0)
@[simp] lemma enumeration_default : enumeration (Q:=Q) default=0 := by
classical
simp only [enumeration,Equiv.trans_apply,Equiv.swap_apply_left]
end MatchingFPRAS.PhysicalPost
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_OnlineStackCompiler
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineStack
open Turing MachineCost PhysicalStream
open scoped Classical
variable {K Λ σ : Type} {Γ : K → Type} [DecidableEq K] [Fintype K]
[∀ k,Fintype (Γ k)] [Inhabited Λ] [Fintype Λ] [Inhabited σ] [Fintype σ]
abbrev Alpha (K : Type) (Γ : K → Type) := TM2to1.Γ' K Γ
abbrev L1 (K : Type) (Γ : K → Type) (Λ σ : Type) := TM2to1.Λ' K Γ Λ σ
abbrev L2 (K : Type) (Γ : K → Type) (Λ σ : Type) := TM1to1.Λ' (Alpha K Γ) (L1 K Γ Λ σ) σ
noncomputable def height (S : ∀ k,List (Γ k)) : ℕ := Finset.univ.sup (fun k=>(S k).length)
noncomputable def stackCfg (c : TM2.Cfg Γ Λ σ) : TM1.Cfg (Alpha K Γ) (L1 K Γ Λ σ) σ :=
⟨c.l.map TM2to1.Λ'.normal,c.var,Tape.mk₁ (StackWords.word c.stk (height c.stk))⟩
variable (M : Λ → TM2.Stmt Γ Λ σ)
noncomputable def program1 := TM2to1.tr M
noncomputable def enc := FixedEncoding.enc (Alpha K Γ)
noncomputable def dec := FixedEncoding.dec (Alpha K Γ)
lemma enc0 : enc (K:=K) (Γ:=Γ) default=List.Vector.replicate (Fintype.card (Alpha K Γ)) false :=
FixedEncoding.blank (Alpha K Γ)
noncomputable def program2 := TM1to1.tr (enc (K:=K) (Γ:=Γ)) dec (program1 M)
noncomputable def support1 := TM2to1.trSupp M Finset.univ
noncomputable def support2 := TM1to1.trSupp (program1 M) (support1 M)
omit [Fintype K] [∀ k,Fintype (Γ k)] [Inhabited σ] [Fintype σ] in
lemma supports1 [Fintype K] [∀ k,Fintype (Γ k)] [Inhabited σ] [Fintype σ] :
TM1.Supports (program1 M) (support1 M) :=
TM2to1.tr_supports M (StackComposition.supports_univ M)
lemma supports2 : TM1.Supports (program2 M) (support2 M) :=
TM1to1.tr_supports enc dec (program1 M) (supports1 M)
noncomputable def accesses : ℕ := Finset.univ.sup (fun l=>StackCost.accesses (M l))
end MatchingFPRAS.OnlineStack
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_ExperimentSupport
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.PhysicalStream.Experiment
variable {α β : Type}
def All : Experiment α → (α → Prop) → Prop
| .done a,P => P a
| .read f,P => All (f false) P ∧ All (f true) P
| .delay _ p,P => All p P
lemma All.mono {p : Experiment α} {P Q : α → Prop} (h : All p P) (hPQ : ∀ a,P a→Q a) : All p Q := by
induction p with
| done a => exact hPQ a h
| read p ih => exact ⟨ih false h.1,ih true h.2⟩
| delay n p ih => exact ih h
lemma mean_nonneg (p : Experiment α) (f : α → ℚ) (h : All p (fun a=>0≤f a)) : 0≤p.mean f := by
induction p with
| done a => exact h
| read p ih => exact div_nonneg (add_nonneg (ih false h.1) (ih true h.2)) (by norm_num)
| delay n p ih => exact ih h
lemma all_true (p : Experiment α) : All p (fun _=>True) := by
induction p with
| done a => trivial
| read p ih => exact ⟨ih false,ih true⟩
| delay n p ih => exact ih
lemma all_indicator (p : Experiment α) (P : α → Prop) [DecidablePred P] :
All p P ↔ p.mean (fun a=>if P a then 0 else 1)=0 := by
induction p with
| done a => simp [All,mean]
| delay n p ih => exact ih
| read p ih =>
have hz (b : Bool) : 0≤(p b).mean (fun a=>if P a then 0 else 1) :=
mean_nonneg _ _ ((all_true _).mono (by intro a _; split <;> norm_num))
simp only [All,mean,ih]
constructor
· rintro ⟨h0,h1⟩; rw [h0,h1]; norm_num
· intro h
have h0:=hz false
have h1:=hz true
constructor <;> linarith
lemma all_of_mean_eq {p q : Experiment α} (h : ∀ f : α → ℚ,q.mean f=p.mean f)
(P : α → Prop) (hp : All p P) : All q P := by
classical
rw [all_indicator,h,←all_indicator]
exact hp
lemma cost_bind_le_of_all (p : Experiment α) (q : α → Experiment β) (N : ℕ)
(h : All p (fun a=>(q a).cost≤N)) : (p.bind q).cost≤p.cost+N := by
induction p with
| done a => simpa only [All,bind,cost,Nat.zero_add] using h
| read p ih =>
have h0:=ih false h.1
have h1:=ih true h.2
simp only [cost,bind]
omega
| delay n p ih => simpa only [bind,cost,Nat.add_assoc] using Nat.add_le_add_left (ih h) n
variable {α : Type}
def worst : Experiment α → (α → ℕ) → ℕ
| .done a,f => f a
| .read p,f => max (worst (p false) f) (worst (p true) f)
| .delay _ p,f => worst p f
lemma all_worst (p : Experiment α) (f : α → ℕ) : All p (fun a=>f a≤p.worst f) := by
induction p with
| done a => exact le_rfl
| read p ih => exact ⟨(ih false).mono (fun a ha=>ha.trans (le_max_left _ _)),
(ih true).mono (fun a ha=>ha.trans (le_max_right _ _))⟩
| delay n p ih => exact ih
end MatchingFPRAS.PhysicalStream.Experiment
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_OnlineFold
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineTree
open TreeTyped
open Turing MachineCost PhysicalStream OnlineStack
variable {A B : Type}
def foldM (f : A×B → Experiment B) : List A → B → Experiment B
| [],b => .done b
| a::as,b => (f (a,b)).bind (foldM f as)
end MatchingFPRAS.OnlineTree
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_OnlineFrame
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineTree
open TreeTyped
open Turing MachineCost PhysicalStream OnlineStack
variable {A B C D : Type}
namespace Second
inductive Point where | split | save | body | pop | cons | halt
deriving DecidableEq, Inhabited
instance instFintypePoint : Fintype Point := ⟨{.split,.save,.body,.pop,.cons,.halt},by intro p; cases p <;> simp⟩
end Second
end MatchingFPRAS.OnlineTree
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_OnlineTraverse
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineTree
open PhysicalStream TreeTyped
variable {A B C : Type}
def traverseM (f : A → Experiment B) : List A → Experiment (List B)
| [] => .done []
| a::as => (f a).bind (fun b=>(traverseM f as).map (List.cons b))
def collectStep (f : A → Experiment B) (x : A×List B) : Experiment (List B) :=
(f x.1).map (fun b=>b::x.2)
end MatchingFPRAS.OnlineTree
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_OnlineWord
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineWord
open PhysicalStream TreeTyped OnlineTree
def prepend : ℕ → List Bool → Experiment (List Bool)
| 0,acc => .done acc
| n+1,acc => .read (fun b=>prepend n (b::acc))
def reverseBits (n : ℕ) : Bits n ≃ Bits n where
toFun w i:=w i.rev
invFun w i:=w i.rev
left_inv w:=by funext i; simp
right_inv w:=by funext i; simp
def step (x : ℕ×List Bool) : Experiment (List Bool) := .read (fun b=>.done (b::x.2))
lemma fold_step (as : List ℕ) (acc : List Bool) :
OnlineTree.foldM step as acc=prepend as.length acc := by
induction as generalizing acc with
| nil => rfl
| cons a as ih => simp only [OnlineTree.foldM,step,Experiment.bind,ih,List.length_cons,prepend]
end MatchingFPRAS.OnlineWord
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_OnlineUniform
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.PhysicalStream
open Finset
variable {A B C : Type} [Fintype A] [Fintype B]
noncomputable def qaverage (f : A → ℚ) : ℚ := (∑ a,f a)/Fintype.card A
def splitFunction (n : ℕ) (A : Type) : (Fin (n+1) → A) ≃ A×(Fin n → A) where
toFun f := (f 0,fun i=>f i.succ)
invFun f := Fin.cons f.1 f.2
left_inv f := by funext i; refine Fin.cases ?_ ?_ i <;> simp
right_inv f := by rcases f with ⟨a,f⟩; rfl
end MatchingFPRAS.PhysicalStream
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_Related2
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumberedHierarchy
open Finset
variable {V : Type*} [Fintype V] [LinearOrder V]
variable (B : V → V → ℚ)
def related (t : ℚ) (x y : V) : Prop := x=y ∨ t≤B x y
instance relatedDec (t : ℚ) (x y : V) : Decidable (related B t x y) :=
inferInstanceAs (Decidable (x=y ∨ t≤B x y))
def component (t : ℚ) (x : V) : Finset V := univ.filter (related B t x)
lemma component_self (t : ℚ) (x : V) : x∈component B t x := by simp [component,related]
def root (t : ℚ) (x : V) : V := (component B t x).min' ⟨x,component_self B t x⟩
lemma root_mem (t : ℚ) (x : V) : root B t x ∈ component B t x := min'_mem _ _
lemma related_root (t : ℚ) (x : V) : related B t x (root B t x) := by
simpa [component] using root_mem B t x
variable (hsym : ∀ x y,B x y=B y x)
variable (htri : ∀ x y z,x≠y → x≠z → y≠z → min (B x z) (B z y)≤B x y)
include hsym in
omit [Fintype V] [LinearOrder V] in
lemma symmetric [Fintype V] [LinearOrder V] : ∀ x y,(B x y:ℝ)=(B y x:ℝ) := by intro x y; rw [hsym]
include htri in
omit [Fintype V] [LinearOrder V] in
lemma triangular [Fintype V] [LinearOrder V] : ∀ x y z,x≠y → x≠z → y≠z →
min (B x z:ℝ) (B z y:ℝ)≤(B x y:ℝ) := by
intro x y z hxy hxz hyz
exact_mod_cast htri x y z hxy hxz hyz
include hsym in
omit [Fintype V] [LinearOrder V] in
lemma related_symm [Fintype V] [LinearOrder V] (t : ℚ) {x y : V}
(hxy : related B t x y) : related B t y x := by
rcases hxy with rfl|h
· exact Or.inl rfl
· exact Or.inr (by rwa [hsym])
abbrev NumberedComponent (t : ℚ) := {x : V // root B t x=x}
def level (H : ℕ) (x : ℚ) : Fin (H+1) :=
⟨Nat.findGreatest (fun k => (2:ℚ)^k≤x) H,Nat.lt_succ_of_le (Nat.findGreatest_le H)⟩
abbrev Label (H : ℕ) := (k : Fin (H+1)) × NumberedComponent B ((2:ℚ)^k.val)
def member {H : ℕ} (l : Label B H) (x : V) : Prop := root B ((2:ℚ)^l.1.val) x=l.2.val
instance memberDec {H : ℕ} (l : Label B H) (x : V) : Decidable (member B l x) :=
inferInstanceAs (Decidable (root B _ x=l.2.val))
lemma member_self {H : ℕ} (l : Label B H) : member B l l.2.val := l.2.property
end MatchingFPRAS.NumberedHierarchy
namespace MatchingFPRAS.RationalSource
open MatchingFPRAS Switching Subdivision Finset
variable {V : Type*} [Fintype V] [LinearOrder V] [Nontrivial V]
def profile (p : ℕ) (B Hu Hv lam : ℚ) (i : Fin (4*p+1)) : ℚ :=
if i.val<2*p then max B (Hu/2^(i.val/2))
else if i.val=2*p then lam else max B (Hv/2^((4*p-i.val)/2))
end MatchingFPRAS.RationalSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_LabelOrder
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumberedHierarchy
open Finset MatchingFPRAS.UnitRefresh
variable {V : Type*} [Fintype V] [LinearOrder V]
variable (B : V → V → ℚ) (hsym : ∀ x y,B x y=B y x)
variable (htri : ∀ x y z,x≠y → x≠z → y≠z → min (B x z) (B z y)≤B x y)
@[instance_reducible] def labelOrder (H : ℕ) : LinearOrder (Label B H) :=
LinearOrder.lift' (fun l : Label B H=>toLex (l.1,l.2.val)) (by
intro a b h
have h' := toLex.injective h
obtain ⟨k,a⟩:=a
obtain ⟨j,b⟩:=b
have hk : k=j:=congrArg Prod.fst h'
cases hk
exact congrArg (Sigma.mk k) (Subtype.ext (congrArg Prod.snd h')))
attribute [local instance] labelOrder
end MatchingFPRAS.NumberedHierarchy
namespace MatchingFPRAS.Transport
open Finset MatchingFPRAS.Replica MatchingFPRAS.Replica.Ladder
variable {V J : Type*} [Fintype V] [DecidableEq V] [Fintype J] [DecidableEq J]
variable {bags : V → Finset J}
open Finset Replica Replica.Ladder Variation
def rationalBase (N : ℕ) : ℚ := 1+((N:ℚ)^2)⁻¹
lemma rationalBase_cast (N : ℕ) : (rationalBase N:ℝ)=1+((N:ℝ)^2)⁻¹ := by
simp [rationalBase]
lemma reaches_cast (N D K t : ℕ) :
max (D:ℚ) (3*4^K)≤(rationalBase N)^t ↔
max (D:ℝ) (3*4^K)≤(1+((N:ℝ)^2)⁻¹)^t := by
rw [←rationalBase_cast]
exact_mod_cast (Iff.rfl : max (D:ℚ) (3*4^K)≤(rationalBase N)^t ↔ _)
def endpoint (N D K : ℕ) (hN : 0<N) : ℕ :=
((range (tierBound N D K+1)).filter
(fun t => max (D:ℚ) (3*4^K)≤(rationalBase N)^t)).min'
(by refine ⟨tierBound N D K,mem_filter.mpr ⟨mem_range.mpr (by omega),?_⟩⟩
exact (reaches_cast _ _ _ _).mpr (tierBound_reaches N D K hN))
lemma endpoint_eq (N D K : ℕ) (hN : 0<N) : endpoint N D K hN=ladderTier N D K hN := by
apply Nat.le_antisymm
· apply min'_le
apply mem_filter.mpr
exact ⟨mem_range.mpr (by have := ladderTier_le N D K hN; omega),
(reaches_cast _ _ _ _).mpr (ladderTier_spec N D K hN)⟩
· have he : max (D:ℝ) (3*4^K)≤(1+((N:ℝ)^2)⁻¹)^(endpoint N D K hN) := by
apply (reaches_cast _ _ _ _).mp
unfold endpoint
exact (mem_filter.mp (min'_mem ((range (tierBound N D K+1)).filter
(fun t => max (D:ℚ) (3*4^K)≤(rationalBase N)^t)) _)).2
unfold ladderTier
exact Nat.find_min' _ he
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Relabel
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
open Finset
variable {V L J : Type*} [Fintype V] [DecidableEq V] [Fintype L] [DecidableEq L]
[Fintype J] [DecidableEq J]
variable {b : V → Finset L} {c : V → Finset J}
omit [Fintype V] [DecidableEq V] [Fintype L] [Fintype J] in
lemma image_symm_bags (e : L ≃ J) (h : ∀ v,(b v).image e=c v) (v : V) :
(c v).image e.symm=b v := by
rw [←h v,image_image]
simp
end MatchingFPRAS.Transport
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_CompleteGraph
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS
@[reducible] noncomputable def completeGraph (n : ℕ) : GraphInput where
n := n
edges := by
classical
exact Finset.univ.filter (fun e => e.1 < e.2)
increasing := by
classical
intro e he
exact (Finset.mem_filter.mp he).2
noncomputable def rawWeight (G : GraphInput) (x : ℚ) (M : Finset (Fin G.n × Fin G.n)) : ℚ :=
∏ e ∈ M, if e ∈ G.edges then 1 else x
noncomputable def rawPartition (G : GraphInput) (x : ℚ) : ℚ :=
∑ M ∈ perfectMatchings (completeGraph G.n), rawWeight G x M
end MatchingFPRAS
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_RatWeight
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
noncomputable section
namespace MatchingFPRAS.RealStage
open Finset
lemma others_nonempty {n : ℕ} (hn : 2 ≤ n) (i : Fin n) : (univ.erase i).Nonempty := by
let j : Fin n := ⟨if i.val=0 then 1 else 0, by split_ifs <;> omega⟩
refine ⟨j,mem_erase.mpr ⟨?_,mem_univ _⟩⟩
apply Fin.ne_of_val_ne
dsimp [j]; split_ifs <;> omega
def rowMaximum {n : ℕ} (hn : 2 ≤ n) (G : Fin n → Fin n → ℝ) (v : Fin n → ℝ) (i : Fin n) : ℝ :=
(univ.erase i).sup' (others_nonempty hn i) (fun j => G i j / v j)
def scaleUpdate {n : ℕ} (hn : 2 ≤ n) (G : Fin n → Fin n → ℝ) (v : Fin n → ℝ) (i : Fin n) : Fin n → ℝ :=
Function.update v i (rowMaximum hn G v i)
def scalingTrace {n : ℕ} (hn : 2 ≤ n) (G : Fin n → Fin n → ℝ) : ℕ → Fin n → ℝ
| 0 => fun _ => 2
| k+1 => if hk : k<n then scaleUpdate hn G (scalingTrace hn G k) ⟨k,hk⟩ else scalingTrace hn G k
open Finset
end MatchingFPRAS.RealStage
end
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_RowPeak
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
noncomputable section
namespace MatchingFPRAS.RealStage
open Finset
variable {n : ℕ}
open Finset
def rowPeak {n : ℕ} (hn : 2 ≤ n) (g : Fin n → Fin n → ℝ) (i : Fin n) : ℝ :=
(univ.erase i).sup' (others_nonempty hn i) (g i)
def scaledHoleMatrix {n : ℕ} (g : Fin n → Fin n → ℝ) (v : Fin n → ℝ) (i j : Fin n) : ℝ :=
g i j/(v i*v j)
def BalancedRows {n : ℕ} (hn : 2 ≤ n) (g : Fin n → Fin n → ℝ) : Prop :=
∀ i, (1:ℝ)/4 ≤ rowPeak hn g i ∧ rowPeak hn g i ≤ 1
end MatchingFPRAS.RealStage
end
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Endpoints
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.GraphBridge
open Finset MatchingFPRAS.Subdivision MatchingFPRAS.Switching
variable {n : ℕ}
noncomputable def rawActivity (G : GraphInput) (x : ℝ) (a b : Fin G.n) : ℝ :=
if (min a b,max a b)∈G.edges then 1 else x
lemma rawActivity_pos (G : GraphInput) (x : ℝ) (hx : 0 < x) : ∀ a b,0 < rawActivity G x a b := by
intro a b
unfold rawActivity
split_ifs <;> positivity
end MatchingFPRAS.GraphBridge
namespace MatchingFPRAS.Trial
open Finset Switching Subdivision Hierarchy Transport
open scoped Classical
noncomputable def cooling (n : ℕ) : ℝ := (1+1/(n:ℝ))⁻¹
lemma cooling_pos (n : ℕ) : 0 < cooling n := by unfold cooling; positivity
lemma cooling_le_one (n : ℕ) : cooling n ≤ 1 := by
unfold cooling
apply inv_le_one_of_one_le₀
have h : (0:ℝ) ≤ 1/(n:ℝ) := by positivity
linarith
noncomputable def raw (G : GraphInput) (j : ℕ) : Fin G.n → Fin G.n → ℝ :=
GraphBridge.rawActivity G (cooling G.n^j)
lemma raw_pos (G : GraphInput) (j : ℕ) (a b : Fin G.n) : 0 < raw G j a b :=
GraphBridge.rawActivity_pos G _ (pow_pos (cooling_pos G.n) j) a b
lemma raw_le_one (G : GraphInput) (j : ℕ) (a b : Fin G.n) : raw G j a b ≤ 1 := by
unfold raw GraphBridge.rawActivity
split_ifs
· rfl
· exact pow_le_one₀ (cooling_pos G.n).le (cooling_le_one G.n)
lemma raw_cooling (G : GraphInput) (j : ℕ) (a b : Fin G.n) :
cooling G.n*raw G j a b ≤ raw G (j+1) a b ∧ raw G (j+1) a b ≤ raw G j a b := by
unfold raw GraphBridge.rawActivity
split_ifs
· simpa using And.intro (cooling_le_one G.n) (le_refl (1:ℝ))
· rw [pow_succ]
constructor
· exact le_of_eq (mul_comm _ _)
· have h := mul_le_mul_of_nonneg_left (cooling_le_one G.n) (pow_pos (cooling_pos G.n) j).le
simpa using h
lemma raw_zero (G : GraphInput) : raw G 0=(fun _ _=>1) := by
funext a b
simp [raw,GraphBridge.rawActivity]
structure ScaleState (G : GraphInput) (j : ℕ) where
scale : Fin G.n → ℝ
positive : ∀ i,0 < scale i
upper : ∀ i,scale i ≤ (2:ℝ)^j
variable {G : GraphInput} {j K S : ℕ}
noncomputable def ScaleState.activity (s : ScaleState G j) : Fin G.n → Fin G.n → ℝ :=
fun a b => raw G j a b*s.scale a*s.scale b
noncomputable def ScaleState.nextActivity (s : ScaleState G j) : Fin G.n → Fin G.n → ℝ :=
fun a b => raw G (j+1) a b*s.scale a*s.scale b
lemma ScaleState.activity_pos (s : ScaleState G j) (a b : Fin G.n) : 0 < s.activity a b :=
mul_pos (mul_pos (raw_pos G j a b) (s.positive a)) (s.positive b)
lemma ScaleState.nextActivity_pos (s : ScaleState G j) (a b : Fin G.n) : 0 < s.nextActivity a b :=
mul_pos (mul_pos (raw_pos G (j+1) a b) (s.positive a)) (s.positive b)
lemma ScaleState.cooling (s : ScaleState G j) (a b : Fin G.n) :
cooling G.n*s.activity a b ≤ s.nextActivity a b ∧ s.nextActivity a b ≤ s.activity a b := by
have h := raw_cooling G j a b
constructor
· have hh := mul_le_mul_of_nonneg_right (mul_le_mul_of_nonneg_right h.1 (s.positive a).le) (s.positive b).le
simpa [ScaleState.activity,ScaleState.nextActivity,mul_assoc] using hh
· exact mul_le_mul_of_nonneg_right (mul_le_mul_of_nonneg_right h.2 (s.positive a).le) (s.positive b).le
lemma ScaleState.activity_bound (s : ScaleState G j) (a b : Fin G.n) : s.activity a b ≤ (4:ℝ)^j := by
calc
_ ≤ 1*(2:ℝ)^j*2^j := by
apply mul_le_mul (mul_le_mul (raw_le_one G j a b) (s.upper a) (s.positive a).le (by norm_num))
(s.upper b) (s.positive b).le (by positivity)
_ = (4:ℝ)^j := by rw [one_mul,←mul_pow]; norm_num
noncomputable def initialScaleState (G : GraphInput) (hn : 2 ≤ G.n) : ScaleState G 0 where
scale _ := (Initializer.initialScale G.n:ℝ)
positive _ := by exact_mod_cast Initializer.initialScale_pos G.n hn
upper _ := by
unfold Initializer.initialScale
push_cast
simp only [pow_zero]
have hs : 1 ≤ Nat.sqrt (G.n-1) := Nat.le_sqrt.mpr (by omega)
have hs' : (1:ℝ) ≤ Nat.sqrt (G.n-1) := by exact_mod_cast hs
simpa using one_div_le_one_div_of_le (by norm_num : (0:ℝ)<1) hs'
end MatchingFPRAS.Trial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TableMarking
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TableMarking
open Finset Transport Variation
variable {V E I : Type*} [Fintype V] [Fintype E] [DecidableEq E] [Fintype I] [DecidableEq I]
variable (inc : E → V → Prop)
variable {A : Type*} [Fintype A] [Nonempty A]
noncomputable def portion (c : E → WeightedOptions I) (e : E) (i : I) : ℝ := (c e).law i
end MatchingFPRAS.TableMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Complexity_TreePolynomialGrid
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
open Polynomial
variable {A B : Type}
variable {m n : A → ℕ} {f : A×(ℕ×ℕ) → B}
def clip (x : ℕ×ℕ) : ℕ := if x.2.size≤x.1 then x.2 else 0
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeListMore
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A B X : Type}
def listMin (x : List ℕ×ℕ) : ℕ := x.1.foldl min x.2
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeCategorical
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
def bitDenominator (bs : List Bool) : ℕ := bs.foldl (fun a _=>2*a) 1
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeQuad
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
variable {A B : Type}
abbrev Quad (A : Type) := (A×A)×(A×A)
def quadList (q : Quad A) : List A := [q.1.1,q.1.2,q.2.1,q.2.2]
def quadFn (q : Quad A) : Fin 4→A := ![q.1.1,q.1.2,q.2.1,q.2.2]
def quadOfFn (f : Fin 4→A) : Quad A := ((f 0,f 1),(f 2,f 3))
def quads (s : List A) : List (Quad A) := (s.product s).product (s.product s)
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeGeometry
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableSource
open TreeTyped Polynomial
abbrev GeometryInput := List ℕ×List Bool
def internalCount (x : GeometryInput) : ℕ := 4*x.2.length
end MatchingFPRAS.ExecutableSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeBottleneck
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableBottleneck
open TreeTyped Polynomial
def square {A B : Type} (n : ℕ) (a : A) (f : A×(ℕ×ℕ)→B) : List (List B) :=
(List.range n).map fun i=>(List.range n).map fun j=>f (a,(i,j))
end MatchingFPRAS.ExecutableBottleneck
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeLabelTable
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped ExecutableBottleneck Polynomial
abbrev LabelKey := ℕ×ℕ
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeStateTable
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped
variable {I A : Type}
[DecidableEq I]
[Inhabited I]
abbrev StateTable (I A : Type) := List (I×A)
def lookup (d : A) (x : StateTable I A×I) : A :=
((x.1.filter (fun z=>decide (z.1=x.2))).headD (x.2,d)).2
def stateRep (keys : List I) (s : I→A) : StateTable I A := keys.map (fun i=>(i,s i))
def setState (x : StateTable I A×(I×A)) : StateTable I A :=
x.1.map fun z=>(z.1,if z.1=x.2.1 then x.2.2 else z.2)
def setPair (x : StateTable I A×((I×I)×(A×A))) : StateTable I A :=
setState (setState (x.1,(x.2.1.1,x.2.2.1)),(x.2.1.2,x.2.2.2))
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeClosureReindex
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh
lemma orderedEnum_lt {A : Type} [Fintype A] [LinearOrder A]
(i j : Fin (Fintype.card A)) : orderedEnum A i < orderedEnum A j ↔ i < j := by
change ((Finset.univ : Finset A).orderIsoOfFin (Finset.card_univ) i).val <
((Finset.univ : Finset A).orderIsoOfFin (Finset.card_univ) j).val ↔ _
exact ((Finset.univ : Finset A).orderIsoOfFin (Finset.card_univ)).lt_iff_lt
end MatchingFPRAS.UnitRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_TreeNumberedCodec
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.Numbered
variable {A : Type} [Fintype A] [LinearOrder A]
def index (a : A) : ℕ := ((UnitRefresh.orderedEnum A).symm a).val
lemma index_injective : Function.Injective (index (A:=A)) := by
intro a b h
exact (UnitRefresh.orderedEnum A).symm.injective (Fin.ext h)
lemma index_le (a b : A) : index a ≤ index b ↔ a ≤ b := by
change (UnitRefresh.orderedEnum A).symm a ≤ (UnitRefresh.orderedEnum A).symm b ↔ _
rw [←not_lt,←not_lt,←UnitRefresh.orderedEnum_lt]
simp
end MatchingFPRAS.TreeTyped.Numbered
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeNumberedSets
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.Numbered
variable {A : Type} [Fintype A] [LinearOrder A]
def embedding : A ↪ ℕ := ⟨index,index_injective⟩
def set (s : Finset A) : Finset ℕ := s.map embedding
end MatchingFPRAS.TreeTyped.Numbered
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeMarking
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableMarking
open TreeTyped ExecutableLadder
variable {C E : Type}
[LinearOrder E]
[Inhabited E]
abbrev MarkInput (C E : Type) := (C×StateTable E (List Bool))×Finset E
abbrev Marks (E : Type) := List (E×ℕ)
def marksRep (s : Finset E) (f : E→Fin 3) : Marks E :=
(s.sort (·≤·)).map (fun e=>(e,(f e).val))
end MatchingFPRAS.ExecutableMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeNumericMarking
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericMarking
open TreeTyped ExecutableLadder ExecutableMarking TreeTyped.Numbered UnitRefresh
variable {E : Type} [Fintype E] [LinearOrder E]
def numericMarks (s : Finset E) (f : E→Fin 3) : Marks ℕ :=
(s.sort (·≤·)).map (fun e=>(index e,(f e).val))
end MatchingFPRAS.NumericMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeLabelCorrect
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped ExecutableBottleneck Finset
abbrev key {n H : ℕ} {B : Fin n→Fin n→ℚ} (l : NumberedHierarchy.Label B H) : LabelKey := (l.1.val,l.2.val.val)
local instance instLinearOrderLabelFin {n H : ℕ} (B : Fin n→Fin n→ℚ) : LinearOrder (NumberedHierarchy.Label B H) := NumberedHierarchy.labelOrder B H
local instance (priority := 2000) instLELabelFin {n H : ℕ} (B : Fin n→Fin n→ℚ) : LE (NumberedHierarchy.Label B H) := (NumberedHierarchy.labelOrder B H).toLE
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeEnumeration
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableSource
open TreeTyped ExecutableBottleneck
attribute [local instance] Transport.prodOrder Transport.sumOrder
local instance (priority := 2000) instLEProdOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : LE (A×B) := Transport.prodOrder.toLE
local instance (priority := 2000) instLTProdOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : LT (A×B) := Transport.prodOrder.toLT
local instance (priority := 2000) instLESumOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : LE (A⊕B) := Transport.sumOrder.toLE
local instance (priority := 2000) instLTSumOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : LT (A⊕B) := Transport.sumOrder.toLT
local instance (priority := 2000) instPreorderSumOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : Preorder (A⊕B) := Transport.sumOrder.toPreorder
end MatchingFPRAS.ExecutableSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeIndex
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
open Polynomial
variable {A : Type}
[DecidableEq A]
[BEq A]
[LawfulBEq A]
def indexStep (x : A×(A×ℕ)) : A×ℕ := (x.2.1,if x.2.1=x.1 then 0 else x.2.2+1)
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeDPProgram
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped
abbrev State := ℕ×(Bags×Table)
def update (x : ((Bags×Parents)×(ℕ×Table))×(ℕ×ℕ)) : Table :=
tabulate entry (context x.1,x.2)
lemma tabulate_materialized {X : Type} (f : X×(ℕ×ℕ) → ℕ) (x : X) (m B : ℕ) :
tabulate f (x,(m,B))=UnitRefresh.Materialized.tabulate m B (fun a r=>f (x,(a.val,r))) :=
tabulate_eq (fun ar=>f (x,ar))
lemma update_eq {V : Type} [Fintype V] [DecidableEq V] {m : ℕ}
(bags : V → Finset (Fin m)) (R : Finset V) (parent : Fin m → Option (Fin m))
(l : Fin m) (t : Table) (B : ℕ) (ps : Parents)
(hps : ps.getD l.val (false,0)=match parent l with | none=>(false,0) | some p=>(true,p.val)) :
update (((activeRep bags R,ps),(l.val,t)),(m,B))=
UnitRefresh.Materialized.update bags R parent l B t := by
unfold update context
simp only [hps,privateNumber_activeRep,sharedNumber_activeRep,totalNumber_activeRep]
rw [tabulate_materialized]
unfold UnitRefresh.Materialized.update
congr 1
funext a r
exact entry_eq bags R parent l a t r
def parentTag {m : ℕ} : Option (Fin m) → Bool×ℕ
| none => (false,0)
| some p => (true,p.val)
def parentRep {m : ℕ} (p : Fin m → Option (Fin m)) : Parents := List.ofFn (parentTag ∘ p)
@[simp] lemma parentRep_length {m : ℕ} (p : Fin m → Option (Fin m)) : (parentRep p).length=m := by
simp [parentRep]
@[simp] lemma parentRep_getD {m : ℕ} (p : Fin m → Option (Fin m)) (l : Fin m) :
(parentRep p).getD l.val (false,0)=parentTag (p l) := by
simp [parentRep,List.getD,l.isLt]
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeDPCount
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped
def initial (x : ℕ×ℕ) : Table :=
tabulate (fun ar : ℕ×(ℕ×ℕ)=>UnitRefresh.pairingCount ar.2.2) (0,x)
def finish (x : Table×ℕ) : ℕ := ((List.range x.2).map fun a=>read (x.1,(a,0))).prod
abbrev CountInput := (Bags×Parents)×List ℕ
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeFastDPEntry
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped Polynomial
abbrev RawCtx := (Bags×Parents)×(ℕ×Table)
def rawTerm (x : (RawCtx×ℕ)×ℕ) : ℕ := term ((context x.1.1,x.1.2),x.2)
def rawEntry (x : RawCtx×(ℕ×ℕ)) : ℕ := entry (context x.1,x.2)
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeClippedDP
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped Polynomial
def nVertices (o : CountInput) : ℕ := o.1.1.length
def nLabels (o : CountInput) : ℕ := o.1.2.length
def nPlan (o : CountInput) : ℕ := o.2.length
def BInitial (o : CountInput) : ℕ := nVertices o*nLabels o
def capBits (o : CountInput) : ℕ := nVertices o*nPlan o+(BInitial o)^2*nLabels o+1
def initialEntry (x : CountInput×(ℕ×ℕ)) : ℕ := UnitRefresh.pairingCount (min x.2.2 (BInitial x.1))
abbrev UpdateInput := (CountInput×RawCtx)×ℕ
def updateRows (x : UpdateInput) := nLabels x.1.1
def updateColumns (x : UpdateInput) := nVertices x.1.1*min x.2 (nPlan x.1.1)
def cappedEntry (x : UpdateInput×(ℕ×ℕ)) : ℕ := clip (capBits x.1.1.1,rawEntry (x.1.1.2,x.2))
def cappedUpdate (x : UpdateInput) : Table := tabulate cappedEntry (x,(updateRows x,updateColumns x))
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeClippedRun
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped Polynomial
abbrev CappedState := CountInput×State
def cappedStep (x : ℕ×CappedState) : CappedState :=
let o:=x.2.1
let st:=x.2.2
let rem:=st.1-1
(o,(rem,(trim st.2.1 x.1,cappedUpdate ((o,((st.2.1,o.1.2),(x.1,st.2.2))),rem))))
def tableWeightBound (o : CountInput) : ℕ :=
1+nLabels o*(2+(nVertices o*nPlan o+1)*(4*capBits o+2))
def cappedCount (o : CountInput) : ℕ :=
finish ((o.2.foldl (fun z l=>cappedStep (l,z)) (o,(o.2.length,(o.1.1,initial (nLabels o,BInitial o))))).2.2.2,nLabels o)
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeDPRepresentation
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
noncomputable def orderedRep {n m : ℕ} (bags : Fin n → Finset (Fin m)) : Bags :=
List.ofFn (fun i=>bagRep (bags i))
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeUnitBranch
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP
def skip (x : ℕ×ℕ) : ℕ := if x.1<x.2 then x.1 else x.1+1
def residual (x : Bags×ℕ) : Bags :=
(List.range (x.1.length-2)).map (fun i=>x.1.getD (skip (i,x.2)) [])
abbrev Context := CountInput
def valid (x : Context×(ℕ×ℕ)) : Bool :=
let bs:=x.1.1.1
let b:=x.2.1
let c:=x.2.2
decide (b≠bs.length-1) && decide (c∈bs.getD (bs.length-1) []) && decide (c∈bs.getD b [])
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeUnitDraw
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP
def decodeIndex (x : ℕ×ℕ) : ℕ×ℕ := (x.1/x.2,x.1%x.2)
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeFastUnit
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP Polynomial
def fastBranch (x : Context×ℕ) : ℕ := cappedCount ((residual (x.1.1.1,x.2),x.1.1.2),x.1.2)
def fastEdgeCount (x : Context×(ℕ×ℕ)) : ℕ := if valid x then fastBranch (x.1,x.2.1) else 0
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeUnitAssemble
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP
abbrev Result := List (ℕ×ℕ)
abbrev Frame := ℕ×(ℕ×ℕ)
def unskip (x : ℕ×ℕ) : ℕ := if x.1<x.2 then x.1 else x.1-1
def assembleAt (x : (Frame×Result)×ℕ) : ℕ×ℕ :=
let n:=x.1.1.1
let b:=x.1.1.2.1
let c:=x.1.1.2.2
let i:=x.2
if i=n+1 then (b,c) else if i=b then (n+1,c) else
let z:=x.1.2.getD (unskip (i,b)) (0,0)
(skip (z.1,b),z.2)
def assemble (x : Frame×Result) : Result :=
(List.range (x.1.1+2)).map (fun i=>assembleAt (x,i))
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeCappedAssembly
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP Polynomial
def capacity (x : Context) : ℕ := x.1.1.length+x.1.2.length+2
def clippedAt (x : (Context×(Frame×Result))×ℕ) : ℕ×ℕ :=
let r:=assembleAt (x.1.2,x.2)
(min r.1 (capacity x.1.1),min r.2 (capacity x.1.1))
def clippedAssemble (x : Context×(Frame×Result)) : Result :=
(List.range (min (x.2.1.1+2) (x.1.1.1.length+2))).map (fun i=>clippedAt (x,i))
def assemblyFoldStep (x : Frame×(Context×Result)) : Context×Result :=
(x.2.1,clippedAssemble (x.2.1,(x.1,x.2.2)))
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeUnitSampler
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP
abbrev Bits := List (List Bool)
abbrev State := Context×(Bits×List Frame)
def nextContext (x : Context×(ℕ×ℕ)) : Context :=
((residual (x.1.1.1,x.2.1),x.1.1.2),x.1.2)
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeFastDescent
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP Polynomial
def DescentInvariant (a : Context×Bits) (k : ℕ) (z : State) : Prop :=
z.1.1.1.length≤a.1.1.1.length ∧
(∀ b∈z.1.1.1,b∈a.1.1.1) ∧ z.1.1.2=a.1.1.2 ∧ z.1.2=a.1.2 ∧ z.2.1=a.2 ∧
z.2.2.length+k≤a.1.1.1.length ∧
∀ f∈z.2.2,f.1≤a.1.1.1.length ∧ f.2.1≤a.1.1.1.length*a.1.1.2.length ∧ f.2.2≤a.1.1.1.length*a.1.1.2.length
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_DPEnvelope
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh.Materialized
open Finset
variable {V : Type} [Fintype V] {m : ℕ}
def RowBound (t : Table) (w : Fin m → ℕ) : Prop := ∀ a r,read t a.val r ≤ w a
def mergeEnvelope (w : Fin m → ℕ) (l p : Fin m) (s : ℕ) : Fin m → ℕ :=
fun a=>if a=l then 1 else if a=p then 2^s*w l*w p else w a
omit [Fintype V] in
lemma entry_rowBound (bags : V → Finset (Fin m)) (R : Finset V)
(parent : Fin m → Option (Fin m)) (l : Fin m) (t : Table) (w : Fin m → ℕ)
(_ : ∀ a,1≤w a) (ht : RowBound t w) :
∀ a r,entry bags R parent l a t r ≤
match parent l with
| none => w a
| some p => mergeEnvelope w l p (sharedCount bags R l) a := by
intro a r
unfold entry
cases hp : parent l with
| none =>
simp only
split_ifs with h
· subst a; exact ht l _
· exact ht a r
| some p =>
simp only
unfold mergeEnvelope
split_ifs with h h'
· exact le_rfl
· subst a
calc
_ ≤ ∑ k∈range (sharedCount bags R l+1),
(sharedCount bags R l).choose k*w l*w p := by
apply sum_le_sum
intro k hk
exact Nat.mul_le_mul (Nat.mul_le_mul_left _ (ht l _)) (ht p _)
_ = 2^(sharedCount bags R l)*w l*w p := by
rw [←sum_mul,←sum_mul,Nat.sum_range_choose]
· exact ht a r
end MatchingFPRAS.UnitRefresh.Materialized
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_ClippedEnvelope
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.UnitRefresh.Materialized
open Finset
variable {V : Type} [Fintype V] {m : ℕ}
def nextEnvelope (bags : V → Finset (Fin m)) (R : Finset V)
(parent : Fin m → Option (Fin m)) (l : Fin m) (w : Fin m → ℕ) : Fin m → ℕ :=
match parent l with | none=>w | some p=>mergeEnvelope w l p (sharedCount bags R l)
end MatchingFPRAS.UnitRefresh.Materialized
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeClippedCorrect
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableDP
open TreeTyped Finset
def runCapped (o : CountInput) : List ℕ → Bags → Table → Bags×Table
| [],bs,t => (bs,t)
| l::ls,bs,t => runCapped o ls (trim bs l)
(cappedUpdate ((o,((bs,o.1.2),(l,t))),ls.length))
end MatchingFPRAS.ExecutableDP
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeFastSample
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableUnit
open TreeTyped ExecutableDP
def unwindClipped (cap : Context) (fs : List Frame) (r : Result) : Result :=
(fs.foldl (fun z f=>assemblyFoldStep (f,z)) (cap,r)).2
open UnitRefresh.Materialized
end MatchingFPRAS.ExecutableUnit
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeRefreshIndexed
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableRefresh
open TreeTyped TreeTyped.Numbered ExecutableDP ExecutableUnit Polynomial
abbrev Key := (ℕ×ℕ)×ℕ
def ordered (x : ℕ×ℕ) : ℕ×ℕ := if x.1<x.2 then x else (x.2,x.1)
def rowKey (x : Result×ℕ) : Key :=
(ordered (x.2,(x.1.getD x.2 (0,0)).1),(x.1.getD x.2 (0,0)).2)
def entryIndex (x : (List Key×Result)×ℕ) : ℕ := x.1.1.idxOf (rowKey (x.1.2,x.2))
def matching (x : List Key×Result) : Finset ℕ :=
((List.range x.2.length).map (fun i=>entryIndex (x,i))).toFinset
abbrev Input := (List Key×CountInput)×Bits
end MatchingFPRAS.ExecutableRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeRefreshCatalog
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableRefresh
open TreeTyped ExecutableDP ExecutableSource Polynomial
def sharedKey (x : Bags×Key) : Bool :=
decide (x.2.2∈x.1.getD x.2.1.1 [] ∧ x.2.2∈x.1.getD x.2.1.2 [])
open Transport UnitRefresh
attribute [local instance] Transport.prodOrder
local instance (priority := 2000) instLTProdOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : LT (A×B) := Transport.prodOrder.toLT
local instance (priority := 2000) instPreorderProdOfLinearOrder_solutions {A B : Type} [LinearOrder A] [LinearOrder B] : Preorder (A×B) := Transport.prodOrder.toPreorder
variable {n m : ℕ} {bags : Fin n→Finset (Fin m)} {a : Bags}
lemma sym_mk_inf_sup (s : Sym2 (Fin n)) : s(s.inf,s.sup)=s :=
(Sym2.sortEquiv.symm_apply_apply s)
lemma sym_inf_mem (s : Sym2 (Fin n)) : s.inf∈s := by
have h:=Sym2.mem_mk_left s.inf s.sup
rwa [sym_mk_inf_sup] at h
lemma sym_sup_mem (s : Sym2 (Fin n)) : s.sup∈s := by
have h:=Sym2.mem_mk_right s.inf s.sup
rwa [sym_mk_inf_sup] at h
end MatchingFPRAS.ExecutableRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeRefreshNumbered
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableRefresh
open TreeTyped TreeTyped.Numbered ExecutableDP ExecutableUnit Transport UnitRefresh
attribute [local instance] Transport.prodOrder
local instance (priority := 2000) instLEProdOfLinearOrder_solutions_1 {A B : Type} [LinearOrder A] [LinearOrder B] : LE (A×B) := Transport.prodOrder.toLE
local instance (priority := 2000) instLTProdOfLinearOrder_solutions_1 {A B : Type} [LinearOrder A] [LinearOrder B] : LT (A×B) := Transport.prodOrder.toLT
variable {V L : Type} [Fintype V] [LinearOrder V] [Fintype L] [LinearOrder L]
variable {bags : V→Finset L}
omit [Fintype V] in
lemma source_inf_mem (s : Sym2 V) : s.inf∈s := by
have h:=Sym2.mem_mk_left s.inf s.sup
have hs : s(s.inf,s.sup)=s := Sym2.sortEquiv.symm_apply_apply s
rwa [hs] at h
omit [Fintype V] in
lemma source_sup_mem (s : Sym2 V) : s.sup∈s := by
have h:=Sym2.mem_mk_right s.inf s.sup
have hs : s(s.inf,s.sup)=s := Sym2.sortEquiv.symm_apply_apply s
rwa [hs] at h
end MatchingFPRAS.ExecutableRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeReach
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped
open Polynomial
variable {A C : Type}
[LinearOrder A]
namespace FiniteReach
abbrev Input (C A : Type) := (C×Finset A)×Finset A
variable (p : C×(A×A) → Bool)
def grow (x : Input C A) : Finset A :=
x.2 ∪ x.1.2.filter (fun b=>∃ a∈x.2,p (x.1.1,(a,b))=true)
def sweep (x : Input C A) : Input C A := (x.1,grow p x)
def reach (x : Input C A) : Finset A := (countDown (fun x=>sweep p x.2) x.1.2.card x).2
end FiniteReach
end MatchingFPRAS.TreeTyped
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_TreeSparseComponents
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {A C : Type}
[LinearOrder A]
attribute [local instance] Transport.Sparse.finsetOrder
variable (p : C×(A×A) → Bool)
def adjacent (x : (C×Finset A)×(A×A)) : Bool :=
decide (x.2.1≠x.2.2) && (decide (x.2.1∈x.1.2) && (decide (x.2.2∈x.1.2) && p (x.1.1,x.2)))
variable {p}
abbrev ComponentInput (C A : Type) := ((C×Finset A)×Finset A)×A
def component (x : ComponentInput C A) : Finset A :=
x.1.2 ∩ FiniteReach.reach (adjacent p) (((x.1.1.1,x.1.2),x.1.1.2),{x.2})
def allComponents (x : (C×Finset A)×Finset A) : Finset (Finset A) :=
x.2.image (fun a=>component (p:=p) (x,a))
def discrepancies (x : (C×Finset A)×(Finset A×Finset A)) : Finset (Finset A) :=
(allComponents (p:=p) (x.1,x.2.1∪x.2.2)).filter (fun s=>¬s⊆x.2.1∩x.2.2)
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeCycleTable
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E C : Type}
[LinearOrder E]
attribute [local instance] Transport.Sparse.finsetOrder
abbrev PairState (E : Type) := Finset E×Finset E
abbrev CycleInput (C E : Type) := (C×Finset E)×PairState E
def exchange (x : PairState E×Finset E) : Finset E := (x.1.1\x.2)∪(x.1.2∩x.2)
def cycle (p : C×(E×E)→Bool) (x : CycleInput C E×Finset E) : PairState E :=
if x.2∈allComponents (p:=p) (x.1.1,x.1.2.1∪x.1.2.2) then
(exchange (x.1.2,x.2),exchange ((x.1.2.2,x.1.2.1),x.2)) else x.1.2
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeSwitchValid
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E V C : Type}
[LinearOrder E]
[LinearOrder V]
abbrev SwitchInput (C E V : Type) := (C×Finset E)×(Quad V×Quad E)
def switchValid (p : C×(E×(V×V))→Bool) (x : SwitchInput C E V) : Bool :=
decide (Function.Injective (quadFn x.2.1) ∧
(∀ i : Fin 4,p (x.1.1,(quadFn x.2.2 i,(quadFn x.2.1 i,quadFn x.2.1 (i+1))))=true) ∧
x.2.2.1.1≠x.2.2.2.1 ∧ x.2.2.1.1∈x.1.2 ∧ x.2.2.2.1∈x.1.2)
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeSwitchRaw
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E V C : Type}
[LinearOrder E]
[LinearOrder V]
attribute [local instance] Transport.Sparse.finsetOrder
def pairSet (x : E×E) : Finset E := {x.1,x.2}
def switchEdit (x : Finset E×Quad E) : Finset E :=
(x.1\pairSet (x.2.1.1,x.2.2.1))∪pairSet (x.2.1.2,x.2.2.2)
abbrev RawSwitchInput (C E V : Type) := (C×(Finset V×Finset E))×Finset E
def switchList (p : C×(E×(V×V))→Bool) (x : RawSwitchInput C E V) : List (Quad V×Quad E) :=
((quads (x.1.2.1.sort (·≤·))).product (quads (x.1.2.2.sort (·≤·)))).filter
(fun q=>switchValid p ((x.1.1,x.2),q))
def switchRaw (p : C×(E×(V×V))→Bool) (x : RawSwitchInput C E V) : Finset (Finset E) :=
((switchList p x).map fun q=>switchEdit (x.2,q.2)).toFinset
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeMatchingCheck
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E V C : Type}
[LinearOrder E]
[LinearOrder V]
def matchingCheck (p : C×(E×V)→Bool) (x : (C×Finset V)×Finset E) : Bool :=
decide (∀ v∈x.1.2,(x.2.filter (fun e=>p (x.1.1,(e,v))=true)).card=1)
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeCertify
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E V C : Type}
[LinearOrder E]
[LinearOrder V]
attribute [local instance] Transport.Sparse.finsetOrder
def certify (p : C×(E×V)→Bool) (x : (C×Finset V)×Finset (Finset E)) : Finset (Finset E) :=
x.2.filter (fun a=>matchingCheck p (x.1,a)=true)
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeColorRaw
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E C : Type}
[LinearOrder E]
attribute [local instance] Transport.Sparse.finsetOrder
def colorRaw (p : C×(E×E)→Bool) (x : (C×Finset E)×Finset E) : Finset (Finset E) :=
x.2.biUnion fun e=>(x.1.2.filter (fun f=>p (x.1.1,(f,e))=true)).image fun f=>insert f (x.2.erase e)
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_TreeSparseNeighbors
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E V C : Type}
[LinearOrder E]
[LinearOrder V]
attribute [local instance] Transport.Sparse.finsetOrder
abbrev TableInput (C E V : Type) := (C×(Finset V×Finset E))×Finset E
def degree (n : ℕ) : ℕ := 8*(n/2).choose 2
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreePairTable
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.SparseProgram
open TreeTyped
variable {E V C : Type}
[LinearOrder E]
[LinearOrder V]
attribute [local instance] Transport.Sparse.finsetOrder
abbrev PairInput (C E V : Type) := (C×(Finset V×Finset E))×PairState E
end MatchingFPRAS.TreeTyped.SparseProgram
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeIndexedPair
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutablePair
open TreeTyped TreeTyped.SparseProgram
def incident (x : (ℕ×ℕ)×ℕ) : Bool := decide (x.1.1=x.2 ∨ x.1.2=x.2)
def same (x : (ℕ×ℕ)×(ℕ×ℕ)) : Bool :=
decide ((x.1.1=x.2.1 ∧ x.1.2=x.2.2) ∨ (x.1.1=x.2.2 ∧ x.1.2=x.2.1))
def adjacent (x : (ℕ×ℕ)×(ℕ×ℕ)) : Bool :=
incident (x.1,x.2.1) || incident (x.1,x.2.2)
end MatchingFPRAS.ExecutablePair
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeIndexedPairCorrect
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutablePair
open TreeTyped TreeTyped.SparseProgram TreeTyped.Numbered
variable {E V : Type} [Fintype E] [LinearOrder E] [Fintype V] [LinearOrder V]
def endpointRep (s : Sym2 V) : ℕ×ℕ := (index s.inf,index s.sup)
end MatchingFPRAS.ExecutablePair
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Arithmetic_TreeStateNormalize
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped Polynomial
variable {I E : Type}
[DecidableEq I]
[Inhabited I]
[LinearOrder E]
abbrev StateEnvelope (I E : Type) := List I×Finset E
def normalizeState (x : StateEnvelope I E×StateTable I (Finset E)) : StateTable I (Finset E) :=
x.1.1.map (fun i=>(i,lookup ∅ (x.2,i)∩x.1.2))
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeLocalSampler
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped
variable {I A B C : Type}
variable [DecidableEq I] [Inhabited I] [Inhabited A]
local instance treeLocalSamplerUpdateInhabited : Inhabited (Replica.Update I) := ⟨Sum.inr default⟩
abbrev LocalContext (C I A B : Type) := C×(StateTable I A×B)
abbrev LocalPairInput (C I A B : Type) := (C×(I×I))×((A×A)×B)
abbrev LocalRefreshInput (C I B : Type) := (C×I)×B
def localPair (p : LocalPairInput C I A B→A×A)
(x : LocalContext C I A B×(I×I)) : StateTable I A :=
setPair (x.1.2.1,(x.2,p ((x.1.1,x.2),
((lookup default (x.1.2.1,x.2.1),lookup default (x.1.2.1,x.2.2)),x.1.2.2))))
def localRefresh (r : LocalRefreshInput C I B→A)
(x : LocalContext C I A B×I) : StateTable I A :=
setState (x.1.2.1,(x.2,r ((x.1.1,x.2),x.1.2.2)))
def localSampler (p : LocalPairInput C I A B→A×A) (r : LocalRefreshInput C I B→A)
(x : LocalContext C I A B×Option (Replica.Update I)) : StateTable I A :=
x.2.elim x.1.2.1 (Sum.elim (fun ij=>localPair p (x.1,ij)) (fun i=>localRefresh r (x.1,i)))
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeScanChoice
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped
variable {I C : Type}
[Inhabited I]
[LinearOrder I]
attribute [local instance] Transport.prodOrder Transport.sumOrder
local instance instInhabitedUpdate : Inhabited (Replica.Update I) := ⟨Sum.inr default⟩
abbrev ScanSetup (C I : Type) := C×(Finset I×Finset I)
def updateList (g : C×(I×I)→Bool) (x : ScanSetup C I) : List (Replica.Update I) :=
(((x.2.1.sort (·≤·)).product (x.2.1.sort (·≤·))).filter (fun ij=>g (x.1,ij))).map Sum.inl++
(x.2.2.sort (·≤·)).map Sum.inr
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeScan
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped
variable {I A B C : Type}
variable [LinearOrder I] [Inhabited I] [Inhabited A]
attribute [local instance] Transport.prodOrder Transport.sumOrder
local instance treeScanUpdateInhabited : Inhabited (Replica.Update I) := ⟨Sum.inr default⟩
abbrev ScanInput (C I A B : Type) := (ScanSetup C I×StateTable I A)×(List Bool×B)
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeScanRun
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped Polynomial
variable {I E B C : Type}
variable [LinearOrder I] [Inhabited I] [LinearOrder E]
attribute [local instance] Transport.prodOrder Transport.sumOrder
abbrev RunSetup (C I E : Type) := ScanSetup C I×StateEnvelope I E
abbrev RunState (C I E : Type) := RunSetup C I E×StateTable I (Finset E)
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeNumericLadder
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericLadder
open TreeTyped ExecutableLadder
abbrev RefreshSetup := List ExecutableRefresh.Key×ExecutableDP.CountInput
abbrev Bits := List Bool×ExecutableUnit.Bits
end MatchingFPRAS.NumericLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeLadderIndexed
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericLadder
open TreeTyped TreeTyped.Numbered ExecutableLadder
attribute [local instance] Transport.prodOrder Transport.sumOrder
variable {I : Type} [Fintype I] [LinearOrder I] [Inhabited I]
local instance instInhabitedUpdate : Inhabited (Replica.Update I) := ⟨Sum.inr default⟩
end MatchingFPRAS.NumericLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeLadderPost
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericLadder
open TreeTyped TreeTyped.Numbered ExecutableLadder Turing
variable {I : Type} [Fintype I] [LinearOrder I] [Inhabited I]
def numericState (x : StateTable I (Finset ℕ)) : StateTable ℕ (Finset ℕ) := x.map (fun a=>(index a.1,a.2))
end MatchingFPRAS.NumericLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreeLadder
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericLadder
open TreeTyped TreeTyped.Numbered ExecutableLadder UnitRefresh Transport Replica.Ladder
attribute [local instance] Transport.prodOrder Transport.sumOrder
variable {V L : Type} [Fintype V] [LinearOrder V] [Fintype L] [LinearOrder L]
variable {bags : V→Finset L} {G : SimpleGraph L}
variable (hbags : ∀ v,∀ a∈bags v,∀ b∈bags v,a=b ∨ G.Adj a b) (hG : G.IsAcyclic)
variable (rank : L→ℕ) (parent : L→Option L)
variable (hb : RankedBags bags rank parent) (hne : ∀ v,(bags v).Nonempty)
variable (hp : ∀ l p,parent l=some p → rank p < rank l)
variable {T q : ℕ} [Inhabited (Slot T q)]
def localBitsRep {k : ℕ} (b : LocalBits V k) : Bits :=
(List.ofFn b.1,List.ofFn (fun i=>List.ofFn (b.2 i)))
end MatchingFPRAS.NumericLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeSlotIndex
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericLadder
open TreeTyped TreeTyped.Numbered Replica.Ladder
def coordinateEquiv (T q : ℕ) : Slot T q ≃ Fin ((T+1)*q) :=
({toFun:=ofLex,invFun:=toLex,left_inv:=fun _=>rfl,right_inv:=fun _=>rfl} : Slot T q≃Fin (T+1)×Fin q).trans finProdFinEquiv
lemma coordinate_le {T q : ℕ} (a b : Slot T q) : coordinateEquiv T q a ≤ coordinateEquiv T q b ↔ a≤b := by
change (ofLex a).2.val+q*(ofLex a).1.val≤(ofLex b).2.val+q*(ofLex b).1.val ↔ a≤b
rw [Prod.Lex.le_iff]
have ha:=(ofLex a).2.isLt
have hb:=(ofLex b).2.isLt
change _ ↔ ((ofLex a).1.val<(ofLex b).1.val ∨ (ofLex a).1=(ofLex b).1 ∧ (ofLex a).2.val≤(ofLex b).2.val)
constructor
· intro h
by_cases hlt : (ofLex a).1.val<(ofLex b).1.val
· exact Or.inl hlt
· have hge : (ofLex b).1.val≤(ofLex a).1.val := Nat.le_of_not_gt hlt
have he : (ofLex a).1.val=(ofLex b).1.val := by
by_contra hh
have hs : (ofLex b).1.val+1≤(ofLex a).1.val := by omega
have hm:=Nat.mul_le_mul_left q hs
nlinarith
exact Or.inr ⟨Fin.ext he,by rw [he] at h; omega⟩
· rintro (h|⟨h,h'⟩)
· have hm:=Nat.mul_le_mul_left q h
nlinarith
· rw [h]; omega
def coordinateOrderIso (T q : ℕ) : Slot T q ≃o Fin ((T+1)*q) :=
{ coordinateEquiv T q with map_rel_iff' := fun {a b}=>coordinate_le a b }
lemma slot_card (T q : ℕ) : Fintype.card (Slot T q)=(T+1)*q := by simp [Slot]
def numberOrderIso (T q : ℕ) : Slot T q ≃o Fin ((T+1)*q) := by
let e : Slot T q ≃o Fin (Fintype.card (Slot T q)) :=
{ toEquiv := (UnitRefresh.orderedEnum (Slot T q)).symm
map_rel_iff' := by
intro a b
change ((UnitRefresh.orderedEnum (Slot T q)).symm a).val ≤
((UnitRefresh.orderedEnum (Slot T q)).symm b).val ↔ a ≤ b
exact index_le a b }
exact e.trans (Fin.castOrderIso (slot_card T q))
end MatchingFPRAS.NumericLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeSlotWeight
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableLadder
open TreeTyped
abbrev TierInput := (ℕ×List Bool)×ℕ
end MatchingFPRAS.ExecutableLadder
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_TreePreparedMarked
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericMarking
open TreeTyped ExecutableLadder TreeTyped.Numbered UnitRefresh NumericLadder
abbrev SampleBits := List (List Bool×Bits)×StateTable ℕ (List Bool)
open Replica.Ladder Transport
attribute [local instance] Transport.prodOrder Transport.sumOrder
end MatchingFPRAS.NumericMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_OnlineSample
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineSample
open PhysicalStream TreeTyped
abbrev word (k : ℕ) : Experiment (List Bool) := OnlineWord.prepend k []
variable {A : Type}
def words (x : ℕ×ℕ) : Experiment (List (List Bool)) :=
OnlineTree.traverseM word (List.replicate x.2 x.1)
def localWords (x : ℕ×ℕ) : Experiment NumericLadder.Bits :=
(word x.1).bind (fun w=>(words x).map (Prod.mk w))
def scan (x : ℕ×ℕ) : Experiment (List Bool×NumericLadder.Bits) :=
(word x.1).bind (fun w=>(localWords x).map (Prod.mk w))
def scans (x : (ℕ×ℕ)×ℕ) : Experiment (List (List Bool×NumericLadder.Bits)) :=
OnlineTree.traverseM scan (List.replicate x.2 x.1)
def markWord (x : ℕ×ℕ) : Experiment (ℕ×List Bool) := (word x.2).map (Prod.mk x.1)
def markRequests (x : ℕ×List ℕ) : List (ℕ×ℕ) := x.2.map (fun i=>(i,x.1))
def marks (x : ℕ×List ℕ) : Experiment (List (ℕ×List Bool)) :=
OnlineTree.traverseM markWord (markRequests x)
abbrev Request := ((ℕ×ℕ)×ℕ)×(ℕ×List ℕ)
def sample (x : Request) : Experiment NumericMarking.SampleBits :=
(scans x.1).bind (fun s=>(marks x.2).map (Prod.mk s))
def many (x : ℕ×Request) : Experiment (List NumericMarking.SampleBits) :=
OnlineTree.traverseM sample (List.replicate x.1 x.2)
end MatchingFPRAS.OnlineSample
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Probability_OnlineSampleLaw
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineSample
open PhysicalStream
abbrev LocalRandom (N k : ℕ) := Bits k × (Fin N → Bits k)
abbrev ScanRandom (N k : ℕ) := Bits k × LocalRandom N k
def localRep {N k : ℕ} (b : LocalRandom N k) : NumericLadder.Bits :=
(List.ofFn b.1,List.ofFn (fun i=>List.ofFn (b.2 i)))
def scanRep {N k : ℕ} (b : ScanRandom N k) : List Bool×NumericLadder.Bits :=
(List.ofFn b.1,localRep b.2)
abbrev Random (N k r m km : ℕ) := (Fin r→ScanRandom N k)×(Fin m→Bits km)
def sampleRep {N k r m km : ℕ} (keys : Fin m→ℕ) (bs : Random N k r m km) : NumericMarking.SampleBits :=
(List.ofFn (fun i=>scanRep (bs.1 i)),List.ofFn (fun i=>(keys i,List.ofFn (bs.2 i))))
end MatchingFPRAS.OnlineSample
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeParentTable
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped ExecutableBottleneck
local instance instLinearOrderLabelFin_1 {n H : ℕ} (B : Fin n→Fin n→ℚ) : LinearOrder (NumberedHierarchy.Label B H) := NumberedHierarchy.labelOrder B H
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeBagTable
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped ExecutableBottleneck Polynomial
def incident (x : ℕ×(ℕ×ℕ)) : Bool := decide (x.1=x.2.1 ∨ x.1=x.2.2)
local instance instLinearOrderLabelFin_2 {n H : ℕ} (B : Fin n→Fin n→ℚ) : LinearOrder (NumberedHierarchy.Label B H) := NumberedHierarchy.labelOrder B H
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeBagCorrect
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped ExecutableBottleneck
local instance instLinearOrderLabelFin_3 {n H : ℕ} (B : Fin n→Fin n→ℚ) : LinearOrder (NumberedHierarchy.Label B H) := NumberedHierarchy.labelOrder B H
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeHierarchyReindex
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.Numbered
variable {A B : Type} [Fintype A] [Fintype B] [LinearOrder A] [LinearOrder B]
def orderedIso (A : Type) [Fintype A] [LinearOrder A] : Fin (Fintype.card A)≃o A where
toEquiv:=UnitRefresh.orderedEnum A
map_rel_iff' := by intro a b; rw [←not_lt,←not_lt,UnitRefresh.orderedEnum_lt]
end MatchingFPRAS.TreeTyped.Numbered
namespace MatchingFPRAS.NumberedHierarchy
open Finset
variable {V W : Type} [Fintype V] [Fintype W] [LinearOrder V] [LinearOrder W]
variable (B : W→W→ℚ) (e : V≃o W)
abbrev reindex : V→V→ℚ := fun i j=>B (e i) (e j)
lemma component_reindex (t : ℚ) (x y : V) :
y∈component (reindex B e) t x ↔ e y∈component B t (e x) := by
simp only [component,mem_filter,mem_univ,true_and,related,reindex,e.injective.eq_iff]
lemma root_reindex (t : ℚ) (x : V) : e (root (reindex B e) t x)=root B t (e x) := by
apply le_antisymm
· have hm : e.symm (root B t (e x)) ∈ component (reindex B e) t x := by
rw [component_reindex,OrderIso.apply_symm_apply]
exact root_mem B t (e x)
have hle := Finset.min'_le (component (reindex B e) t x) _ hm
have hh:=e.monotone hle
simpa only [OrderIso.apply_symm_apply,root] using hh
· exact Finset.min'_le (component B t (e x)) _
((component_reindex B e t x _).mp (root_mem (reindex B e) t x))
def componentReindex (t : ℚ) : NumberedComponent (reindex B e) t≃NumberedComponent B t where
toFun x:=⟨e x.val,by rw [←root_reindex B e t x.val,x.property]⟩
invFun x:=⟨e.symm x.val,by
apply e.injective
rw [root_reindex,OrderIso.apply_symm_apply,x.property]⟩
left_inv x:=Subtype.ext (e.symm_apply_apply x.val)
right_inv x:=Subtype.ext (e.apply_symm_apply x.val)
def labelReindex (H : ℕ) : Label (reindex B e) H≃Label B H :=
Equiv.sigmaCongrRight (fun k=>componentReindex B e ((2:ℚ)^k.val))
attribute [local instance] labelOrder
local instance (priority := 2000) instLELabel {U : Type} [Fintype U] [LinearOrder U] {H : ℕ}
(C : U→U→ℚ) : LE (Label C H) := (labelOrder C H).toLE
def labelOrderReindex (H : ℕ) : Label (reindex B e) H≃o Label B H where
toEquiv:=labelReindex B e H
map_rel_iff' := by
intro a b
change toLex (a.1,e a.2.val)≤toLex (b.1,e b.2.val) ↔
toLex (a.1,a.2.val)≤toLex (b.1,b.2.val)
simp only [Prod.Lex.le_iff,ofLex_toLex,e.le_iff_le]
open Finset
variable {V W : Type} [Fintype V] [Fintype W] [LinearOrder V] [LinearOrder W]
variable (B : W→W→ℚ) (e : V≃o W)
variable (hsym : ∀ a b,B a b=B b a)
variable (htri : ∀ x y z,x≠y → x≠z → y≠z → min (B x z) (B z y)≤B x y)
omit [Fintype V] [Fintype W] in
include hsym in
lemma reindex_symm : ∀ a b,reindex B e a b=reindex B e b a := fun a b=>hsym (e a) (e b)
omit [Fintype V] [Fintype W] in
include htri in
lemma reindex_tri : ∀ x y z,x≠y → x≠z → y≠z →
min (reindex B e x z) (reindex B e z y) ≤ reindex B e x y :=
fun x y z hxy hxz hyz=>htri (e x) (e y) (e z) (e.injective.ne hxy) (e.injective.ne hxz) (e.injective.ne hyz)
end MatchingFPRAS.NumberedHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeBags
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped TreeTyped.Numbered ExecutableBottleneck NumberedHierarchy
variable {V : Type} [Fintype V] [LinearOrder V]
variable (B : V→V→ℚ) (hB : ∀ a b,0 ≤ B a b)
(hsym : ∀ a b,B a b=B b a)
(htri : ∀ x y z,x≠y → x≠z → y≠z → min (B x z) (B z y)≤B x y)
attribute [local instance] NumberedHierarchy.labelOrder
variable (xs : List Bool) {E : Type} [Fintype E] [DecidableEq E] (left right : E→V)
(es : List (ℕ×ℕ))
(hes : ∀ p,p∈es ↔ ∃ e,(index (left e),index (right e))=p)
@[instance_reducible] def ordinaryLabelFintype (H : ℕ) : Fintype (Label B H) := inferInstance
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeInitialMatching
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableRefresh
open TreeTyped TreeTyped.Numbered ExecutableDP ExecutableUnit Transport UnitRefresh
abbrev InitialInput := List Key×CountInput
open Turing
end MatchingFPRAS.ExecutableRefresh
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_TreeRankPlan
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableHierarchy
open TreeTyped ExecutableDP Polynomial
def rankLe (a b : ℕ×ℕ) : Prop := b.1<a.1 ∨ (a.1=b.1 ∧ a.2≤b.2)
instance instDecidableRelProdNatRankLe : DecidableRel rankLe := fun a b=>inferInstanceAs (Decidable (b.1<a.1 ∨ (a.1=b.1 ∧ a.2≤b.2)))
instance instIsTransProdNatRankLe : IsTrans (ℕ×ℕ) rankLe := ⟨by intro a b c; simp only [rankLe]; omega⟩
instance instTotalProdNatRankLe : Std.Total rankLe := ⟨by intro a b; simp only [rankLe]; omega⟩
instance instAntisymmProdNatRankLe : Std.Antisymm rankLe := ⟨by intro a b hab hba; simp only [rankLe] at *; apply Prod.ext <;> omega⟩
def rankEntries (rs : List ℕ) : List (ℕ×ℕ) := (List.range rs.length).map fun i=>(rs.getD i 0,i)
def rankPlan (rs : List ℕ) : List ℕ := ((rankEntries rs).insertionSort rankLe).map Prod.snd
end MatchingFPRAS.ExecutableHierarchy
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_RationalStart
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.RationalSource
open Finset Transport Subdivision Switching
variable {n : ℕ}
def pairIndex (he : Even n) (i : Fin n) : Fin n :=
if hi : i.val%2=0 then ⟨i.val+1,by obtain ⟨k,hk⟩:=he; have h:=i.isLt; omega⟩
else ⟨i.val-1,by have h:=i.isLt; omega⟩
lemma pairIndex_ne (he : Even n) (i : Fin n) : pairIndex he i≠i := by
intro h
have hh:=congrArg Fin.val h
unfold pairIndex at hh
split_ifs at hh <;> simp only at hh <;> omega
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] prodOrder sumOrder
end MatchingFPRAS.RationalSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_TreeGeneratedPrepared
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableSource
open TreeTyped TreeTyped.Numbered ExecutableBottleneck ExecutableHierarchy ExecutableRefresh NumericLadder
attribute [local instance] NumberedHierarchy.labelOrder
def rangeFromList {A : Type} (xs : List A) : Finset ℕ := (List.range xs.length).toFinset
open Turing
end MatchingFPRAS.ExecutableSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeStart
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableSource
open TreeTyped TreeTyped.Numbered ExecutableBottleneck ExecutableHierarchy ExecutableRefresh
attribute [local instance] NumberedHierarchy.labelOrder
def mateIndex (n : ℕ) : ℕ := if n%2=0 then n+1 else n-1
open Turing
end MatchingFPRAS.ExecutableSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_TreeObservables
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableMarking
open TreeTyped
variable {C E : Type}
[LinearOrder E]
[Inhabited E]
def zeroMarks (xs : Marks E) : Bool := xs.all (fun z=>decide (z.2=0))
def probeExpected (x : E×(E×ℕ)) : ℕ := if x.2.1=x.1 then 2 else 0
def probeFlag (x : E×Marks E) : Bool :=
x.2.any (fun z=>decide (z.1=x.1)) && x.2.all (fun z=>decide (z.2=probeExpected (x.1,z)))
def eraseMark (x : E×Marks E) : Marks E := x.2.filter (fun z=>decide (z.1≠x.1))
end MatchingFPRAS.ExecutableMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_TreeStageStatisticsCorrect
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableStatistics
open TreeTyped ExecutableMarking
variable {C E : Type}
[LinearOrder E]
[Inhabited E]
variable {S : ℕ} (s : Fin S→Finset E) (m : Fin S→E→Fin 3)
def sampleRep : List (Marks E) := List.ofFn (fun i=>marksRep (s i) (m i))
def scalarA (i : Fin S) : ℚ := if ∀ e∈s i,m i e=0 then 1 else 0
def scalarD (r : E→ℚ) (i : Fin S) : ℚ := if ∀ e∈s i,m i e=0 then ∏ e∈s i,r e else 0
def scalarProbe (r : E→ℚ) (e : E) (i : Fin S) : ℚ :=
if e∈s i ∧ ∀ a∈s i,m i a=if a=e then 2 else 0 then ∏ a∈s i\{e},r a else 0
end MatchingFPRAS.ExecutableStatistics
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_TreeNumericStatistics
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.TreeTyped.Numbered
variable {E A : Type} [Fintype E] [LinearOrder E]
def extend (d : A) (f : E→A) (i : ℕ) : A :=
if h:i<Fintype.card E then f (UnitRefresh.orderedEnum E ⟨i,h⟩) else d
end MatchingFPRAS.TreeTyped.Numbered
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_RationalScale
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FiniteTrial
open Finset
def cooling (n : ℕ) : ℚ := (1+1/(n:ℚ))⁻¹
lemma cooling_cast (n : ℕ) : (cooling n:ℝ)=Trial.cooling n := by
simp [cooling,Trial.cooling]
def raw (G : GraphInput) (j : ℕ) (a b : Fin G.n) : ℚ :=
if (min a b,max a b)∈G.edges then 1 else cooling G.n^j
lemma raw_cast (G : GraphInput) (j : ℕ) (a b : Fin G.n) :
(raw G j a b:ℝ)=Trial.raw G j a b := by
unfold raw Trial.raw GraphBridge.rawActivity
split_ifs <;> simp [cooling_cast]
structure ScaleState (G : GraphInput) (j : ℕ) where
scale : Fin G.n → ℚ
positive : ∀ i,0 < scale i
upper : ∀ i,scale i≤2^j
def ScaleState.toReal {G : GraphInput} {j : ℕ} (s : ScaleState G j) : Trial.ScaleState G j where
scale i:=(s.scale i:ℝ)
positive i:=by exact_mod_cast s.positive i
upper i:=by exact_mod_cast s.upper i
def ScaleState.activity {G : GraphInput} {j : ℕ} (s : ScaleState G j) : Fin G.n → Fin G.n → ℚ :=
fun a b=>raw G j a b*s.scale a*s.scale b
def ScaleState.nextActivity {G : GraphInput} {j : ℕ} (s : ScaleState G j) : Fin G.n → Fin G.n → ℚ :=
fun a b=>raw G (j+1) a b*s.scale a*s.scale b
lemma ScaleState.activity_cast {G : GraphInput} {j : ℕ} (s : ScaleState G j) :
(fun a b=>(s.activity a b:ℝ))=s.toReal.activity := by
funext a b
simp only [ScaleState.activity,Trial.ScaleState.activity,Rat.cast_mul,raw_cast,ScaleState.toReal]
lemma ScaleState.nextActivity_cast {G : GraphInput} {j : ℕ} (s : ScaleState G j) :
(fun a b=>(s.nextActivity a b:ℝ))=s.toReal.nextActivity := by
funext a b
simp only [ScaleState.nextActivity,Trial.ScaleState.nextActivity,Rat.cast_mul,raw_cast,ScaleState.toReal]
lemma ScaleState.activity_pos {G : GraphInput} {j : ℕ} (s : ScaleState G j) (a b : Fin G.n) :
0 < s.activity a b := by
have h:=s.toReal.activity_pos a b
rw [←s.activity_cast] at h
dsimp only at h
exact_mod_cast h
lemma ScaleState.nextActivity_pos {G : GraphInput} {j : ℕ} (s : ScaleState G j) (a b : Fin G.n) :
0 < s.nextActivity a b := by
have h:=s.toReal.nextActivity_pos a b
rw [←s.nextActivity_cast] at h
dsimp only at h
exact_mod_cast h
def initialScaleState (G : GraphInput) (hn : 2≤G.n) : ScaleState G 0 where
scale _:=Initializer.initialScale G.n
positive _:=Initializer.initialScale_pos G.n hn
upper i:=by
have h:=(Trial.initialScaleState G hn).upper i
change (Initializer.initialScale G.n:ℝ)≤2^0 at h
exact_mod_cast h
end MatchingFPRAS.FiniteTrial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_RationalEstimator
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.FiniteTrial
open Finset Transport
variable {V : Type*} [LinearOrder V]
def sampleAverage {Ω : Type*} {S : ℕ} (f : Ω → ℚ) (x : Fin S → Ω) : ℚ :=
(∑ i,f (x i))/(S:ℚ)
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] prodOrder sumOrder
end MatchingFPRAS.FiniteTrial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_TreeNumericSummaries
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericMarking
open TreeTyped TreeTyped.Numbered ExecutableStatistics ExecutableLadder
abbrev Bindings := List ((ℕ×ℕ)×ℕ)
end MatchingFPRAS.NumericMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_TreeStatistics
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericMarking
open TreeTyped TreeTyped.Numbered ExecutableStatistics ExecutableLadder
ExecutableBottleneck ExecutableSource
open Finset Transport
variable {E : Type} [DecidableEq E]
def selectedMarks (s : Finset E) (m : ↥s→Fin 3) (e : E) : Fin 3 :=
if h:e∈s then m ⟨e,h⟩ else 0
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] prodOrder sumOrder
end MatchingFPRAS.NumericMarking
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_TreeBindings
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableSource
open TreeTyped TreeTyped.Numbered ExecutableBottleneck ExecutableHierarchy ExecutableRefresh NumericLadder ExecutableLadder NumericMarking
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] Transport.prodOrder Transport.sumOrder
local instance (priority := 2000) instLEProdOfLinearOrder_solutions_1 {A B : Type} [LinearOrder A] [LinearOrder B] : LE (A×B) := Transport.prodOrder.toLE
local instance (priority := 2000) instLTProdOfLinearOrder_solutions_1 {A B : Type} [LinearOrder A] [LinearOrder B] : LT (A×B) := Transport.prodOrder.toLT
local instance (priority := 2000) instPreorderProdOfLinearOrder_solutions_1 {A B : Type} [LinearOrder A] [LinearOrder B] : Preorder (A×B) := Transport.prodOrder.toPreorder
end MatchingFPRAS.ExecutableSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_TreeSparseStage
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.ExecutableSource
open TreeTyped TreeTyped.Numbered ExecutableBottleneck ExecutableHierarchy ExecutableRefresh NumericLadder
open ExecutableLadder UnitRefresh Replica.Ladder Transport NumericMarking ExecutableStatistics
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] Transport.prodOrder Transport.sumOrder
abbrev StageControls := ((List Bool×List Bool)×ℕ)×(List Bool×List Bool)
open Turing
end MatchingFPRAS.ExecutableSource
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_OnlineRequest
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineSchedule
open TreeTyped Transport ExecutableSource NumericLadder
open TreeTyped.Numbered UnitRefresh
open ExecutableBottleneck ExecutableHierarchy ExecutableRefresh
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] Transport.prodOrder Transport.sumOrder
abbrev PrecisionData := ScanInput×(ℕ×ℕ)
def scanError (x : PrecisionData) : ℕ :=
2*(1+(x.1.1.2.2*(ladderQ x.1.1.1.1 x.1.1.1.2)^2+ladderQ x.1.1.1.1 x.1.1.1.2))+
4*(8*x.2.1^2+4*x.2.1+3)+2*x.1.1.1.1^2*x.2.2
def precisionPlan (x : PrecisionData) : ((ℕ×ℕ)×ℕ)×ℕ :=
(((Nat.clog 2 (discreteLadderSteps x.1.1.1.1 x.1.1.1.2 x.1.1.2.1 x.1.1.2.2 x.1.2 *scanError x*x.1.2),
x.1.1.1.1),discreteLadderSteps x.1.1.1.1 x.1.1.1.2 x.1.1.2.1 x.1.1.2.2 x.1.2),
Nat.clog 2 (6*x.2.1*x.1.2))
end MatchingFPRAS.OnlineSchedule
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_OutputLengthBound
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.Transport
open Finset
lemma clog_two_le_self (m : ℕ) : Nat.clog 2 m ≤ m :=
Nat.clog_le_of_le_pow (Nat.lt_two_pow_self (n:=m)).le
lemma bitPrecision_le (R : ℕ) (η : ℚ) : bitPrecision R η ≤ R*⌈η⁻¹⌉₊ :=
clog_two_le_self _
lemma sym2_card_le_square (V : Type*) [Fintype V] : Fintype.card (Sym2 V) ≤ (Fintype.card V)^2 := by
simpa only [Fintype.card_prod,pow_two] using Fintype.card_le_of_surjective _ (Sym2.mk_surjective (α:=V))
def tierPolynomial (N D K : ℕ) := N^2*(D+2*K+2)
def lambdaPolynomial (N D K T : ℕ) := 10*N*ladderQ N D*(T+1)*(K+(N*D+2)+1)
def stepsPolynomial (N D K m : ℕ) :=
20*ladderL N D*ladderM N D (tierPolynomial N D K)*
(lambdaPolynomial N D K (tierPolynomial N D K)+m+1)
def edgePolynomial (N K : ℕ) := N^2*((2*K+1)*N)
def scanErrorPolynomial (N D K : ℕ) :=
2*(1+ladderM N D (tierPolynomial N D K))+
4*(8*(edgePolynomial N K)^2+4*edgePolynomial N K+3)+2*N^2*((2*K+1)*N)
def totalBitsPolynomial (N D K m H : ℕ) :=
let t:=stepsPolynomial N D K m
let R:=scanErrorPolynomial N D K
t*((t*R*H)+(t*R*H+N*(t*R*H)))+edgePolynomial N K*(6*edgePolynomial N K*H)
lemma endpoint_le_polynomial (N D K : ℕ) (hN : 0<N) : endpoint N D K hN ≤ tierPolynomial N D K := by
rw [endpoint_eq]
apply (ladderTier_le N D K hN).trans
unfold tierBound tierPolynomial
gcongr
exact clog_two_le_self D
lemma lambda_le_polynomial (N D K T : ℕ) : ladderLambda N D K T ≤ lambdaPolynomial N D K T := by
unfold ladderLambda lambdaPolynomial
gcongr
exact clog_two_le_self _
lemma discreteSteps_le_polynomial (N D K T m : ℕ) (hT : T ≤ tierPolynomial N D K) :
discreteLadderSteps N D K T m ≤ stepsPolynomial N D K m := by
have hl : ladderLambda N D K T ≤ lambdaPolynomial N D K (tierPolynomial N D K) :=
(lambda_le_polynomial N D K T).trans (by unfold lambdaPolynomial; gcongr)
have hm : ladderM N D T ≤ ladderM N D (tierPolynomial N D K) := by unfold ladderM; gcongr
unfold discreteLadderSteps stepsPolynomial
gcongr
exact clog_two_le_self m
end MatchingFPRAS.Transport
namespace MatchingFPRAS.Variation
open Transport
variable {A B C : Type*} [Fintype A] [Fintype B] [Fintype C]
def paddedBits {k B : ℕ} (h : k≤B) :
(Fin B → Bool) ≃ ((Fin k → Bool) × (Fin (B-k) → Bool)) :=
(Equiv.arrowCongr (finCongr (Nat.add_sub_of_le h).symm) (Equiv.refl Bool)).trans (pairBitsEquiv k (B-k))
def padSampler {k B : ℕ} (h : k≤B) (f : (Fin k → Bool) → A) : (Fin B → Bool) → A :=
fun bits=>f ((paddedBits h bits).1)
noncomputable def markedBitsEquiv (E : Type*) [Fintype E] (t k : ℕ) :
(Fin (t+Fintype.card E*k) → Bool) ≃ ((Fin t → Bool) × (E → Fin k → Bool)) :=
(pairBitsEquiv t (Fintype.card E*k)).trans (Equiv.prodCongr (Equiv.refl _)
((matrixBitsEquiv (Fintype.card E) k).trans
(Equiv.arrowCongr (Fintype.equivFin E).symm (Equiv.refl _))))
end MatchingFPRAS.Variation
namespace MatchingFPRAS.FiniteTrial
open Transport Variation
variable {G : GraphInput} [Nontrivial (Fin G.n)]
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] prodOrder sumOrder
open Transport Variation
variable {G : GraphInput} [Nontrivial (Fin G.n)]
attribute [local instance] NumberedHierarchy.labelOrder
attribute [local instance] prodOrder sumOrder
def successorBitsEquiv (j B : ℕ) : (Fin ((j+1)*B) → Bool) ≃ (Fin (j*B+B) → Bool) :=
Equiv.arrowCongr (finCongr (Nat.succ_mul j B)) (Equiv.refl Bool)
end MatchingFPRAS.FiniteTrial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Complexity_OnlineRequestCost
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.NumericBounds
open Polynomial TreeTyped
variable {A B : Type}
def Bound (f m : A→ℕ) : Prop := ∃ p : Polynomial ℕ,∀ x,f x≤p.eval (m x)
end MatchingFPRAS.NumericBounds
namespace MatchingFPRAS.OnlineSchedule
open TreeTyped Polynomial NumericBounds Transport ExecutableSource
def precisionNorm (x : PrecisionData) : ℕ :=
x.1.1.1.1+x.1.1.1.2+x.1.1.2.1+x.1.1.2.2+x.1.2+x.2.1+x.2.2
end MatchingFPRAS.OnlineSchedule
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Arithmetic_OnlineFractionParam
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineSchedule
open TreeTyped Polynomial
abbrev RootInput := ℕ×List Bool
def rootCandidate (x : RootInput×ℕ) : Bool := decide (x.1.1<(x.2+1)^2)
def findRoot (x : RootInput) : ℕ :=
listMin ((List.range (x.2.length+1)).filter (fun i=>rootCandidate (x,i)),x.2.length)
end MatchingFPRAS.OnlineSchedule
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_OnlineLadderSchedule
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineSchedule
open TreeTyped Polynomial ExecutableSource Transport
abbrev LadderInput := (ℕ×ℕ)×ℕ
def distortion (x : ℕ×ℕ) : ℕ := 100*x.2^2*(100000000*(x.1+1)^4)
end MatchingFPRAS.OnlineSchedule
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_OnlineInitial
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineInitial
open TreeTyped ExecutableSource OnlineSchedule
def root (n : ℕ) : ℕ := findRoot (n-1,List.replicate n false)
end MatchingFPRAS.OnlineInitial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Graphs_OnlineGraphInvariant
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineGraph
open TreeTyped ExecutableSource
open PhysicalStream OnlineSchedule
abbrev Edges := List (ℕ×ℕ)
end MatchingFPRAS.OnlineGraph
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Algorithm_OnlineHistorySize
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineTrial
open TreeTyped PhysicalStream ExecutableSource
open Polynomial OnlineSchedule OnlineSample
variable {G : GraphInput} [Nontrivial (Fin G.n)]
noncomputable def vectorPolynomial : Polynomial ℕ :=
let B : Polynomial ℕ := X+1
B*(4*B+8*(B+B*B*(19+B+2*(B+B*B+1))+1)+6)+1
noncomputable def productPolynomial : Polynomial ℕ :=
let B : Polynomial ℕ := X+1
8*(B+B*(2*(B+B*B+1)+1)+1)+3
noncomputable def statePolynomial : Polynomial ℕ := 100*(X+1)+2*vectorPolynomial+2*productPolynomial
end MatchingFPRAS.OnlineTrial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Complexity_OnlineRunCost
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineTrial
open TreeTyped PhysicalStream Polynomial OnlineGraph OnlineSample
noncomputable def initialWeightPolynomial : Polynomial ℕ := 2*X+3+statePolynomial
end MatchingFPRAS.OnlineTrial
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Machines_OnlineCase
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.OnlineTree
open TreeTyped
open Turing MachineCost PhysicalStream OnlineStack
variable {A B : Type}
namespace Case
inductive Point where | split | test | yesClear | noClear | yes | no | halt
deriving DecidableEq, Inhabited
instance instFintypePoint : Fintype Point := ⟨{.split,.test,.yesClear,.noClear,.yes,.no,.halt},by intro p;cases p <;>simp⟩
end Case
end MatchingFPRAS.OnlineTree
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Sampling_Endpoints2
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS
namespace ExecutableInput
open TreeTyped
abbrev SparseInput := ℕ×List (ℕ×ℕ)
def tooSparse (x : SparseInput) : Bool := decide (2*x.2.length<x.1)
open Turing
end ExecutableInput
end MatchingFPRAS
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_Codec
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralCodec
open TreeTyped
def parts (a : Symbol) : List Bool×List Bool :=
(List.replicate a.val false,List.replicate (7-a.val) false)
def fromBit (b : Bool) : Symbol := if b then 2 else 1
def natWord (n : ℕ) : List Symbol := (n.bits.map fromBit)++[3]
end MatchingFPRAS.LiteralCodec
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_TapeTools
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralTape
open Turing MachineCost
variable {Γ Λ σ : Type} [Inhabited Γ]
@[simp] lemma mk₂_head (a : Γ) (L R : List Γ) : (Tape.mk₂ L (a::R)).head=a := rfl
@[simp] lemma mk₂_right (a : Γ) (L R : List Γ) :
(Tape.mk₂ L (a::R)).move .right=Tape.mk₂ (a::L) R := by
simp [Tape.mk₂,ListBlank.cons_mk]
@[simp] lemma mk₂_left (a : Γ) (L R : List Γ) :
(Tape.mk₂ (a::L) R).move .left=Tape.mk₂ L (a::R) := by
simp [Tape.mk₂,ListBlank.cons_mk]
@[simp] lemma mk₂_write (a b : Γ) (L R : List Γ) :
(Tape.mk₂ L (a::R)).write b=Tape.mk₂ L (b::R) := by
simp [Tape.mk₂,ListBlank.cons_mk]
def select [DecidableEq σ] (vs : List σ) (f : σ→TM1.Stmt Γ Λ σ)
(fallback : TM1.Stmt Γ Λ σ) : TM1.Stmt Γ Λ σ :=
vs.foldr (fun v tail=>.branch (fun _ s=>decide (s=v)) (f v) tail) fallback
def writeLeft (xs : List Γ) (q : TM1.Stmt Γ Λ σ) : TM1.Stmt Γ Λ σ :=
xs.foldr (fun a tail=>.write (fun _ _=>a) (.move .left tail)) q
def eraseToLeft (n : ℕ) (q : TM1.Stmt Γ Λ σ) : TM1.Stmt Γ Λ σ :=
Nat.rec q (fun _ tail=>.move .left (.write (fun _ _=>default) tail)) n
variable {I : Type} [DecidableEq I]
def grab (is : List I) (q : TM1.Stmt Γ Λ (I→Γ)) : TM1.Stmt Γ Λ (I→Γ) :=
is.foldr (fun i tail=>.load (fun a v=>Function.update v i a) (.move .right tail)) q
end MatchingFPRAS.LiteralTape
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_BlockMap
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralBlockMap
open Turing LiteralTape
inductive Label
| start | read | seek | back | stopSep | stopOut
deriving DecidableEq, Inhabited
instance instFintypeLabel : Fintype Label := ⟨{.start,.read,.seek,.back,.stopSep,.stopOut}, by intro a; cases a <;> simp⟩
abbrev Block (w : ℕ) := Fin w→Symbol
noncomputable def code (w : ℕ) (h : Block w→List Symbol) (header : List Symbol) :
Label→TM1.Stmt Symbol Label (Block w)
| .start => .move .left (.write (fun _ _=>7) (.move .left (.write (fun _ _=>6)
(.move .right (.move .right (.goto (fun _ _=>.read)))))))
| .read => grab (List.finRange w)
(.branch (fun _ b=>decide (b=fun _=>0))
(.move .left (.goto (fun _ _=>.stopSep)))
(.move .left (.write (fun _ _=>7) (eraseToLeft w (.move .left (.goto (fun _ _=>.seek)))))))
| .seek => .branch (fun a _=>decide (a=6))
(select Finset.univ.toList (fun b=>.write (fun _ _=>0)
(writeLeft (h b).reverse (.write (fun _ _=>6) (.move .right (.goto (fun _ _=>.back)))))) .halt)
(.move .left (.goto (fun _ _=>.seek)))
| .back => .branch (fun a _=>decide (a=7))
(.move .right (.goto (fun _ _=>.read)))
(.move .right (.goto (fun _ _=>.back)))
| .stopSep => .branch (fun a _=>decide (a=7))
(.write (fun _ _=>0) (.move .left (.goto (fun _ _=>.stopOut))))
(.move .left (.goto (fun _ _=>.stopSep)))
| .stopOut => .branch (fun a _=>decide (a=6))
(.write (fun _ _=>0) (writeLeft header.reverse (.write (fun _ _=>0) (.move .right .halt))))
(.move .left (.goto (fun _ _=>.stopOut)))
variable (w : ℕ) (h : Block w→List Symbol) (header : List Symbol)
def working (out : List Symbol) (gap : ℕ) (input : List Symbol) : Tape Symbol :=
Tape.mk₂ (7::(List.replicate gap 0++out.reverse++[6])) input
def budget (H n s : ℕ) : ℕ := (n+1)*(3+w+H+2*(s+n*(H+w)))
end MatchingFPRAS.LiteralBlockMap
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_Parse
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralParse
open TreeTyped Polynomial LiteralCodec
def numStep (x : Symbol×List ℕ) : List ℕ :=
if x.1=3 then 0::x.2
else if x.1=1 then (2*x.2.headD 0)::x.2.tail
else if x.1=2 then (2*x.2.headD 0+1)::x.2.tail
else x.2
def parse (as : List Symbol) : List ℕ := as.foldr (fun a ns=>numStep (a,ns)) []
end MatchingFPRAS.LiteralParse
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_Input
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralInput
open TreeTyped Polynomial LiteralParse
abbrev PairState := (Bool×ℕ)×List (ℕ×ℕ)
def pairStep (x : ℕ×PairState) : PairState :=
if x.2.1.1 then ((false,0),(x.1,x.2.1.2)::x.2.2) else ((true,x.1),x.2.2)
def pairs (ns : List ℕ) : List (ℕ×ℕ) := (ns.foldl (fun s n=>pairStep (n,s)) ((false,0),[])).2
def edgeNumbers (G : GraphInput) : List (ℕ×ℕ) :=
((G.edges.map toLex.toEmbedding).sort (·≤·)).map (fun e=>((ofLex e).1.val,(ofLex e).2.val))
end MatchingFPRAS.LiteralInput
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_Packed
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralPacked
open TreeTyped
lemma flatMap_uniform_length {α β : Type} (as : List α) (f : α→List β) (w : ℕ)
(h : ∀ a,(f a).length=w) : (as.flatMap f).length=as.length*w := by
induction as with
| nil => simp
| cons a as ih => simp only [List.flatMap_cons,List.length_append,h,ih,List.length_cons,Nat.add_mul,Nat.one_mul];omega
end MatchingFPRAS.LiteralPacked
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_PackedExecution
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralPacked
open Turing LiteralTape LiteralBlockMap
def singletonBlock (a : Symbol) : Block 1 := fun _=>a
end MatchingFPRAS.LiteralPacked
namespace MatchingFPRAS.LiteralTape
open Turing MachineCost
variable {Γ Λ σ : Type} [Inhabited Γ]
def eraseRight (n : ℕ) (q : TM1.Stmt Γ Λ σ) : TM1.Stmt Γ Λ σ :=
Nat.rec q (fun _ tail=>.write (fun _ _=>default) (.move .right tail)) n
noncomputable def eraseCode (n : ℕ) : Unit→TM1.Stmt Symbol Unit Unit := fun _=>eraseRight n .halt
end MatchingFPRAS.LiteralTape
end OAI
end
section
-- module Solutions.OAIQ051_MC.MatchingCount_Tapes_Physical
set_option linter.all false
set_option linter.unusedVariables false
set_option linter.unusedTactic false
set_option linter.unreachableTactic false
namespace OAI
namespace MatchingFPRAS.LiteralTape
open Turing MachineCost PhysicalStream
variable {Γ Λ σ : Type} [Inhabited Γ] [Inhabited Λ] [Fintype Λ] [Fintype σ] [Inhabited σ]
omit [Inhabited Γ] [Fintype σ] [Inhabited σ] in
lemma supports_univ (M : Λ→TM1.Stmt Γ Λ σ) : TM1.Supports M Finset.univ := by
classical
refine ⟨Finset.mem_univ _,fun l _=>?_⟩
induction M l with
| move d q ih => exact ih
| write f q ih => exact ih
| load f q ih => exact ih
| branch f q r ih jh => exact ⟨ih,jh⟩
| goto f => exact fun a v=>Finset.mem_univ _
| halt => trivial
end MatchingFPRAS.LiteralTape
end OAI
end