# Topos Foundations
Simon Frost

- [Introduction](#introduction)
- [Setup](#setup)
- [SubobjectClassifier](#subobjectclassifier)
- [SheafSection](#sheafsection)
- [SheafCoherenceCheck](#sheafcoherencecheck)
- [InternalPredicate](#internalpredicate)
- [Building a Sheaf Diagram](#building-a-sheaf-diagram)
- [Connection to Democritus](#connection-to-democritus)
- [Coherence Checking](#coherence-checking)
  - [Coherence failure](#coherence-failure)
- [Predicate Evaluation](#predicate-evaluation)
- [Subobject Classification](#subobject-classification)
- [Internal Logic Operators](#internal-logic-operators)
  - [Conjunction (`internal_and`)](#conjunction-internal_and)
  - [Disjunction (`internal_or`)](#disjunction-internal_or)
  - [Negation (`internal_not`)](#negation-internal_not)
- [Interpretation](#interpretation)
  - [Document-to-KG pipelines](#document-to-kg-pipelines)
  - [Multi-source data fusion](#multi-source-data-fusion)
  - [Distributed consensus](#distributed-consensus)

## Introduction

**Topos theory** provides the foundational framework for FunctorFlow’s
local-to-global construction. In a topos, every logical operation has a
spatial counterpart:

| Topos concept                     | Intuition                           |
|:----------------------------------|:------------------------------------|
| **Subobject classifier** $\Omega$ | Generalized truth values            |
| **Sheaf**                         | Local data that glues consistently  |
| **Section**                       | A local data patch over a domain    |
| **Coherence check**               | Do local patches agree on overlaps? |
| **Internal predicate**            | A proposition valued in $\Omega$    |

The central pattern is the **sheaf condition**: local information
patches can be glued into a globally consistent whole if and only if
they agree on their overlaps. This is precisely the requirement for
multi-source data fusion, distributed knowledge graphs, and modular AI
systems.

FunctorFlow.jl provides first-class types for subobject classifiers,
sheaf sections, coherence checks, and internal predicates, along with a
`build_sheaf_diagram` function that compiles them into an executable
diagram.

## Setup

``` julia
using FunctorFlow
```

## SubobjectClassifier

A `SubobjectClassifier` defines the truth-value object $\Omega$ for the
topos. In classical logic, $\Omega = \{\text{true}, \text{false}\}$. In
a topos, $\Omega$ can carry richer truth values — for example,
three-valued logic with `true`, `false`, and `unknown`.

``` julia
Ω = SubobjectClassifier(:TruthValues;
    truth_object=:Omega,
    true_map=:true_map
)
```

    SubobjectClassifier(:TruthValues, :Omega, :true_map, Set([Symbol("true"), Symbol("false")]), Dict{Symbol, Any}())

``` julia
println("Name:         ", Ω.name)
println("Truth object: ", Ω.truth_object)
println("True map:     ", Ω.true_map)
```

    Name:         TruthValues
    Truth object: Omega
    True map:     true_map

The `truth_object` names the truth-value object $\Omega$ in the diagram,
and the `true_map` names the morphism $\text{true}: 1 \to \Omega$.
Richer truth structures (three-valued, fuzzy, probabilistic) can be
encoded via metadata and characteristic maps.

## SheafSection

A `SheafSection` represents a **local data patch**: a piece of
information defined over a specific domain (open set). A collection of
sections forms a presheaf; when they satisfy the gluing condition, they
form a sheaf.

``` julia
s1 = SheafSection(:EntitySection;
    base_space=:PubMedAbstracts,
    section_data=Dict(:BRCA1 => "tumor suppressor",
                      :TP53 => "guardian of the genome"),
    domain=Set([:BRCA1, :TP53]),
    metadata=Dict(:source => "PubMed", :confidence => 0.95)
)
```

    SheafSection(:EntitySection, :PubMedAbstracts, Dict(:TP53 => "guardian of the genome", :BRCA1 => "tumor suppressor"), Set([:TP53, :BRCA1]), Dict{Symbol, Any}(:confidence => 0.95, :source => "PubMed"))

``` julia
s2 = SheafSection(:RelationSection;
    base_space=:ClinicalTrials,
    section_data=Dict(:BRCA1 => "tumor suppressor",
                      :EGFR => "receptor tyrosine kinase"),
    domain=Set([:BRCA1, :EGFR]),
    metadata=Dict(:source => "ClinicalTrials.gov", :confidence => 0.88)
)
```

    SheafSection(:RelationSection, :ClinicalTrials, Dict(:BRCA1 => "tumor suppressor", :EGFR => "receptor tyrosine kinase"), Set([:BRCA1, :EGFR]), Dict{Symbol, Any}(:confidence => 0.88, :source => "ClinicalTrials.gov"))

``` julia
println("Section 1 base space: ", s1.base_space, ", domain: ", s1.domain)
println("Section 2 base space: ", s2.base_space, ", domain: ", s2.domain)
```

    Section 1 base space: PubMedAbstracts, domain: Set([:TP53, :BRCA1])
    Section 2 base space: ClinicalTrials, domain: Set([:BRCA1, :EGFR])

Notice that both sections contain information about `:BRCA1` — this is
the overlap where coherence will be checked.

## SheafCoherenceCheck

A `SheafCoherenceCheck` verifies whether sections agree on their
overlapping domains. If they do, the sections can be glued into a global
section; if not, the coherence failure is reported.

``` julia
overlap_checker = (s_a, s_b) -> begin
    # Check if sections agree on their overlapping domain
    overlap_domain = intersect(s_a.domain, s_b.domain)
    all(k -> get(s_a.section_data, k, nothing) == get(s_b.section_data, k, nothing), overlap_domain)
end

check = SheafCoherenceCheck([s1, s2];
    overlap_checker=overlap_checker,
    stability_penalty=0.1
)
```

    SheafCoherenceCheck(SheafSection[SheafSection(:EntitySection, :PubMedAbstracts, Dict(:TP53 => "guardian of the genome", :BRCA1 => "tumor suppressor"), Set([:TP53, :BRCA1]), Dict{Symbol, Any}(:confidence => 0.95, :source => "PubMed")), SheafSection(:RelationSection, :ClinicalTrials, Dict(:BRCA1 => "tumor suppressor", :EGFR => "receptor tyrosine kinase"), Set([:BRCA1, :EGFR]), Dict{Symbol, Any}(:confidence => 0.88, :source => "ClinicalTrials.gov"))], var"#3#4"(), nothing, 0.1, Dict{Symbol, Any}())

``` julia
println("Sections:          ", [s.name for s in check.sections])
println("Stability penalty: ", check.stability_penalty)
println("Has overlap checker: ", check.overlap_checker !== nothing)
```

    Sections:          [:EntitySection, :RelationSection]
    Stability penalty: 0.1
    Has overlap checker: true

On the overlap `[:BRCA1]`, section 1 assigns `"tumor suppressor"` and
section 2 also assigns `"tumor suppressor"` — so these sections are
coherent and can be glued.

## InternalPredicate

An `InternalPredicate` is a proposition valued in the subobject
classifier $\Omega$. It maps elements to truth values, enabling
fine-grained membership queries within the topos.

``` julia
pred = InternalPredicate(:IsHighConfidence, Ω;
    characteristic_map=entry -> haskey(entry, :confidence) && entry[:confidence] > 0.9
)
```

    InternalPredicate(:IsHighConfidence, SubobjectClassifier(:TruthValues, :Omega, :true_map, Set([Symbol("true"), Symbol("false")]), Dict{Symbol, Any}()), var"#11#12"(), Dict{Symbol, Any}())

``` julia
println("Predicate name: ", pred.name)
println("Classifier:     ", pred.classifier.name)
println("Has char. map:  ", pred.characteristic_map !== nothing)
```

    Predicate name: IsHighConfidence
    Classifier:     TruthValues
    Has char. map:  true

The predicate `:IsHighConfidence` maps each entry to `:true` if its
confidence exceeds 0.9, and `:unknown` otherwise. This is evaluated
internally within the topos — the result is a truth value in $\Omega$,
not a bare Boolean.

## Building a Sheaf Diagram

`build_sheaf_diagram` compiles sections and their overlap structure into
a full FunctorFlow `Diagram`. It creates:

1.  An **object** for each section’s domain
2.  A **morphism** for each section (mapping domain to values)
3.  **Gluing morphisms** for each overlap, enforcing the sheaf condition

``` julia
sections = [s1, s2]

D = build_sheaf_diagram(sections; name=:DocumentKG)
```

    Diagram :DocumentKG
      Objects:
        LocalSections::local_claims
        Overlap::overlap_region
        GlobalSection::global_state
      Operations:
        glue = Δ(LocalSections, along=Overlap, target=GlobalSection, reducer=:set_union)
      Ports:
        → sections (local_claims)
        → overlaps (overlap_region)
        ← global (global_state)

``` julia
println("Objects:    ", collect(keys(D.objects)))
println("Operations: ", collect(keys(D.operations)))
println("Ports:      ", collect(keys(D.ports)))
```

    Objects:    [:LocalSections, :Overlap, :GlobalSection]
    Operations: [:glue]
    Ports:      [:sections, :overlaps, :global]

The gluing morphisms connect overlapping domains and ensure that the
values assigned to shared elements are consistent. When compiled and
run, the diagram propagates local data patches through the gluing
morphisms, producing a globally consistent knowledge graph.

``` julia
ir = to_ir(D)
println("Diagram IR name: ", ir.name)
println("IR objects:      ", length(ir.objects))
println("IR operations:   ", length(ir.operations))
```

    Diagram IR name: DocumentKG
    IR objects:      3
    IR operations:   1

## Connection to Democritus

The `democritus_gluing_block` implements the same sheaf-gluing pattern
as a reusable block. “Democritus” refers to the atomic decomposition and
recomposition of knowledge — breaking information into local atoms
(sections) and gluing them back together.

``` julia
demo = democritus_gluing_block(; name=:DemoGlue)
```

    Diagram :DemoGlue
      Objects:
        LocalClaims::local_claims
        OverlapRegion::overlap_region
        GlobalState::global_state
      Operations:
        glue = Δ(LocalClaims, along=OverlapRegion, target=GlobalState, reducer=:set_union)
      Ports:
        → input (local_claims)
        → relation (overlap_region)
        ← output (global_state)

``` julia
println("Democritus block objects: ", collect(keys(demo.objects)))
println("Democritus block ops:    ", collect(keys(demo.operations)))
```

    Democritus block objects: [:LocalClaims, :OverlapRegion, :GlobalState]
    Democritus block ops:    [:glue]

The Democritus block is a pre-wired sheaf diagram with standard section
and gluing morphisms. It provides the same guarantees as a manually
constructed sheaf diagram but with less boilerplate.

You can inspect the structure to see the gluing morphisms.

``` julia
for (name, op) in demo.operations
    if op isa Morphism
        println("  $name: $(op.source) → $(op.target) (morphism)")
    elseif op isa KanExtension
        println("  $name: $(op.source) along $(op.along) → $(op.target) (kan)")
    end
end
```

      glue: LocalClaims along OverlapRegion → GlobalState (kan)

## Coherence Checking

The `check_coherence` function evaluates the sheaf condition on a
`SheafCoherenceCheck`, verifying locality, gluing, and stability across
all section pairs.

``` julia
result = check_coherence(check)
println("Coherence passed: ", result.passed)
println("Locality: ", result.locality)
println("Gluing: ", result.gluing)
println("Stability: ", result.stability)
```

    Coherence passed: true
    Locality: true
    Gluing: true
    Stability: true

Because both `s1` and `s2` assign `"tumor suppressor"` to `:BRCA1`, the
coherence check passes — locality, gluing, and stability are all
satisfied.

### Coherence failure

When sections disagree on their overlapping domain, the coherence check
reports a failure:

``` julia
sec_bad = SheafSection(:s_bad;
    base_space=:X,
    section_data=[100, 200, 300],
    domain=Set([:a, :b, :c])
)
check_bad = SheafCoherenceCheck([s1, sec_bad];
    overlap_checker=(s1, s2) -> false
)
result_bad = check_coherence(check_bad)
println("Coherence with disagreeing sections: ", result_bad.passed)
```

    Coherence with disagreeing sections: false

The overlap checker explicitly returns `false`, so the coherence check
fails — demonstrating how FunctorFlow surfaces inconsistencies rather
than silently merging conflicting data.

## Predicate Evaluation

`evaluate_predicate` applies an `InternalPredicate`’s characteristic map
to a datum and returns a truth value in $\Omega$ as a `Symbol`.

``` julia
omega = SubobjectClassifier(:Omega)
pred_pos = InternalPredicate(:positive, omega;
    characteristic_map=x -> x > 0
)

tv = evaluate_predicate(pred_pos, 5)
println("evaluate_predicate(pred_pos, 5) = ", tv)    # Symbol("true")

tv2 = evaluate_predicate(pred_pos, -3)
println("evaluate_predicate(pred_pos, -3) = ", tv2)  # Symbol("false")
```

    evaluate_predicate(pred_pos, 5) = true
    evaluate_predicate(pred_pos, -3) = false

The result is `Symbol("true")` or `Symbol("false")` — truth values in
the subobject classifier, not bare Julia `Bool`s. This distinction
matters: in a richer topos, truth values can include
`Symbol("unknown")`, `Symbol("probable")`, etc.

## Subobject Classification

`classify_subobject` applies a characteristic function to every element
of a data collection, producing a dictionary mapping each element to its
truth value in $\Omega$.

``` julia
data = Dict(:a => 5, :b => -3, :c => 10, :d => 0)
classification = classify_subobject(omega, x -> x > 0, data)
for (k, v) in sort(collect(classification))
    println("  $k → $v")
end
```

      a → true
      b → false
      c → true
      d → false

This is the topos-theoretic analogue of filtering: instead of discarding
elements, we classify every element by its membership in the subobject.
The result is a complete map from the ambient set into $\Omega$.

## Internal Logic Operators

FunctorFlow provides internal logic operators that compose predicates
within the topos. These operators produce new `InternalPredicate`s whose
characteristic maps combine the originals pointwise.

``` julia
p = InternalPredicate(:positive, omega;
    characteristic_map=x -> x > 0
)
q = InternalPredicate(:even, omega;
    characteristic_map=x -> x % 2 == 0
)
```

    InternalPredicate(:even, SubobjectClassifier(:Omega, :Omega, :true_map, Set([Symbol("true"), Symbol("false")]), Dict{Symbol, Any}()), var"#26#27"(), Dict{Symbol, Any}())

### Conjunction (`internal_and`)

``` julia
pq = internal_and(p, q)
println("4 is positive AND even: ", pq.characteristic_map(4))
println("3 is positive AND even: ", pq.characteristic_map(3))
```

    4 is positive AND even: true
    3 is positive AND even: false

### Disjunction (`internal_or`)

``` julia
p_or_q = internal_or(p, q)
println("-2 is positive OR even: ", p_or_q.characteristic_map(-2))
println("7 is positive OR even:  ", p_or_q.characteristic_map(7))
```

    -2 is positive OR even: true
    7 is positive OR even:  true

### Negation (`internal_not`)

``` julia
not_p = internal_not(p)
println("-1 is NOT positive: ", not_p.characteristic_map(-1))
println("5 is NOT positive:  ", not_p.characteristic_map(5))
```

    -1 is NOT positive: true
    5 is NOT positive:  false

These operators respect the internal logic of the topos: they work over
any truth-value structure $\Omega$ supports, not just classical Boolean
logic.

## Interpretation

Topos foundations connect FunctorFlow to three practical patterns in AI:

### Document-to-KG pipelines

Each document produces a local knowledge graph (a section over its
domain). The sheaf condition ensures that entities mentioned in multiple
documents receive consistent representations. The gluing morphisms
implement entity resolution and fact reconciliation.

### Multi-source data fusion

Different data sources (clinical trials, literature, expert annotations)
are modeled as sections over overlapping domains. The coherence check
verifies agreement on shared entities, and the sheaf diagram fuses them
into a unified representation. Disagreements are surfaced as coherence
failures rather than silently overwritten.

### Distributed consensus

In a distributed system, each node holds a local view (section) of the
global state. The sheaf condition is precisely the consensus
requirement: all nodes must agree on their shared observations. The
topos framework provides formal criteria for when local updates can be
consistently merged and when they cannot.

The topos-theoretic perspective ensures that FunctorFlow’s
local-to-global constructions are not ad hoc — they inherit the full
power of sheaf theory, including restriction maps, gluing axioms, and
the internal logic of the topos. This makes the system both principled
and practically useful for any task that involves assembling a global
picture from local pieces.
