proarrow
Safe HaskellNone
LanguageGHC2024

Proarrow.Category.Enriched.Finitary.Sheaf

Description

Sheaves on a finite site, decided by enumeration.

A cover of a generates a Sieve (generatedSieve), and a matching family for that cover is exactly a natural transformation out of the sieve -- which over finitary profunctors is a finite thing you can list. So the sheaf condition becomes a comparison of two finite lists (sheafAt): restrict each element at a to get one table per element, enumerate the matching families to get the other list, and check the two agree as multisets. Comparing only their lengths is not enough: Props.Sheaf's Collapse has as many elements as matching families and is still not a sheaf.

The same coverage is a Lawvere–Tierney topology on the topos. closure sends a sieve to the pairs (g, h) along which it pulls back to a covering one, and lawvereTierney packages that as an arrow on Omega.

The topology also has a sheafification, Sheafify, with its unit and universal property -- computed rather than postulated, so it is one more thing that can be enumerated and compared.

Synopsis

Documentation

generatedSieve :: forall t {j} {k} (a :: k) (b :: j) c. (Site t k, LocallyFinite k, CategoryOf j, Ob a, Ob b) => Cover t k a c -> Sieve a b Source Github #

The sieve a cover generates at (a, b): the arrows into a that factor through a leg, paired with every arrow out of b.

isMaximal :: forall {j} {k} (a :: k) (b :: j). (FiniteCat j, FiniteCat k) => Sieve a b -> Bool Source Github #

Whether a sieve is the maximal one -- every arrow of the category is in it.

contains :: forall {j} {k} (a :: k) (b :: j). (FiniteCat j, FiniteCat k) => Sieve a b -> Sieve a b -> Bool Source Github #

Whether every point of the second sieve is a point of the first.

isCovering :: forall t {j} {k} (a :: k) (b :: j). (HasFiniteCovers t k, FiniteCat j, FiniteCat k) => Sieve a b -> Bool Source Github #

Whether a sieve is covering: either it is the maximal sieve, or it contains the sieve that some cover of its object generates -- which, a sieve being closed under composition, is to contain that cover's legs (coveringCover).

That is the coverage taken at face value. It agrees with the Grothendieck topology the coverage generates only when the covers are stable and compose. When they do not, closure stops being idempotent, and testLawvereTierney is where that shows up.

coveringCover :: forall t {j} {k} (a :: k) (b :: j). (HasFiniteCovers t k, CategoryOf j) => Sieve a b -> Maybe (SomeCover t k a) Source Github #

The first listed cover all of whose legs lie in the sieve, if there is one. This is the search isCovering makes and the one extendPlus needs, and it needs no tabulation: whether a sieve contains the legs at the identity decides whether it contains everything they generate.

So it trusts the closure Proarrow.Profunctor.Instance.Sieve does not enforce: on a hand-built predicate that is not a sieve it says yes where comparing the whole generated sieve says no.

closure :: forall t {j} {k} (a :: k) (b :: j). (HasFiniteCovers t k, FiniteCat j, FiniteCat k) => Sieve a b -> Sieve a b Source Github #

The Lawvere–Tierney closure of a sieve: the pairs (g, h) along which it pulls back to a covering one. A sieve is covering exactly when its closure is the maximal sieve.

Note both components -- dimap g h, not just lmap g. A coverage constrains only the contravariant side, but a sieve over j +-> k has two, which is why Props.Sheaf checks this function's naturality at a non-trivial j.

lawvereTierney :: forall t j k. (HasFiniteCovers t k, FiniteCat j, FiniteCat k) => (Omega :: PROD (FINITARY j k)) ~> (Omega :: PROD (FINITARY j k)) Source Github #

The coverage as a Lawvere–Tierney topology on the topos of finitary profunctors: closure, as an arrow on the subobject classifier.

isSheaf :: forall t {j} {k} (p :: j +-> k). (HasFiniteCovers t k, Finitary p, FiniteCat j, FiniteCat k) => Bool Source Github #

