PossiblyInfiniteList #
A note in the beginning: We mimic Mathlib's Stream'.Seq a lot here. Still I keep this separate to have full control about all the details. In the end, what we need should be simple enough.
This file defines a PossiblyInfiniteList which is an InfiniteList over an Option of the desired type.
The offered functions are very similar to the ones of InfiniteList.
An InfiniteList over Option has no_holes if an element being none implies its successors also being none. This is a property that we want for possibly infinite lists but we need to be able to express it on the underlying infinite list first.
Instances For
A PossiblyInfiniteList is an InfiniteList over Option that has no_holes.
- infinite_list : InfiniteList (Option α)
- no_holes : self.infinite_list.no_holes
Instances For
Basics #
The essential functions on infinite lists, mainly get, drop, head, and tail.
Obtain another possibly infinite list by dropping the first n elements from the current one.
Instances For
Drops the first element.
Instances For
Constructs a possibly infinite list from a possibly infinite list and a new head element.
Equations
- PossiblyInfiniteList.cons hd tl = { infinite_list := InfiniteList.cons (some hd) tl.infinite_list, no_holes := ⋯ }
Instances For
Equations
- PossiblyInfiniteList.instMembership = { mem := fun (l : PossiblyInfiniteList α) (a : α) => some a ∈ l.infinite_list }
Two possibly infinite lists are the same of they are the same on all indices.
InfiniteList.no_holes restated for the PossiblyInfiniteList.
A closed version of the no_holes property. That is, if an element is none, then not only its immediate successor but all successors are none.
Get after drop can be rewritten into get.
Dropping zero elements changes nothing.
The head is the same as getting the element at index zero.
The head is in the list.
Getting the head after dropping n equals getting n.
Getting the nth element from the tail equals getting the successor of n from the original list.
Getting the tail after dropping n is the same as dropping n.succ.
Getting the first element on cons is the new head.
Getting any index > 0 on cons yields the respective element from the previous possibly infinite list.
Any PossiblyInfiniteList can be written using the cons constructor.
Suffixes #
Here, we define a suffix relation on PossiblyInfiniteList inspired by List.IsSuffix.
For l1 and l2, l1 <:+ l2 denotes that l1 is a suffix of l2.
The suffix relation is reflexive and transitive but not necesarrily antisymmetric!
A suffix relation on possibly infinite lists. This is inspired by List.IsSuffix. Read l1 <:+ l2 as: l1 is a suffix of l2.
Equations
- (l1 <:+ l2) = (l1.infinite_list <:+ l2.infinite_list)
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
The suffix relation is reflexive.
The suffix relation is transitive.
Two suffixes of the same list must be suffixes of each other in some way. This is similar to List.suffix_or_suffix_of_suffix.
A member of a suffix is also a member of the current list.
Dropping elements yields a suffix.
The tail is a suffix.
Recursor for Members #
We define a recursion (induction) principle for members (Elements) of a PossiblyInfiniteList called mem_rec.
This can be used with the induction tactic to prove a property for each Element of a PossiblyInfiniteList.
Note that for using this coveniently, the goal needs to expressed (rewritten) using an Element.
A recursor for proving properties about list members via induction.
Map #
We allow to map over PossiblyInfiniteList just like List.map.
Applies a function to each list element; just like List.map.
Equations
- l.map f = { infinite_list := l.infinite_list.map fun (o : Option α) => Option.map f o, no_holes := ⋯ }
Instances For
When getting after map, we can instead get and then apply the mapping function.
The tail of a mapped list is the same as applyign map to the tail.
Generating a PossiblyInfiniteList #
We provide functions for "step-by-step" generation of a PossiblyInfiniteList from a function building a next element from an existing one. This is very similar to what is done for Mathlib's Stream'.Seq.
Making use of InfiniteList.generate, we can also generate a PossiblyInfiniteList only that the start value and the result of the generator function are now options.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The head of a generated list is the mapped version of the starting value.
The nth element of a generated list is the mapped version of the nth element of the iterated "carrier" list.
The successor of the nth element of a generated list can be seen as applying the mapper function after the generator function after taking the nth element from the iterated "carrier" list.
The tail of a generated list is the list generated when applying the generator function once on the starting element before the actual generation.
Empty Infinite Lists #
The empty PossiblyInfiniteList is simply the PossiblyInfiniteList that is none on all indices.
The empty PossiblyInfiniteList is none everywhere.
Instances For
A PossiblyInfiniteList is empty if and only if its head is none.
Finite PossiblyInfiniteList #
We define when we consider a PossiblyInfiniteList to be finite, namely when it is none on some index.
We also define a function converting a finite PossiblyInfiniteList into a plain List.
Transforms a finite list into an inductive List.
Equations
- l.toList_of_finite fin = PossiblyInfiniteList.toList_of_finite.loop l fin 0
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
A mapped list is finite if the original list is finite.
The empty list is finite.
The nth element in the transformed list is the nth element from the original list.
An element is in the transformed finite list if and only if it is in the original list.
Mapping over the transformed finite list is the same as mapping first and then transforming.
The transformed list is empty if and only if the original list is empty.
Converting a List into a PossiblyInfiniteList #
We can always convert a plain List into a PossiblyInfiniteList by setting all indices beyond the length of the list to none.
When building from a List, the PossiblyInfiniteList is finite.
Transforming a List to a PossiblyInfiniteList and back, gives the original list.