1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//! `topos` is an autodiff compiler stack. Record a graph, inspect
//! it, differentiate it, compile it, emit it. The spec is an
//! immutable [`Network`]; the state is a caller-owned
//! [`Parameters`].
//!
//! Expressions record onto a [`Tape`]. Sealing yields the network.
//! `forward` materializes every value, `backward` differentiates one
//! scalar target, and `step` is a pure data transform of the
//! parameters. Training never touches the graph:
//!
//! ```
//! use topos::{Detach, Tape, Tensor};
//!
//! // Record the graph in one closure; the return value is the set
//! // of names that leave the tape, detached to symbols in one call.
//! // Operators record as they run; values are `Copy` and never
//! // consumed. A scalar is a rank-0 tensor: the graph is always
//! // tensors, and the element type (`f64` here) is the open seam.
//! let (network, [w, x, y, loss]) = Tape::record(|tape| {
//! let w = tape.parameter(0.0_f64);
//! let x = tape.input(0.0);
//! let y = tape.input(0.0);
//! let error = w * x - y;
//! [w, x, y, error * error].detach()
//! });
//! let mut parameters = network.parameters();
//!
//! // The graph is recorded once; every step feeds one sample of the line
//! // `y = 2 * x` and steps the parameters, leaving the network untouched.
//! let samples = [(1.0, 2.0), (2.0, 4.0), (3.0, 6.0)];
//! for step in 0..100 {
//! let (sample_x, sample_y) = samples[step % samples.len()];
//! let run = network.forward(¶meters, [(x, sample_x.into()), (y, sample_y.into())]);
//! let gradients = run.backward(loss).parameters(¶meters);
//! parameters = parameters.step(&gradients, |w, g| {
//! w.clone() - g.clone() * Tensor::from(0.02)
//! });
//! }
//!
//! let learned = parameters.of(w).scalar();
//! assert!((learned - 2.0).abs() < 1e-6);
//! ```
//!
//! Differentiation comes in a hierarchy of three, in this order of
//! recommendation. [`Tape::differentiate`] records the chain rule as
//! ordinary nodes and answers [`Adjoints`] — the derivative as spec:
//! lower a forward-only entry over `adjoints.roots()` and fusion and
//! liveness apply to the chain rule itself, with
//! [`Run::recorded_gradients`] bridging to `step`. [`Run::backward`]
//! (the loop above) is the interpreter applying the same rules
//! without recording — the oracle the transform is proven against
//! bitwise, shipped forever. [`Entry::backward`] is neither: a
//! memory posture that retains what the engine scan reads, so a plan
//! that did not record its derivative can still answer `backward`.
//!
//! # The stack: one spec, named interpretations
//!
//! The tape is the spec; everything after it is a derived
//! interpretation of the same columns, each with a printable
//! artifact, and the whole compiler is this list:
//!
//! ```text
//! spec Tape / Network record, describe
//! shape inferred at record panics at the recording expression
//! value BoundEntry::interpret the oracle; Network::forward is the whole-spec form
//! cotangent Run::backward the engine reverse scan, oracle of reverse mode
//! trace Tape::differentiate the same rules recording themselves (Trace)
//! schedule BoundEntry::lower Plan: keep-set, liveness, election; describe
//! catalog Plan::patterns elected offers as data, never rewrites
//! text Plan::emit_stablehlo the interchange boundary
//! ```
//!
//! The value and cotangent rows compute over [`Tensor`]; the trace
//! row records over [`Trace`] — one derivative-rule body, two
//! interpretations of the recordable vocabulary ([`Recordable`]).
//! A new idea plugs in at a named seam, costed like an opcode: an
//! element type at [`Element`], a transcendental at [`MapOperation`],
//! a fusion as a pattern plus matcher, an AD mode as a recording
//! interpretation proven against [`Run::backward`], an industrial
//! target as an emission sibling consuming [`Plan`]. The core stays
//! closed; the table is how the crate refuses a pass manager and
//! still says yes to research.
//!
//! # Two surfaces, one crate
//!
//! Two audiences read this crate, and each has a map — rustdoc
//! modules that only re-export, so `use topos::Tape` keeps working
//! and nothing moves:
//!
//! - [`model`] — write a network, train it, checkpoint it: the
//! recording and run types, the neural facades, the optimizers.
//! - [`compiler`] — inspect, lower, emit, extend: the printable IR
//! ([`Opcode`], [`Node`], `describe`), the catalog as data, the
//! recording interpretation ([`Trace`]), the element seam, the
//! backend interrogation types, and the [`reference`](mod@reference)
//! kernels.
//!
//! ```no_run
//! # use topos::{Detach, Tape};
//! # let (network, [loss]) = Tape::record(|tape| {
//! # let w = tape.parameter(1.0_f64);
//! # [w * w].detach()
//! # });
//! // The compiler surface in three lines: print the spec, lower an
//! // entry, emit the schedule.
//! println!("{}", network.describe());
//! let plan = network.entry([loss]).lower();
//! println!("{}", plan.emit_stablehlo().expect("every operation lowers"));
//! ```
// The default build forbids `unsafe` outright. A backend feature
// drops `forbid` but keeps the crate-wide `deny`, so `unsafe`
// outside a scope-allowed backend module stays a compile error.
// The tiers are folders; the modules keep their flat crate paths, so
// `crate::graph` reads the same wherever the files sit. `core` is
// never re-exported publicly: `topos::Tape` is the only spelling.
// Core: the spec and its named readings. What the crate exists to
// do -- record a spec, then read it.
pub use ;
// Derived: faster or foreign readings of the same spec. A backend may
// decline and the interpreter remains the truth; emission writes the
// plan as text and is a sibling of `describe`, not a second compiler.
pub use ;
// Facades: convenience on the public surface, composed through it
// alone, with no privileged engine access.
pub use neural;
// `notebook` adds inherent methods to types the crate already owns, so
// nothing ever names its path; declaring it inside the tier is enough.
// Tools: the bitwise references a new element is graded against.
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
/// The model surface: write a network, train it, checkpoint it.
///
/// Everything here re-exports the crate root — `use topos::model::*`
/// is enough to record, run, and train, and flat `use topos::Tape`
/// imports keep working unchanged.
/// The compiler surface: inspect, lower, emit, and extend the stack.
///
/// The closed IR view, the catalog as data, the recording
/// interpretation, the element seam, and the backend interrogation
/// types — everything a research consumer reads that a training loop
/// never mentions. All re-exports of the crate root; the reference
/// kernels live in [`crate::reference`].