Whether a finitary profunctor is a sheaf for the coverage: at every pair of objects and every cover, restriction is a bijection from the elements at the covered object to the matching families on the sieve the cover generates.

sheafAt :: forall t {j} {k} (p :: j +-> k) (a :: k) (b :: j) c. (Site t k, Finitary p, FiniteCat j, FiniteCat k, Ob a, Ob b) => Cover t k a c -> Bool Source Github #

The sheaf condition at one cover: the restrictions of the elements at the covered object are exactly the matching families on the sieve it generates, as multisets.

withTabulatedSheaf :: forall t {j} {k} (p :: j +-> k) r. (HasFiniteCovers t k, Finitary p, FiniteCat j, FiniteCat k) => (forall {lm :: [[[[Nat]]]]} {rm :: [[[[Nat]]]]} (tab :: j +-> k). (tab ~ (Tabulated t lm rm :: k -> j -> Type), KnownTables j k lm rm, Sheaf t tab) => (p :~> tab) -> (tab :~> p) -> r) -> r -> r Source Github #

Present a finitary profunctor by its tables, as withTabulated does, and tag the presentation with the coverage -- which is to give it a Sheaf instance. What that instance asserts is decided here, by isSheaf, so the assertion is backed by an enumeration and not by the caller's word; the failure continuation is taken when the profunctor is no sheaf for t.

This is how a sheaf with no Sheaf instance of its own -- a representable, a sheafification -- becomes an object of SHEAVES. It is also the cheap way to be one: the condition is decided on the tables rather than on p, where a Sheafify answers a single toIndex by re-running the whole plus construction.

withSieve :: forall {j} {k} (a :: k) (b :: j) r. (FiniteCat j, FiniteCat k) => Sieve a b -> (forall (q :: j +-> k). Finitary q => (q :~> Yo a ('OP b)) -> r) -> r Source Github #

A sieve as a subobject of the representable, handed on with its inclusion: the natural transformations out of that subobject are exactly the matching families on the sieve, with no separate treatment of the points outside it and no argument about which naturality conditions may be dropped. This is the one notion of matching family in the module; sheafAt and Plus both go through it.

withSubobject checks the closure a sieve must have, and its failure branch is unreachable for any coverage, lawful or not: generatedSieve's membership ignores its covariant argument and is closed under precomposition, and leastDenseSieve is a meet of sieves. Reaching it would take a Finitary instance on the hom-profunctor whose elements omits an arrow, which testFinitary rules out.

Sheafification

data Plus t (p :: j +-> k) (a :: k) (b :: j) where Source Github #

One step of the plus construction for the topology t. An element at (a, b) is a matching family on a dense sieve, taken up to agreement on a dense sieve; a Plus value holds one such family, as a partial function whose support is its sieve -- the sieve is never stored separately and so cannot disagree with the family. On a finite site whose coverage is a Grothendieck topology the dense sieves have a least one, leastDenseSieve, and every element has exactly one family on it: so the element a value stands for is its restriction to that sieve, plusTable, and that is what Finitary numbers and Proarrow.Testing compares. Nothing has to be quotiented.

That is HasFiniteCovers's Composition law, and leastDenseSieve fails loudly rather than compute where it does not hold.

The constructor checks none of: that the support is a sieve, that it is dense, that the family is matching -- as Sieve's does not check closure. plusElements builds only lawful values; one built by hand is its builder's responsibility.

Constructors

Plus :: forall {k} {j} (a :: k) (b :: j) (p :: j +-> k) t. (Ob a, Ob b) => (forall (c :: k) (d :: j). (c ~> a) -> (b ~> d) -> Maybe (p c d)) -> Plus t p a b 

Instances

Instances details
(Site t k, LocallyFinite k, CategoryOf j) => Sheaf t (Sheafify t p :: k -> j -> Type) Source Github #

Sheafification lands in the sheaves. This is the theorem Props.Sheaf checks by enumeration with isSheaf @t @(Sheafify t p); here it is as an instance, so a Sheafify can be used wherever a Sheaf is asked for.

gluePlus would type-check for any Plus t q, but its laws need q separated -- which Plus t p always is, so the head is the double plus. The single-plus statement that is also true, Sheaf t p => Sheaf t (Plus t p), is thereby foreclosed for good: it would overlap this one with neither more specific.

Instance details

Defined in Proarrow.Category.Enriched.Finitary.Sheaf

Methods

glue :: forall (a :: k) c (b :: j). (Ob a, Ob b) => Cover t k a c -> (forall (x :: k). Leg t k a c x -> Sheafify t p x b) -> Sheafify t p a b Source Github #

(HasFiniteCovers t k, Finitary p, FiniteCat j, FiniteCat k) => Finitary (Plus t p :: k -> j -> Type) Source Github #

Numbered by plusElements, as the internal hom is numbered by the natural transformations out of its weight.

Instance details

Defined in Proarrow.Category.Enriched.Finitary.Sheaf

Methods

size :: forall (a :: k) (b :: j). (Ob a, Ob b) => Natural Source Github #

toIndex :: forall (a :: k) (b :: j). (Ob a, Ob b) => Plus t p a b -> Natural Source Github #

fromIndex :: forall (a :: k) (b :: j). (Ob a, Ob b) => Natural -> Plus t p a b Source Github #

elements :: forall (a :: k) (b :: j). (Ob a, Ob b) => [Plus t p a b] Source Github #

(CategoryOf j, CategoryOf k) => Profunctor (Plus t p :: k -> j -> Type) Source Github # 
Instance details

Defined in Proarrow.Category.Enriched.Finitary.Sheaf

Methods

dimap :: forall (c :: k) (a :: k) (b :: j) (d :: j). (c ~> a) -> (b ~> d) -> Plus t p a b -> Plus t p c d Source Github #

lmap :: forall (c :: k) (a :: k) (b :: j). (c ~> a) -> Plus t p a b -> Plus t p c b Source Github #

rmap :: forall (b :: j) (d :: j) (a :: k). (b ~> d) -> Plus t p a b -> Plus t p a d Source Github #

(\\) :: forall (a :: k) (b :: j) r. ((Ob a, Ob b) => r) -> Plus t p a b -> r Source Github #

support :: forall {k1} {k} t (p :: k1 +-> k) (a :: k) (b :: k1). Plus t p a b -> Sieve a b Source Github #

The sieve a value is defined on.

isDense :: forall t {j} {k} (a :: k) (b :: j). (HasFiniteCovers t k, FiniteCat j, FiniteCat k) => Sieve a b -> Bool Source Github #

Whether a sieve is dense for the topology: its closure is the maximal sieve. On a lawful coverage this agrees with isCovering -- testDenseIsCovering checks that -- but it is the stable notion, and Plus needs stability, since dimap pulls a support back along arrows.

leastDenseSieve :: forall t {j} {k} (a :: k) (b :: j). (HasFiniteCovers t k, FiniteCat j, FiniteCat k, Ob a, Ob b) => Sieve a b Source Github #

The meet of all the dense sieves at a pair of objects, and so the least dense sieve -- when the covers compose, since that is what makes closure preserve meets. Restriction to it is what picks one matching family out of each element of Plus. On a coverage whose covers pull back but do not compose the meet need not be dense, and this errors, naming the law that failed, rather than let Plus compute on it: a poset w ≤ x ≤ a, w ≤ y ≤ a with a covered by x and by y separately and each of those by w is the smallest example.

plusElements :: forall t {j} {k} (p :: j +-> k) (a :: k) (b :: j). (HasFiniteCovers t k, Finitary p, FiniteCat j, FiniteCat k, Ob a, Ob b) => [Plus t p a b] Source Github #

The elements of Plus at a pair of objects: the matching families on the least dense sieve, in the order natElements lists them.

restrictTo :: forall {j} {k} (q :: k -> j -> Type) (a :: k) (b :: j) t (p :: j +-> k). (q :~> Yo a ('OP b)) -> Plus t p a b -> q :~> p Source Github #

A value restricted to a sieve reified as a subobject: the natural transformation out of it that the value's family is.

plusTable :: forall t {j} {k} (p :: j +-> k) (a :: k) (b :: j). (HasFiniteCovers t k, Finitary p, FiniteCat j, FiniteCat k) => Plus t p a b -> [Natural] Source Github #

A value's restriction to the least dense sieve, as its natTable: the indices of its values at that sieve's points. See Plus for what that determines.

samePlus :: forall t {j} {k} (p :: j +-> k) (a :: k) (b :: j). (HasFiniteCovers t k, Finitary p, FiniteCat j, FiniteCat k) => Plus t p a b -> Plus t p a b -> Bool Source Github #

Whether two values stand for the same element: their restrictions to the least dense sieve agree. One sieve for the pair, where two plusTables would each build their own -- which is what Proarrow.Testing's equality on Plus wants, since it compares far more often than it shows.

type Sheafify t (p :: j +-> k) = Plus t (Plus t p) Source Github #

Sheafification: the plus construction twice. One Plus makes a profunctor separated -- two elements with the same restrictions to a dense sieve are equal -- and the second makes it a sheaf. The first alone need not: Props.Sheaf's constant presheaf on the two-point space has one section over the empty set after one plus, but still two over the whole space where a sheaf needs four. On a site whose covers have no overlaps, ByArrow say, one plus is already a sheaf and the second changes nothing.

unitPlus :: forall t {j} {k} (p :: j +-> k). Profunctor p => p :~> Plus t p Source Github #

The unit of the plus construction: an element as the family of its own restrictions, on the maximal sieve.

unitSheafify :: forall t {j} {k} (p :: j +-> k). Profunctor p => p :~> Sheafify t p Source Github #

unitPlus twice: the unit of sheafification.

extendPlus :: forall t {j} {k} (p :: j +-> k) (q :: j +-> k). (HasFiniteCovers t k, Sheaf t q) => (p :~> q) -> Plus t p :~> q Source Github #

The universal property, one plus at a time: a map into a sheaf extends along unitPlus. A dense support either is everything, and the family is read off at the identity, or contains the legs of some listed cover -- that is what density at the identity says, and coveringCover finds it -- and the family restricted to those legs glues. Which cover is found does not matter, q being a sheaf; nor need q be Finitary -- gluing is all that is asked of it.

gluePlus :: forall t {j} {k} (q :: j +-> k) (a :: k) c (b :: j). (Site t k, LocallyFinite k, Ob a, Ob b) => Cover t k a c -> (forall (x :: k). Leg t k a c x -> Plus t q x b) -> Plus t q a b Source Github #

Gluing for the plus construction: a matching family over a cover, assembled into one family. At (g, h) it takes the first leg that g factors through and whose family is defined at the factor -- factorThrough gives that factor u, and the value is the leg's family at (u, h). So the support of the result is what the legs generate from the legs' own supports, which is dense by HasFiniteCovers's Composition law.

Well definedness -- that another leg, or another factorisation through the same leg, gives the same value -- is exactly what matching says, and glue is unconstrained on families that are not matching, so the first one found is as good as any.

extendSheafify :: forall t {j} {k} (p :: j +-> k) (q :: j +-> k). (HasFiniteCovers t k, Sheaf t q) => (p :~> q) -> Sheafify t p :~> q Source Github #

extendPlus twice: a map into a sheaf extends along unitSheafify.

The category of sheaves

type SHEAVES t j k = SUBCAT ((Finitary :: (j +-> k) -> Constraint) :&&: (Sheaf t :: (j +-> k) -> Constraint)) Source Github #

The full subcategory of FINITARY j k on the sheaves for t: the finitary profunctors that have a Sheaf instance. Its finite limits are computed exactly as FINITARY's and are sheaves by the closure instances -- TerminalProfunctor, :*:, and Reindex for the equalizers. Its colimits are not computed as FINITARY's: a quotient of sheaves is no sheaf, and they go through Sheafify. Its hom-sets are finitary by the conjunction instance in Proarrow.Category.Enriched.Finitary.Topos.

type SHF t (p :: j +-> k) = 'SUB p :: SUBCAT ((Finitary :: (j +-> k) -> Constraint) :&&: (Sheaf t :: (j +-> k) -> Constraint)) Source Github #

A sheaf as an object of SHEAVES, as FIN names an object of FINITARY.

Orphan instances

(Site t k, CategoryOf j) => HasBinaryProducts (SHEAVES t j k) Source Github # 
Instance details

Methods

withObProd :: forall (a :: SHEAVES t j k) (b :: SHEAVES t j k) r. (Ob a, Ob b) => (Ob (a && b) => r) -> r Source Github #

fst :: forall (a :: SHEAVES t j k) (b :: SHEAVES t j k). (Ob a, Ob b) => (a && b) ~> a Source Github #

snd :: forall (a :: SHEAVES t j k) (b :: SHEAVES t j k). (Ob a, Ob b) => (a && b) ~> b Source Github #

(&&&) :: forall (a :: SHEAVES t j k) (x :: SHEAVES t j k) (y :: SHEAVES t j k). (a ~> x) -> (a ~> y) -> a ~> (x && y) Source Github #

(***) :: forall (a :: SHEAVES t j k) (b :: SHEAVES t j k) (x :: SHEAVES t j k) (y :: SHEAVES t j k). (a ~> x) -> (b ~> y) -> (a && b) ~> (x && y) Source Github #

(Site t k, Enumerable j, Enumerable k) => HasEqualizers (SHEAVES t j k) Source Github #

Equalizers as in FINITARY, by equalizeNat; the result is a sheaf for every coverage, which testEqualizersAreSheaves checks by enumeration.

Instance details

Methods

equalize :: forall (a :: SHEAVES t j k) (b :: SHEAVES t j k) r. (a ~> b) -> (a ~> b) -> (forall (e :: SHEAVES t j k). (e ~> a) -> r) -> r Source Github #

factorEqualizer :: forall (e :: SHEAVES t j k) (x :: SHEAVES t j k) (e' :: SHEAVES t j k). (e ~> x) -> (e' ~> x) -> e' ~> e Source Github #

(Site t k, Enumerable j, Enumerable k) => HasPullbacks (SHEAVES t j k) Source Github # 
Instance details

Methods

pullback :: forall (o :: SHEAVES t j k) (a :: SHEAVES t j k) (b :: SHEAVES t j k) r. (a ~> o) -> (b ~> o) -> (forall (p :: SHEAVES t j k). (p ~> a) -> (p ~> b) -> r) -> r Source Github #

factorPullback :: forall (a :: SHEAVES t j k) (b :: SHEAVES t j k) (p :: SHEAVES t j k) (q :: SHEAVES t j k). (p ~> a) -> (p ~> b) -> (q ~> a) -> (q ~> b) -> q ~> p Source Github #

(Site t k, CategoryOf j) => HasTerminalObject (SHEAVES t j k) Source Github # 
Instance details

Associated Types

type TerminalObject 
Instance details

Defined in Proarrow.Category.Enriched.Finitary.Sheaf

type TerminalObject = 'SUB (TerminalProfunctor :: k -> j -> Type) :: SUBCAT ((Finitary :: (j +-> k) -> Constraint) :&&: (Sheaf t :: (j +-> k) -> Constraint))

Methods

terminate :: forall (a :: SHEAVES t j k). Ob a => a ~> (TerminalObject :: SHEAVES t j k) Source Github #