# DKE Library — Specification **Version:** 1.0.4, changed in rev 163 · alpha · API 1.4 · rev 170\ **Status:** Published normative specification of the DKE Library.\ **Audience:** Customers who load facts into a DKE store and reason over them; authors of fact producers, whether they use our package or write their own.\ **This document as Markdown:** [dke-library-spec.md](/spec/dke/library/dke-library-spec.md) — the same text this page is rendered from, for the producer authors above who would rather read the source than the page. --- ## 1. Status and scope This specification is normative for **the library** — the code LangSyn publishes for you to use, as opposed to the language you write or the wire you send it over. Two artifacts are in scope, and they are two halves of one story: | Artifact | What it is | Where it is served | |---|---|---| | **Reasoning modules** (`.dpy`) | DKE Python programs that supply the *reasoning* — a kind schema, standing rules, and queries | `https://dke.langsyn.com/source//`, one path per module | | **`dkepy`** (Python package) | The package that writes the *facts* those modules reason over | `https://dke.langsyn.com/source/dkepy/` | **`dkekey`**, the key tool served beside them at `https://dke.langsyn.com/source/dkekey/`, is not specified here: the store key it issues is specified by [MCP Reference §3.1](/ref/dke/mcp/#issuing-a-store-key-on-your-own-machine), which `dke.keys` in `dkepy` implements too. A module supplies the reasoning; a producer supplies the facts. Neither is useful without the other, and the thing that binds them — the vocabulary they must agree on — belongs to neither and is specified in §5. **What is normative here and what is not.** The [Library Reference](/ref/dke/library/) describes what the published modules and `dkepy` contain and stands on its own authority as a description. This document states the same surface as a **contract**: what you may depend on, what may change under you, and what a conformant producer must do. Where the two disagree, this document governs. **Names are English.** Every kind name, field name, rule name and query name below is written in English, as the library's identifiers are. This is a separate question from the `language` parameter of the wire, which selects the *keyword* surface of the program you send and is specified in the [MCP Reference](/ref/dke/mcp/). **Out of scope.** The DKE Python language itself ([Python Specification](/spec/dke/python/)); the wire protocol ([MCP Reference](/ref/dke/mcp/)); the contents of *your* store, which are yours. ### 1.1 Conformance language **MUST** / **MUST NOT** state a requirement; violating one is an error, though not always one a machine catches — §5.4 says exactly which are checked. **SHOULD** states a strong recommendation with a stated cost for departing. **MAY** states a permission. A **conformant producer** is any program that writes facts a published module reasons over, whether or not it uses `dkepy`. --- ## 2. The shared vocabulary A reasoning module declares kinds and fields. A producer writes values into them. **The names are the interface** — there is no registration step, no handshake, and no negotiation: a fact lands where its name says it lands, or it lands somewhere nothing reads. ### 2.1 Naming - A kind name is **scoped to its module**: `code.Function` and `finance.Function` are different kinds and never read each other's data. - Kind names are `CapitalizedWords`. Field names are `lower_snake_case`. - A producer MUST write the kind name **exactly** as the module declares it. Case and spelling are the whole of the matching; nothing corrects a near miss. §5.4 names the one check that catches this and the ones that do not. - A subject identifies one thing of that kind. Subjects are the producer's to choose, MUST be stable across loads for the same thing, and MUST be used consistently: §3.3 gives the case where a display name in a subject position silently corrupts every answer. ### 2.2 Value classes A field declares one of the writable value classes of the DKE Python language — `string`, `int`, `bool`, and the others given in the [Python Specification §5](/spec/dke/python/). This document adds no value classes and no coercions. A producer SHOULD write the declared class; a mismatch is not caught by any library-level check (§5.4). ### 2.3 Three ways a field gets its value This distinction is load-bearing throughout §3, and getting it wrong is the most common way a store produces confident wrong answers. | Field | Written by | Read by | |---|---|---| | **Declared field** | you, or your producer | rules and queries | | **Derived field** | the engine, kept current as its inputs change | rules and queries | | **Rule conclusion** | the engine, in force exactly while its condition holds | queries | A producer **MUST NOT** write a derived field or a rule conclusion. They are maintained for you and carry a `derived` provenance rather than a source, so a conclusion is always distinguishable from something you were told. ### 2.4 Absence is a value Several rules in §3 read the **absence** of a field, not its contents. This is the sharpest edge in the library, so it is stated as a requirement rather than as advice: > A producer MUST write an absence-read field **only where the thing it records > is actually true**, and MUST NOT write a placeholder, an empty string, or a > default into one. Writing such a field everywhere does not make a rule fire everywhere — it **silences the rule everywhere**, and the store then answers every question with the same list while nothing reports a fault. §3.3 names which fields these are. `checkup` distinguishes "nothing reaches these" from "nothing was looked for"; §4.4 says how. --- ## 3. Reasoning modules ### 3.1 What a module may declare Five declaration forms, all of which become part of your store the moment you `import` the module: | Declaration | Written by | Normative note | |---|---|---| | **Class** | the module | Declares a kind and its fields. | | **Derived field** | the module | A field whose value is an expression over other fields of the same kind. | | **Standing rule** | the module | Concludes one field about the subjects it binds. | | **Standing constraint** | the module | A condition over your facts. `checkup` reports each subject that breaks it; it refuses no write. | | **Query** | the module | A `def` you call by name, answering over the facts you have loaded. | A module MUST NOT contain anything else that persists. Module semantics in general — how `import` resolves, how namespacing works, what re-submitting does — are the language's, in the [Python Reference §9](/ref/dke/python/#modules). Every standing rule in `code` ranges over **one** kind. The language allows more — a rule may bind subjects of several kinds and relate them ([Python Reference §8.8](/ref/dke/python/#standing-rules)) — but `code` asks each of its questions of a field on the subject being asked about. That is why several fields in §3.3 look redundant: an observation another kind also records is recorded again on the side that reads it. ### 3.2 The published modules Twenty-four modules are published, each served at `https://dke.langsyn.com/source//` under its version, with a `latest` alias: | Module | Reasons about | Specified in | |---|---|---| | **`code`** | a codebase | §3.3 through §3.6 | | **`identity`** | which of your records name the same thing | §3.7 through §3.9 | | **`argument`** | which of your claims stand, given what supports and attacks what | §3.10 through §3.12 | | **`agenda`** | what is overdue, coming up, late or forbidden among your commitments and obligations | §3.13 through §3.15 | | **`quantum`** | quantum circuits: simulating one, which gates a device cannot run as written, and whether a result computed outside the store still holds | §3.16 through §3.18 | | **`pqc`** | which uses of quantum-vulnerable cryptography to move first, and which miss a deadline | §3.19 through §3.22 | | **`harmony`** | four-part writing as a harmony teacher marks it, the rhythm of a melody against its bars, and the arithmetic of tuning, set classes, twelve-tone rows and even rhythms | §3.23 through §3.26 | | **`physics`** | quantities in their units, the dimensions of equations and resistors in series and parallel, and the calculation of classical motion, heat, circuits and a magnet | §3.27 through §3.30 | | **`chemistry`** | the hydrogens, formula, weight and functional groups of a molecule drawn as atoms and bonds, a reaction's enthalpy by Hess's law, and the calculation of formulas, balanced equations, pH and kinetics | §3.31 through §3.34 | | **`biology`** | what a metabolic network can make from its medium, ancestry, carriers and what a mode of inheritance cannot explain in a pedigree, and the calculation of the genetic code, crosses, populations, drift and repressor rings | §3.35 through §3.37 | | **`astronomy`** | which stars never set, never rise or can be seen from a site, which bookings an instrument can observe given the night and the star's time above the horizon, and the calculation of Julian dates, sidereal time, rising and setting, the Sun, day length and orbits | §3.38 through §3.41 | | **`geography`** | regions inside regions, which regions neighbour which and which neighbours share a colour, which places lie in which boxes of latitude and longitude, and the calculation of distances, bearings, projections and areas on the Earth | §3.42 through §3.44 | | **`mathematics`** | whole numbers by their divisors, finite operations by their tables, and triangles by their sides, and the calculation of number theory, counting, continued fractions and numerical methods | §3.45 through §3.48 | | **`statistics`** | the strata of a study and whether pooling them reverses what each shows, screening tests by what a positive result is worth, and significance tests, and the calculation of descriptive statistics, distributions, tests and a seeded generator | §3.49 through §3.52 | | **`earthscience`** | the climate group of a weather station, the category of a storm by its wind and which of two minerals scratches the other, and the calculation of the atmosphere and the solid Earth | §3.53 through §3.56 | | **`computing`** | whether the words of a binary code can be read without a separator, and the calculation of checksums, check digits, number bases, error-correcting codes, entropy, Huffman codes and shortest paths | §3.57 through §3.60 | | **`calendars`** | which years are leap years under the Julian and the Gregorian rule and which the two disagree about, how many days a calendar reform skipped and which days fall in its gap, and the calculation of month lengths, weekdays, Easter, day numbers and spans | §3.61 through §3.64 | | **`colour`** | which contrast levels a colour pair clears and whether a ray is totally reflected, and the calculation of luminance, contrast, hue, refraction, lenses, Wien's law and frequency | §3.65 through §3.68 | | **`body`** | which antigens a donor's blood group has that a recipient's lacks and what that means for a transfusion, the band of a body mass index, and the calculation of the index, resting energy, body surface and maximum heart rate; not medical advice | §3.69 through §3.72 | | **`sound`** | whether a noise exposure or a worker's day is over a limit and whether a frequency is audible, and the calculation of decibels, distance, the speed of sound, wavelength, the Doppler shift and a time-weighted average; not occupational-health advice | §3.73 through §3.76 | | **`finance`** | which of several loan offers costs the least in total and which carry a payment over a household's limit, and the calculation of payments, compound interest, effective rates, doubling time, present value and real rates; not financial advice | §3.77 through §3.80 | | **`food`** | whether a dish was cooked to the minimum internal temperature of its kind or held too long in the danger zone and which of the nine major allergens it holds, and the calculation of a recipe's scale, baker's percentages, mass of a volume and food energy; not food-safety or medical advice | §3.81 through §3.83 | | **`architecture`** | which style a building's features make, which structure and which building was the tallest when it was completed, whether a tower tips, a hull is unstable, a room rings too long or too short and a channel falls too little, and the calculation of a lean, Sabine's reverberation time, a hull's metacentric height, a gradient and a pendulum; not engineering, naval-architecture, acoustic-design or heritage advice | §3.84 through §3.87 | | **`elections`** | who wins an election under plurality, majority, the Condorcet method and the Borda count, whether no candidate beats every other head to head and whether a count is disputed, an instant-runoff count, and the calculation of the Hare and Droop quotas and of a house's seats by largest remainders and by the D'Hondt, Sainte-Lague and Huntington-Hill methods; not legal or electoral advice | §3.88 through §3.91 | `code` reasons about **whatever codebase you load**. It describes no particular one, and it ships no facts. ### 3.3 `code` — declared fields A producer writes these. Fields marked **absence-read** are governed by §2.4. **`Function`** | Field | Class | Notes | |---|---|---| | `name` | `string` | | | `module` | `string` | A path. It hints at language at best; no query may rely on it for that. | | `lines` | `int` | | | `branches` | `int` | What counts as a branch is the producer's decision, so two producers MAY disagree on scale. | | `loops` | `int` | | | `deprecated` | `bool` | Typically supplied by hand rather than by a producer. | | `language` | `string` | Optional, absent-tolerant. What makes a polyglot store sliceable, and what makes two producers distinguishable. | | `test` | `string` | **Absence-read.** A test *seen to reach* this function. Reaching is not executing: this is not a coverage measurement. | | `returns_ignored` | `int` | Calls whose return value is not bound, tested, or handed onward. | | `called` | `bool` | **Absence-read.** Recorded on the callee's side as well as in a `Call`, so `uncalled` reads a field of the function itself (§3.1). | | `callers` | `int` | Distinct callers, not call sites. Write it for **every** function including zero — it is read by comparison, not by absence. | | `callees` | `int` | Distinct callees. Same rule as `callers`. | | `explained` | `bool` | **Absence-read.** A reason was written down; see `Rationale`. | **`Class`** — `name: string`, `module: string`, `methods: int`, `language: string` (optional, as on `Function`). **`Call`** — `caller: string`, `callee: string`, `site: string`. > `caller` and `callee` MUST hold the **subject** of a `Function`, never its > display name. The queries compare; they cannot tell a name from a subject. A > display name here makes every function look uncalled, and nothing reports an > error. **`UnresolvedCall`** — `caller: string` (a `Function` subject), `site: string`, `text: string` (the callee as written). > A call whose target could not be named. **No edge is asserted here, and a > producer MUST NOT assert one.** A missing edge is a known gap; a guessed edge > is a wrong answer the queries cannot tell from a fact. Absent-tolerant: record > none and everything else works, with `dispatch_sites()` returning nothing. **`Rationale`** — `subject: string` (the `Function` or `Class` it explains), `marker: string`, `text: string`, `site: string`. > **Stated, never inferred.** Which comments count is the producer's decision. > Whatever convention is chosen, it SHOULD be one an author had to type on > purpose: a convention wide enough to sweep ordinary comments turns every line > into a fact and the query into noise. **`Import`** — `importer: string`, `imported: string`, `root: string`. **`Dependency`** — `name: string`, `version: string`, `direct: bool`, `pinned: bool`. **`Counterpart`** — `name: string`, `left: string`, `right: string`, `relation: string`, `left_covers: int`, `right_covers: int`. > Two functions that have to agree. **Stated, never inferred** — agreement is a > claim about intent and no call graph can see it. `relation` names what is > being counted, because it differs per pair; `left_covers` and `right_covers` > count members of *that* set and are comparable to each other and to nothing > else. This is the one kind no producer LangSyn publishes writes (§5.2). ### 3.4 `code` — derived fields Maintained by the engine. A producer MUST NOT write one. | Field | Definition | |---|---| | `Function.complexity` | `branches + loops + 1` | | `Counterpart.gap` | `left_covers - right_covers` | | `Counterpart.reverse_gap` | `right_covers - left_covers` | Both directions of the gap are kept, each reading as a positive magnitude where it applies, because a query cannot negate a claim's value. ### 3.5 `code` — standing rules Each holds continuously: its conclusion is in force exactly while its condition holds over your data, and withdraws itself when the condition stops holding. | Rule | Over | Concludes | While | |---|---|---|---| | `hotspot` | `Function` | `hotspot` | `complexity > 10` | | `oversized` | `Function` | `oversized` | `lines > 200` | | `sprawling_class` | `Class` | `sprawling` | `methods > 20` | | `hub` | `Function` | `hub` | `callers > 5` | | `untested` | `Function` | `untested` | `lines > 0` and `test` absent | | `uncalled_fn` | `Function` | `uncalled` | `lines >= 0` and `called` absent | | `critical_untested` | `Function` | `critical_untested` | `complexity > 10` and `test` absent | | `unexplained_critical` | `Function` | `unexplained_critical` | `complexity > 10`, `test` absent, `explained` absent | | `discards_result` | `Function` | `discards_result` | `returns_ignored > 0` | | `left_stricter` | `Counterpart` | `left_stricter` | `gap > 0` | | `right_stricter` | `Counterpart` | `right_stricter` | `gap < 0` | Two notes that are contract rather than commentary: - **The thresholds are values, not percentiles.** `> 10`, `> 200`, `> 20`, `> 5` select whatever your store has, and select nothing when your store has nothing. A percentile would always name someone, including in a codebase with no hub at all. They are yours to argue with; they are not adaptive. - **A rule cannot be all absences.** `untested` and `uncalled_fn` carry a positive premise (`lines > 0`, `lines >= 0`) as a *range*, not a filter — a rule whose every premise is an absence has no set to work over and is refused. ### 3.6 `code` — queries Called by name after `import code`. Every one answers over the facts you have loaded, and over nothing else. | Query | Answers | |---|---| | `callers_of(fn)` | Functions that call `fn`, directly. | | `callees_of(fn)` | Functions `fn` calls, directly. | | `impact_of(fn)` | Who breaks if `fn` changes: callers, and their callers, **to depth 3**. | | `importers_of(mod)` | Modules importing `mod`. | | `functions_in(lang)` | Functions recorded with `language` = `lang`. | | `hotspots_in(lang)` | Hotspots, narrowed to one language. | | `uncalled()` | Functions nothing was seen to call. | | `hubs()` | Functions many things depend on. | | `rationale_for(fn)` | Reasons recorded against `fn`. | | `unexplained()` | Critical functions carrying no recorded reason. | | `dispatch_sites()` | Calls whose target could not be named. | | `unused_dependencies()` | Declared dependencies nothing imports. | | `unpinned_dependencies()` | Dependencies with no pin. | | `asymmetries()` | Counterpart pairs where one side checks more. | | `discarded_results()` | Functions throwing a result away. | | `critical()` | Complicated and unreached. | `impact_of` walks to a **fixed depth**, not until nothing new is reached. That is a stated bound, not an approximation to be improved: the language guarantees termination and a reachability closure is not something it will run. **An empty answer is an answer.** It means no loaded fact satisfies the question — which is different from the question being unanswerable, and different again from the field being empty because nobody wrote it. §4.4. ### 3.7 `identity` — declared fields You write these; no producer in `dkepy` writes them. **`Record`** | Field | Class | Notes | |---|---|---| | `name` | `string` | For reading. No rule reads it: a name a statement uses is a record whether or not one is recorded here. | **`Same`**, **`Possibly`**, **`Different`** — each a *statement*, with `a: string` and `b: string` holding the names of the two records it is about. A statement's own name carries no meaning and only keeps two statements apart. Names are matched exactly. A name a statement uses and no `Record` carries is not an error: it is a record to every rule below. `unrecorded()` (§3.9) lists such names. ### 3.8 `identity` — standing rules Each holds continuously: its conclusion is in force exactly while its condition holds over your data, and withdraws itself when the condition stops holding. Four rules conclude a **relation**, a three-segment path read as `SameEntity.x.y`, rather than a field. | Rule | Over | Concludes | While | |---|---|---|---| | `same_stated` | `Same`, `Record` | `SameEntity` | a statement's `a` names `x` and its `b` names `y`; concludes `SameEntity.x.y` | | `same_stated_back` | `Same`, `Record` | `SameEntity` | the same statement; concludes `SameEntity.y.x` | | `same_further` | `Record` | `SameEntity` | `SameEntity.x.y` and `SameEntity.y.z`; concludes `SameEntity.x.z` | | `possibly_stated` | `Possibly`, `Record` | `PossiblySame` | a statement's `a` names `x` and its `b` names `y`; concludes `PossiblySame.x.y` | | `possibly_stated_back` | `Possibly`, `Record` | `PossiblySame` | the same statement; concludes `PossiblySame.y.x` | | `contradicted` | `Different`, `Record` | `contradicted` | the statement's `a` and `b` name `x` and `y`, and `SameEntity.x.y` holds | | `contested_a` | `Different`, `Record` | `contested` | a `contradicted` statement's `a` names the record | | `contested_b` | `Different`, `Record` | `contested` | a `contradicted` statement's `b` names the record | Four notes that are contract rather than commentary: - **The relations are not namespaced.** `SameEntity` and `PossiblySame` are read by those bare names in every unit, and are never `identity.SameEntity`. A unit that declares a `class` of either name reads its own class by that name. - **`SameEntity` is closed; `PossiblySame` is not.** A record in any chain of `Same` statements is related to every record the chain reaches, itself included. A possibility relates exactly the two records a statement names. - **A `Different` statement withdraws nothing.** It and every `Same` statement it contradicts stand together; the contradiction is concluded, not resolved. - **The closure is quadratic in an entity.** An entity of *n* records holds *n*² `SameEntity` conclusions. ### 3.9 `identity` — queries Called by name after `import identity`. Every one answers over the facts you have loaded, and over nothing else. | Query | Answers | |---|---| | `same_as(r)` | Every other record `SameEntity` relates to `r`. | | `possibly_same_as(r)` | Every other record `PossiblySame` relates to `r`. | | `contested()` | Records named by a `contradicted` statement. | | `contradictions()` | `Different` statements concluded `contradicted`, by name. | | `unrecorded()` | Names a statement uses that no `Record` carries. | ### 3.10 `argument` — declared fields You write these; no producer in `dkepy` writes them. **`Claim`** | Field | Class | Notes | |---|---|---| | `text` | `string` | For reading. No rule reads it: a name a statement uses is a claim whether or not one is recorded here. | **`Support`**, **`Attack`**, **`Weakening`** — each a *statement*, with `by: string` naming the claim that supports, attacks or weakens, and `target: string` naming the claim it bears on. A statement's own name carries no meaning and only keeps two statements apart. A statement bears on nothing until both fields are written. Names are matched exactly. A name a statement uses and no `Claim` carries is not an error: it is a claim to every rule below. `unrecorded()` (§3.12) lists such names. ### 3.11 `argument` — standing rules Each holds continuously: its conclusion is in force exactly while its condition holds over your data, and withdraws itself when the condition stops holding. | Rule | Over | Concludes | While | |---|---|---|---| | `attack_reaches` | `Attack`, `Claim` | `attacked` | an attack's `by` names a claim and its `target` names this one | | `weakening_reaches` | `Claim`, `Weakening` | `weakened` | a weakening's `by` names a claim and its `target` names this one | | `nothing_attacks` | `Claim` | `unattacked` | no attack with a `by` names this claim as its `target` | | `attack_stands` | `Attack`, `Claim` | `undefended` | an attack targets this claim, and the claim its `by` names is `unattacked` | | `attack_answered` | `Attack`, `Claim` | `answered` | the claim this attack's `by` names is `undefended`; concluded on the attack | | `every_attack_answered` | `Claim` | `reinstated` | this claim is `attacked`, and every attack with a `by` that targets it is `answered` | | `premise_attacked` | `Claim`, `Support` | `contested` | the claim a support's `by` names is `attacked`, and its `target` names a claim; concluded on the support | Four notes that are contract rather than commentary: - **Two steps, then silence.** A claim is `unattacked`, `undefended` or `reinstated`, or it is named by none of the three: it is *open*. Claims that attack one another, and the claims such a chain reaches, are open. No answer says an open claim falls. - **A weakening decides nothing.** It concludes `weakened` and takes part in no other rule. - **A support is not a defence.** It takes part only in `premise_attacked`. - **No relation is concluded.** Every field `argument` derives is on one of its own kinds. ### 3.12 `argument` — queries Called by name after `import argument`. Every one answers over the facts you have loaded, and over nothing else. Each answers a sorted list of names. | Query | Answers | |---|---| | `supporters_of(c)` | The `by` of every `Support` whose `target` is `c`. | | `attackers_of(c)` | The `by` of every `Attack` whose `target` is `c`. | | `weakeners_of(c)` | The `by` of every `Weakening` whose `target` is `c`. | | `unattacked()` | Claims concluded `unattacked`. | | `undefended()` | Claims concluded `undefended`. | | `reinstated()` | Claims concluded `reinstated`. | | `weakened()` | Claims concluded `weakened`. | | `contested_premises()` | The `by` of every `Support` concluded `contested`. | | `unrecorded()` | Names a statement uses that no `Claim` carries. | ### 3.13 `agenda` — declared fields You write these; no producer in `dkepy` writes them. **`Goal`** | Field | Class | Notes | |---|---|---| | `text` | `string` | For reading. No rule reads it: a name a commitment serves is a goal whether or not one is recorded here. | **`Commitment`** | Field | Class | Notes | |---|---|---| | `action` | `string` | What is undertaken. Compared exactly with a prohibition's `action`. | | `due` | `datetime` | When it is due. A later `update` from the same source replaces it and keeps the value it replaced. | | `serves` | `string` | The goal it is for. Optional. | | `done_at` | `datetime` | When it was done. Absent while it is open. | **`Obligation`** | Field | Class | Notes | |---|---|---| | `action` | `string` | What is owed. Compared exactly with a prohibition's `action`. | | `due` | `datetime` | When it is due, as for a commitment. | | `owed_to` | `string` | Who it is owed to. For reading; no rule reads it. | | `done_at` | `datetime` | When it was done. Absent while it is open. | **`Prohibition`** | Field | Class | Notes | |---|---|---| | `action` | `string` | An action that may not be taken. The claim's validity window, if it has one, is when the prohibition applies. | Names are matched exactly. A name a commitment serves and no `Goal` carries is not an error: it is a goal to every rule below. `unrecorded()` (§3.15) lists such names. ### 3.14 `agenda` — standing rules Each holds continuously: its conclusion is in force exactly while its condition holds over your data, and withdraws itself when the condition stops holding. | Rule | Over | Concludes | While | |---|---|---|---| | `commitment_forbidden` | `Commitment`, `Prohibition` | `forbidden` | the commitment's `action` equals a prohibition's `action`; valid where the two claims' windows overlap | | `obligation_forbidden` | `Obligation`, `Prohibition` | `forbidden` | the obligation's `action` equals a prohibition's `action`; valid where the two claims' windows overlap | | `commitment_late` | `Commitment` | `late` | the commitment's `done_at` is later than its `due` | | `obligation_late` | `Obligation` | `late` | the obligation's `done_at` is later than its `due` | | `goal_pursued` | `Commitment`, `Goal` | `pursued` | a commitment's `serves` names the goal | | `goal_met` | `Goal` | `met` | the goal is `pursued`, and no commitment serving it lacks a `done_at` | Two standing constraints are reported by `checkup` and refuse no write. `nothing_forbidden_committed` is violated by each `Commitment` that is `forbidden` and has no `done_at`, and `nothing_forbidden_owed` by each such `Obligation`. Four notes that are contract rather than commentary: - **No rule reads the present.** Every rule compares recorded values with each other. What depends on the time is a query, and takes the time as `at`. - **A prohibition is not enforced.** It concludes `forbidden` and violates a constraint; it removes and refuses nothing. - **`late` needs both dates.** An item with no `done_at`, or no `due`, is never `late`, whatever the time. - **No relation is concluded.** Every field `agenda` derives is on one of its own kinds. ### 3.15 `agenda` — queries Called by name after `import agenda`. Every one answers over the facts you have loaded, and over nothing else. Each answers a sorted list except `previous_dues`, which keeps the order the dates were given. A commitment is named `Commitment.` and an obligation `Obligation.`. An item is **open at** `at` when it has no `done_at`, or its `done_at` is later than `at`. | Query | Answers | |---|---| | `overdue(at)` | Commitments and obligations open at `at` whose `due` is earlier than `at`. | | `due_within(at, span)` | Commitments and obligations open at `at` whose `due` is at or after `at` and earlier than `at + span`. | | `unsettled(at)` | Commitments and obligations whose `due` or `done_at` holds two values in force at `at`. `overdue` and `due_within` omit these. | | `forbidden(at)` | Commitments and obligations open at `at` and concluded `forbidden` at `at`. | | `blocked()` | Commitments and obligations with no `done_at` whose `due` holds one value, at which they are concluded `forbidden`. | | `late()` | Commitments and obligations concluded `late`. | | `met()` | Goals concluded `met`, by name. | | `serving(g)` | Commitments whose `serves` is `g`. | | `previous_dues(item)` | The `due` values `item` held before the one in force now, oldest first, as RFC 3339 text. Empty when the item's `due` holds two values in force. | | `unrecorded()` | Names a commitment serves that no `Goal` carries. | ### 3.16 `quantum` — declared fields `quantum` has two halves that share nothing but the subject. The simulation half declares one kind, `State`, and is otherwise functions over values (§3.18). The reasoning half declares the rest. `dke.quantum.device` (§4.5) writes `Device`, `PhysicalQubit` and `Native`; `dke.quantum.provenance` writes `Result` and a circuit's `digest`; the module records its own `Op` facts when it is imported. You write the rest. **`State`** | Field | Class | Notes | |---|---|---| | `amplitudes` | `blob` | A state's amplitudes in index order, sixteen bytes each: a complex as two little-endian IEEE 754 doubles. Written by `save` and `keep` (§3.18). | **`Gate`** | Field | Class | Notes | |---|---|---| | `op` | `string` | The operation, named as an `Op` subject is: `h`, `cnot`, `rz`. | | `a` | `string` | The qubit it acts on, by name. A compiled circuit names a qubit by its number, as text. | | `b` | `string` | The second qubit of a two-qubit gate. Absent for a one-qubit gate. | | `step` | `int` | Its position. Gates are ordered by `step` within one circuit. | | `circuit` | `string` | The `Circuit` it belongs to. Optional: the gates that name none are one circuit together. | **`Qubit`** | Field | Class | Notes | |---|---|---| | `label` | `string` | For reading. No rule reads it: the rules compare the names gates use. | **`Coupler`** | Field | Class | Notes | |---|---|---| | `a` | `string` | One qubit of a pair the chip can act on together. | | `b` | `string` | The other. A coupler joins its pair in either order. | **`Op`** | Field | Class | Notes | |---|---|---| | `qubits` | `int` | How many qubits the operation takes. | | `diagonal` | `bool` | Whether it is diagonal. Diagonal operations commute with one another. | The module records `qubits` and `diagonal` for `h`, `x`, `y`, `z`, `s`, `t`, `rx`, `ry`, `rz`, `cnot`, `cz`, `sx`, `id`, `ecr`, `swap` and `rzz` when it is imported, under the source `quantum`. Record another operation the same way. **`Device`** | Field | Class | Notes | |---|---|---| | `qubits` | `int` | How many physical qubits it has. | | `snapshot_at` | `datetime` | When the calibration snapshot its facts were read from was taken. | | `digest` | `string` | The snapshot's digest (§4.5), which names the calibration exactly. | **`PhysicalQubit`** | Field | Class | Notes | |---|---|---| | `device` | `string` | The `Device` it belongs to. | | `index` | `string` | Its number, as text, which is how a compiled circuit's gates name it. | | `t1` | `real` | Its relaxation time, in microseconds. | | `t2` | `real` | Its dephasing time, in microseconds. | | `readout_error` | `real` | The probability that reading it out gives the wrong value. | | `measured_at` | `datetime` | When the latest of those three was measured. | **`Native`** | Field | Class | Notes | |---|---|---| | `device` | `string` | The `Device` that runs it. | | `op` | `string` | The operation, as the module names it: `cnot` where a device says `cx`. | | `a` | `string` | The qubit it runs on, or the first of an ordered pair, by index. | | `b` | `string` | The second of the pair. Absent for a one-qubit operation. The pair is ordered, because a device may run a two-qubit operation one way round only. | | `error` | `real` | The measured probability that it fails. | | `length` | `real` | Its duration, in nanoseconds. | | `measured_at` | `datetime` | When `error` was measured. Absent when no error is recorded. | **`Circuit`** | Field | Class | Notes | |---|---|---| | `device` | `string` | The `Device` it was compiled for. Optional: a circuit that names none is judged by no device rule. | | `digest` | `string` | The digest of the text it was written from (§4.5). The writer keeps it true; the store compares digests and never computes one. | **`Result`** | Field | Class | Notes | |---|---|---| | `circuit` | `string` | The circuit the result is about. | | `digest` | `string` | That circuit's digest, as the result's producer read it. | | `source` | `string` | The circuit it was derived from, if any. | | `source_digest` | `string` | That circuit's digest, as read. | | `device` | `string` | The device it was computed for, if any. | | `device_digest` | `string` | That device's digest, as read. | | `producer` | `string` | What produced it, with its version. No rule reads it. | | `settings` | `string` | How the producer was asked. No rule reads it. | | `seed` | `int` | The seed it drew from. No rule reads it. | | `outcome` | `string` | The result itself, as text. | Names are matched exactly. A qubit is compared by its name and is never bound as a subject, since a compiled circuit names its qubits by number. ### 3.17 `quantum` — standing rules Each holds continuously: its conclusion is in force exactly while its condition holds over your data, and withdraws itself when the condition stops holding. The rules over two gates relate only gates of one circuit: a gate's circuit is its `track`, and the gates that name no circuit share the empty track. | Rule | Over | Concludes | While | |---|---|---|---| | `gate_diagonal` | `Gate`, `Op` | `diagonal` | the gate's `op` names the operation; the gate takes the operation's `diagonal` | | `track_of_circuit` | `Gate` | `track` | the gate names a `circuit`, which is its track | | `track_of_none` | `Gate` | `track` | the gate has a `step` and names no `circuit`; its track is the empty string | | `shares_earlier_aa` | `Gate` | `RunsBefore` | two gates on one track, the first's `a` equal to the second's `a`, and the first's `step` earlier | | `shares_earlier_ab` | `Gate` | `RunsBefore` | as `shares_earlier_aa`, with the first's `a` equal to the second's `b` | | `shares_earlier_ba` | `Gate` | `RunsBefore` | as `shares_earlier_aa`, with the first's `b` equal to the second's `a` | | `shares_earlier_bb` | `Gate` | `RunsBefore` | as `shares_earlier_aa`, with the first's `b` equal to the second's `b` | | `ordered_first` | `Gate` | `MustPrecede` | the first gate runs before the second, and the first is not diagonal | | `ordered_second` | `Gate` | `MustPrecede` | the first gate runs before the second, and the second is not diagonal | | `commutes` | `Gate` | `CommutesWith` | the first gate runs before the second, and both are diagonal | | `uncoupled` | `Gate`, `Op` | `uncoupled` | a two-qubit gate with no `device`, whose two qubits no `Coupler` joins in either order | | `gate_device` | `Gate`, `Circuit` | `device` | the gate's `circuit` names the circuit; the gate takes the circuit's `device` | | `gate_width` | `Gate`, `Op` | `width` | the gate's `op` names the operation; the gate takes the operation's `qubits` | | `op_on_device` | `Gate`, `Native` | `op_on_device` | the gate's device runs its `op` natively on some qubit or pair | | `first_on_device` | `Gate`, `PhysicalQubit` | `first_on_device` | the gate's device has a physical qubit whose `index` is the gate's `a` | | `second_on_device` | `Gate`, `PhysicalQubit` | `second_on_device` | the gate's device has a physical qubit whose `index` is the gate's `b` | | `runs_as_one` | `Gate`, `Native` | `RunsAs` | a one-qubit gate, and a native operation of its device with the same `op` on its `a` | | `runs_as_pair` | `Gate`, `Native` | `RunsAs` | a native operation of the gate's device with the same `op` on the same ordered pair | | `off_device_first` | `Gate`, `Device` | `off_device` | the gate's device has no physical qubit whose `index` is the gate's `a` | | `off_device_second` | `Gate`, `Device` | `off_device` | a two-qubit gate whose device has no physical qubit whose `index` is the gate's `b` | | `not_native` | `Gate`, `Device` | `not_native` | the gate's device runs its `op` on no qubit at all | | `not_here_one` | `Gate` | `not_here` | a one-qubit gate whose device runs its `op` and has its qubit, but does not run that operation on that qubit | | `not_here_pair` | `Gate` | `not_here` | a two-qubit gate whose device runs its `op` and has both its qubits, but runs it on that pair in neither order | | `reversed_pair` | `Gate`, `Native` | `reversed` | the gate's device runs its `op` on its pair the other way round, and not this way | | `illegal_off_device` | `Gate` | `illegal` | the gate is `off_device` | | `illegal_not_native` | `Gate` | `illegal` | the gate is `not_native` | | `illegal_not_here` | `Gate` | `illegal` | the gate is `not_here` | | `illegal_reversed` | `Gate` | `illegal` | the gate is `reversed` | | `circuit_current` | `Result`, `Circuit` | `circuit_current` | the result's `digest` equals the `digest` of its `circuit` | | `source_current` | `Result`, `Circuit` | `source_current` | the result's `source_digest` equals the `digest` of its `source` | | `source_none` | `Result` | `source_current` | the result has an `outcome` and names no `source` | | `device_current` | `Result`, `Device` | `device_current` | the result's `device_digest` equals the `digest` of its `device` | | `device_none` | `Result` | `device_current` | the result has an `outcome` and names no `device` | | `holds` | `Result` | `holds` | `circuit_current`, `source_current` and `device_current` all hold and the result is not `stopped`; concludes the result's `outcome` | | `unrecorded_circuit` | `Result` | `unrecorded` | the result has an `outcome` and no `circuit` | | `unrecorded_outcome` | `Result` | `unrecorded` | the result names a `circuit` and has no `outcome` | | `unrecorded_digest` | `Result` | `unrecorded` | the result names a `circuit` and has no `digest` | | `unrecorded_source_digest` | `Result` | `unrecorded` | the result names a `source` and has no `source_digest` | | `unrecorded_device_digest` | `Result` | `unrecorded` | the result names a `device` and has no `device_digest` | | `circuit_unknown` | `Result` | `circuit_unknown` | no `Circuit` the result names as its `circuit` has a `digest` | | `circuit_changed` | `Result`, `Circuit` | `circuit_changed` | the result's `digest` differs from the `digest` of its `circuit` | | `source_unknown` | `Result` | `source_unknown` | no `Circuit` the result names as its `source` has a `digest` | | `source_changed` | `Result`, `Circuit` | `source_changed` | the result's `source_digest` differs from the `digest` of its `source` | | `device_unknown` | `Result` | `device_unknown` | no `Device` the result names has a `digest` | | `recalibrated` | `Result`, `Device` | `recalibrated` | the result's `device_digest` differs from the `digest` of its `device` | | `stopped_unrecorded` | `Result` | `stopped` | the result is `unrecorded` | | `stopped_circuit_unknown` | `Result` | `stopped` | the result is `circuit_unknown` | | `stopped_circuit_changed` | `Result` | `stopped` | the result is `circuit_changed` | | `stopped_source_unknown` | `Result` | `stopped` | the result is `source_unknown` | | `stopped_source_changed` | `Result` | `stopped` | the result is `source_changed` | | `stopped_device_unknown` | `Result` | `stopped` | the result is `device_unknown` | | `stopped_recalibrated` | `Result` | `stopped` | the result is `recalibrated` | Two standing constraints are reported by `checkup` and refuse no write. `every_pair_coupled` is violated by each `Gate` that is `uncoupled`, and `every_gate_legal` by each `Gate` that is `illegal`. Five notes that are contract rather than commentary: - **Four relations are concluded.** `RunsBefore`, `MustPrecede` and `CommutesWith` relate two gates, the earlier first, and `RunsAs` relates a gate to the native operation it runs as. Every other conclusion is a field of a `Gate` or a `Result`. The queries of §3.18 read the relations. - **A gate is judged by one set of rules.** A gate whose circuit names a device is judged by the device's own qubits and operations, and `uncoupled` never holds for it. A gate whose circuit names no device is judged by the couplers alone. - **A device with no facts runs nothing.** A circuit naming a device the store holds no facts for has every gate `off_device` and `not_native`, which is also how a misspelt device name shows itself. - **A digest holding two values holds the result through neither.** When two sources disagree about a digest, every comparison with the other value concludes its reason, and the result does not hold. - **No rule reads the present.** What depends on the time is a query, and takes the time as `at`. ### 3.18 `quantum` — queries Called by name after `import quantum`. Qubit `q` is bit `q` of an amplitude's index, so qubit 0 is the lowest bit; a state of `n` qubits is a `list` of 2ⁿ amplitudes. A step, as `advance`, `advance_chacha`, `overlap`, `clifford`, `rev_code`, `rev_same` and `rev_meets` take one, is a tuple of a gate's name, the qubits it acts on and an angle that only the rotations read, or `("measure", [q], 0.0)`; a reversible circuit's steps are `x`, `cnot`, `ccx`, `z`, `cz`, `ccz`, `swap` and `cswap`, with a `theta` of 0.0, and `("mx", [q], 0.0)`, which measures `q` in the X basis and leaves it 0, with the controlled forms `x_if`, `cnot_if`, `ccx_if`, `z_if`, `cz_if`, `ccz_if`, `swap_if` and `cswap_if`, which take the measured qubit first and then the gate's own qubits. The functions over a state read and write no fact: | Query | Answers | |---|---| | `zero(n)` | The all-zero state on `n` qubits. | | `phase(theta)` | e raised to i·`theta`, as `cos(theta) + i·sin(theta)`. | | `h(psi, q)` | `psi` after a Hadamard gate on qubit `q`. | | `x(psi, q)` | `psi` after an X gate on qubit `q`. | | `y(psi, q)` | `psi` after a Y gate on qubit `q`. | | `z(psi, q)` | `psi` after a Z gate on qubit `q`. | | `s(psi, q)` | `psi` after an S gate on qubit `q`. | | `t(psi, q)` | `psi` after a T gate on qubit `q`. | | `rx(psi, q, theta)` | `psi` after a rotation of `theta` radians about X on qubit `q`. | | `ry(psi, q, theta)` | `psi` after a rotation of `theta` radians about Y on qubit `q`. | | `rz(psi, q, theta)` | `psi` after a rotation of `theta` radians about Z on qubit `q`. | | `cnot(psi, c, tg)` | `psi` after a controlled NOT with control `c` and target `tg`. | | `cz(psi, a, b)` | `psi` after a controlled Z on `a` and `b`. | | `sx(psi, q)` | `psi` after the square root of X on qubit `q`. | | `ecr(psi, a, b)` | `psi` after an echoed cross-resonance gate, with Qiskit's matrix and `a` as its first qubit. | | `swap(psi, a, b)` | `psi` with qubits `a` and `b` exchanged. | | `ccx(psi, a, b, tg)` | `psi` after a Toffoli gate: qubit `tg` flips when `a` and `b` are both 1. | | `ccz(psi, a, b, c)` | `psi` after a gate that negates the amplitudes whose qubits `a`, `b` and `c` are all 1. | | `cswap(psi, c, a, b)` | `psi` after a Fredkin gate: qubits `a` and `b` exchanged when `c` is 1. | | `probabilities(psi)` | The probability of each basis state, in index order. | | `weights(psi, q)` | The probability of qubit `q` being 0 and of its being 1, each summed in index order. | | `collapsed(psi, q, bit, norm)` | The amplitudes whose qubit `q` is `bit`, each times `norm`, and zero elsewhere. | | `measure(psi, q, u)` | Qubit `q` measured: 0 when `u` is below the probability of 0, and 1 otherwise, with the state that outcome leaves, renormalised. | | `tableau(n)` | Aaronson and Gottesman's stabilizer tableau of the all-zero state on `n` qubits: 2n + 1 rows of 2n + 1 bits. | | `pauli_phase(x1, z1, x2, z2)` | The power of i that multiplying Pauli (`x1`, `z1`) into (`x2`, `z2`) contributes. | | `row_product(hrow, irow, n)` | Row `hrow` multiplied by row `irow`, with the sign worked out modulo 4. | | `tab_h(tab, a)` | `tab` after a Hadamard gate on qubit `a`. | | `tab_s(tab, a)` | `tab` after an S gate on qubit `a`. | | `tab_cnot(tab, a, b)` | `tab` after a controlled NOT with control `a` and target `b`. | | `tab_measure(tab, a, u)` | Qubit `a` measured on `tab`, with the tableau that leaves. A random outcome is 1 exactly when `u` is at least one half; a determined one does not read `u`. | | `tab_gate(tab, name, q)` | `tab` after the Clifford gate `name` on the qubits `q`, up to a global phase. | | `clifford(n, steps)` | The tableau of a Clifford circuit of `steps` on `n` qubits, from the all-zero state. | | `lcg_next(state)` | The next state of Park and Miller's minimal standard generator, multiplier 48271 and modulus 2³¹ − 1. A seed is an int from 1 to 2³¹ − 2. | | `lcg_uniform(state)` | The generator state as a value in (0, 1). | | `chacha_quarter(w, a, b, c, d)` | `w` after ChaCha20's quarter round, RFC 8439, section 2.1, on its words `a`, `b`, `c` and `d`. `w` is changed in place, and is the list answered. | | `chacha_block(key, counter, nonce)` | The ChaCha20 block of RFC 8439, section 2.3, as its 16 words in order, for a `key` of 8 words, a block `counter` and a `nonce` of 3 words, each from 0 to 0xFFFFFFFF. Raises `ValueError` for any other. | | `chacha_unit(block, i)` | Value `i` of `block`: (`block[2·i]` >> 5) · 2²⁶ + (`block[2·i + 1]` >> 6), divided by 2⁵³, an exact value in [0, 1). | | `chacha_uniform(key, n)` | `chacha_unit` of value `n` mod 8 of the block at counter `n` // 8 with a nonce of three zeros, for a stream position `n` from 0 to 2³⁵ − 1. Raises `ValueError` for any other position. | | `unitary(name, theta)` | The matrix of gate `name`; `theta` is read by `rx`, `ry` and `rz` only. | | `adjoint(m)` | The conjugate transpose of `m`. | | `overlap(n, steps, back, j)` | Amplitude `j` after running `steps` and then undoing `back`, on basis state `j`. Two circuits equal up to a global phase answer the same value for every `j`. | | `rev_code(n, steps)` | The steps of a reversible circuit on `n` qubits as `(operation, a, b, c)`: operations 0 to 7 for `x`, `cnot`, `ccx`, `z`, `cz`, `ccz`, `swap` and `cswap`, with the qubits in the order the gate's function takes them, and 8 for `mx` on `a`, with its number among the `mx` steps in `b`. A controlled step `_if` is its gate's operation plus 16·(1 + `j`), `j` the number of the latest `mx` of its first qubit, and the qubits it answers are the gate's own. Raises `ValueError` for any other gate, a count of qubits other than the step's (the measured qubit of a controlled step included), a qubit outside 0 to `n` − 1, a qubit named twice in one step (the measured one included), and a controlled step whose first qubit no earlier `mx` measured. | | `rev_apply(w, code)` | Runs what `rev_code` answered on the wires `w`, one `int` for each qubit whose bit `k` is that qubit in input `k` of 64, changing `w` in place, and answers the sign of the 64 inputs, bit `k` set where input `k`'s is −1. Every outcome of an `mx` is 0. | | `rev_apply_under(w, code, outcomes)` | `rev_apply` with the outcome of the `j`-th `mx` the bit `j` of `outcomes`, the same for all 64 inputs. An `mx` under outcome 1 negates the sign of the inputs where its qubit is 1, and under either sets the qubit to 0; a controlled step runs only where the outcome it names is 1. | | `rev_measures(code)` | The number of `mx` steps in what `rev_code` answered. | | `lowest_lane(m)` | The lowest bit set in the nonzero 64-bit `int` `m`, from 0 to 63. | | `rev_same(n, a, b)` | Whether reversible circuits `a` and `b` on `n` qubits are equal, on all 2**`n` inputs, as `(holds, 2**n, first, why)`. They are equal when, on every input, they leave the same bits under one sign shared by every input: the sign of the two at input 0 is the shared one, and `first` is the lowest input where the bits differ or the sign differs from it, with `why` `"output"` or `"sign"`, `"output"` when both. When they are equal `first` is −1 and `why` is `""`. Raises `ValueError` when either circuit holds an `mx` or a controlled step: a circuit that measures is held to a specification with `rev_meets`, where every qubit but the inputs starts at 0. Input `x` puts bit `q` of `x` on qubit `q`. | | `rev_meets(n, steps, ins, outs, want, signs)` | Whether the reversible circuit `steps` on `n` qubits meets a specification, on all 2**len(`ins`) inputs under every assignment of the outcomes of its `mx` steps, as `(holds, the cases, first, why)`: the cases are 2**len(`ins`) times 2 for each `mx`, and case `i` is input `i` mod 2**len(`ins`) under the outcomes `i` div 2**len(`ins`), outcome `j` being the `j`-th `mx`. The sign is exact in every case. Input `x` puts bit `j` of `x` on qubit `ins[j]` and every other qubit starts at 0. At the end the qubits `ins` hold what they held, no qubit outside `ins` and `outs` is 1, the qubits `outs` hold `want[x]` with bit `j` on qubit `outs[j]`, and the sign is −1 exactly when `signs[x]` is nonzero (an empty `signs` is +1 for every input). `first` is the lowest case that fails and `why` the first of `"input"`, `"ancilla"`, `"output"` and `"sign"` that holds there; a circuit that holds answers −1 and `""`. Raises `ValueError` when `want` is not 2**len(`ins`) values, `signs` is neither empty nor that many, a qubit is outside the circuit or named twice among `ins` and `outs`, a value of `want` does not fit `outs`, or the cases would be more than 2**62. | These read or write a state kept in the store as `State.`: | Query | Answers | |---|---| | `save(name, psi)` | Nothing. Keeps `psi` under `name`, replacing any state kept there. | | `load(name)` | The state kept under `name`, bit for bit, or an empty list when none is. | | `drop(name)` | Nothing. Forgets the state kept under `name`. | | `packed(name)` | The bytes kept under `name`, or an empty blob when none are. | | `keep(name, b)` | Nothing. Keeps the bytes `b` under `name`, as `save` keeps a state. | | `advance(name, steps, u)` | Runs `steps` on the state kept under `name` and keeps the state it ends with. Each measurement takes `lcg_uniform(u)`, then `u` becomes `lcg_next(u)`. Answers the generator state it ended with and the bits it measured. | | `advance_chacha(name, steps, key, n)` | As `advance`, with each measurement taking `chacha_uniform(key, n)`, then `n` becoming `n + 1`. Answers the position it ended at and the bits it measured. Raises `ValueError` when `n`, or a position a measurement would take, is outside 0 to 2³⁵ − 1. | | `weigh(name, q)` | `weights` of the state kept under `name`. | | `collapse(name, q, bit, norm)` | Nothing. Keeps `collapsed` of the state kept under `name`. | These answer over the facts you have loaded, each a sorted list: | Query | Answers | |---|---| | `after(g)` | The gates gate `g` `MustPrecede`. | | `commuting(g)` | The gates gate `g` `CommutesWith`: later gates sharing a qubit with `g` that may run before it. | | `uncoupled_gates()` | The gates concluded `uncoupled`. | | `illegal_gates(c)` | Each gate of circuit `c` its device cannot run as written, as `" "`, once for each of `off_device`, `not_native`, `not_here` and `reversed` that holds. | | `stale_gates(c, at, max_age)` | Each gate of circuit `c` that `RunsAs` a native operation whose `measured_at` is later than `at`, earlier than `at` less `max_age`, or absent. `at` is a `datetime` and `max_age` a `duration`. A gate its device cannot run is in `illegal_gates` and not here. | | `results_not_holding()` | Each result a reason holds for, as `" "`, once for each of `unrecorded`, `circuit_unknown`, `circuit_changed`, `source_unknown`, `source_changed`, `device_unknown` and `recalibrated` that holds. | | `results_of(c)` | The results naming `c` as their `circuit` or their `source`. | | `produced(r)` | What result `r` records, as `" "`, one line for each field it records, in the order of §3.16. Not sorted. | ### 3.19 `pqc` — declared fields `dke.pqc.cbom` (§4.5) writes an algorithm's `quantum` and `strength` and a use's `system` and `algorithm` from a cryptographic bill of materials. You write the rest. Every year is a calendar year, written as an `int`, and every boundary is the first year WITHOUT something. **`Horizon`** | Field | Class | Notes | |---|---|---| | `year` | `int` | The first year a quantum computer able to break the vulnerable algorithms is assumed to exist. Two horizons are two assumptions held at once, and every use is reasoned about under both. | **`Algorithm`** | Field | Class | Notes | |---|---|---| | `quantum` | `string` | `"vulnerable"` for an algorithm a quantum computer breaks. Any other value is not vulnerable. | | `strength` | `int` | Its classical security strength, in bits, which is what a deadline is stated against. | **`Data`** | Field | Class | Notes | |---|---|---| | `shelf_life` | `int` | How many years after it is protected the data must stay protected. | **`System`** | Field | Class | Notes | |---|---|---| | `migration` | `int` | How many years moving the system off a vulnerable algorithm takes. | **`Deadline`** | Field | Class | Notes | |---|---|---| | `year` | `int` | The first year an algorithm the deadline covers may not be used. | | `strength` | `int` | The deadline covers a vulnerable algorithm of at most this many bits. | **`Use`** | Field | Class | Notes | |---|---|---| | `system` | `string` | The `System` that uses the algorithm. | | `algorithm` | `string` | The `Algorithm` it uses. | | `protects` | `string` | The `Data` it protects. | | `migrated` | `int` | The first year the use no longer relies on its algorithm, planned or done. Absent when there is no plan. | | `horizon` | `int` | Concluded by a rule (§3.21). Never written. | | `shelf_life` | `int` | Concluded by a rule (§3.21). Never written. | | `migration` | `int` | Concluded by a rule (§3.21). Never written. | ### 3.20 `pqc` — derived fields | Field | Definition | |---|---| | `Use.migrate_by` | `horizon - shelf_life` | | `Use.start_by` | `migrate_by - migration` | `migrate_by` is the first year the use must no longer rely on its algorithm, and `start_by` the last year to start moving it. ### 3.21 `pqc` — standing rules Each holds continuously, as in §3.17. | Rule | Over | Concludes | While | |---|---|---|---| | `vulnerable` | `Use`, `Algorithm` | `vulnerable` | the use's `algorithm` names an algorithm whose `quantum` is `"vulnerable"` | | `use_horizon` | `Use`, `Horizon` | `horizon` | the use is `vulnerable`; the use takes every horizon's `year` | | `use_shelf_life` | `Use`, `Data` | `shelf_life` | the use is `vulnerable` and its `protects` names the data; the use takes the data's `shelf_life` | | `use_migration` | `Use`, `System` | `migration` | the use is `vulnerable` and its `system` names the system; the use takes the system's `migration` | | `late` | `Use` | `late` | the use's `migrated` is later than its `migrate_by` | | `unplanned` | `Use` | `unplanned` | the use is `vulnerable` and has no `migrated` | | `deadline` | `Use`, `Algorithm`, `Deadline` | `deadline` | the use's algorithm is `"vulnerable"` and its `strength` is at most a deadline's `strength`; concludes the earliest such deadline's `year`, under any value of it | | `deadline_name` | `Use`, `Algorithm`, `Deadline` | `deadline_name` | as `deadline`; concludes the name of the deadline with that year, the first in name order when two share it | | `misses` | `Use` | `misses` | the use's `migrated` is later than its `deadline` | Two standing constraints are reported by `checkup` and refuse no write. `no_late_plan` is violated by each `Use` that is `late`, and `no_missed_deadline` by each `Use` that `misses`. Two notes that are contract rather than commentary: - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about: a use is late or misses a deadline if any value on record makes it so, and its `deadline` is the earliest year of any value of any deadline that covers it, one source's year. `unsettled()` names each such use, by its own fields and the horizon, shelf life and migration time it is reasoned about with; a deadline's `year` is not among them, and `why` on the use's `deadline` names the year that placed it. - **No rule reads the present.** A question that depends on the year takes it as `at`. ### 3.22 `pqc` — queries Called by name after `import pqc`. Every one answers use names, sorted, except `priority`, which answers them in order. | Query | Answers | |---|---| | `priority()` | Every vulnerable use with a `start_by`, the earliest first, and uses with the same year in name order. A use with two values is placed by the earlier. | | `exposed()` | Every use that is `late`, and every `unplanned` use with a `migrate_by`: what it protects from that year on can be recorded now and read at the horizon. | | `noncompliant()` | Every use that `misses`, and every `unplanned` use with a `deadline`. | | `remaining(at)` | Every `vulnerable` use still relying on its algorithm in year `at`: it has no `migrated`, or its latest `migrated` is later than `at`. | | `unclassified()` | Every use with no `algorithm`, or naming an algorithm with no `quantum`. No rule concludes anything about such a use. | | `unassessed()` | Every `vulnerable` use with no `start_by`: its data's shelf life, its system's migration time or a horizon is not recorded. | | `unsettled()` | Every use whose `algorithm`, `migrated`, `horizon`, `shelf_life` or `migration` holds more than one value. | ### 3.23 `harmony` — declared fields The five writing scripts of §3.26 write `Voice`, `Key`, `Degree`, `Note`, `Bar` and `Tone` under the source `"harmony"`, and you may write the same fields yourself. A **pitch** is a MIDI note number: 60 is middle C and each step is a semitone. A **pitch class** is a pitch taken within the octave, 0 for C up to 11 for B. A **beat** is one chord, numbered from 1 in order. Rhythm is counted in a unit you choose, such as a sixteenth, from 0 at the start of the piece. **`Voice`** | Field | Class | Notes | |---|---|---| | `place` | `int` | The voice's order from the bottom, 1 for the bass. Two voices MUST NOT share a place: the rules compare voices by place. | | `low` | `int` | The lowest pitch of its range. | | `high` | `int` | The highest pitch of its range. | **`Key`** | Field | Class | Notes | |---|---|---| | `tonic` | `int` | The tonic's pitch class. | | `mode` | `string` | `"major"` or `"minor"`. No rule reads it; `key()` reads it to choose the degrees it writes. | **`Degree`** | Field | Class | Notes | |---|---|---| | `key` | `string` | The `Key` the degree belongs to. | | `pc` | `int` | A pitch class that belongs to that key. | **`Note`** | Field | Class | Notes | |---|---|---| | `voice` | `string` | The `Voice` that sings it. | | `beat` | `int` | The chord it belongs to. | | `pitch` | `int` | Its pitch. | | `key` | `string` | The `Key` it is checked against. Absent for a note checked against none. | | `place` | `int` | Concluded by a rule (§3.25). Never written. | | `p1` | `int` | Concluded by a rule (§3.25). Never written. | | `p2` | `int` | Concluded by a rule (§3.25). Never written. | | `p3` | `int` | Concluded by a rule (§3.25). Never written. | | `spacing` | `bool` | Concluded by a rule (§3.25). Never written. | | `range` | `string` | Concluded by a rule (§3.25). Never written. | | `chromatic` | `bool` | Concluded by a rule (§3.25). Never written. | | `chord` | `string` | Concluded by a rule (§3.25), on a chord's bass note. Never written. | | `seventh` | `string` | Concluded by a rule (§3.25), on a chord's bass note. Never written. | **`Fifths`**, **`Octaves`** and **`Crossing`** declare no field. Each is a relation between two notes, `Fifths.a.m` for notes `a` and `m`, concluded by the rules of §3.25 and never written. They are declared so that reading one that does not stand answers empty. **`Bar`** | Field | Class | Notes | |---|---|---| | `start` | `int` | Where the bar starts. | | `length` | `int` | How long it lasts. Bars of different lengths are a change of metre. | | `pulse` | `int` | The length of its beat. | | `tones` | `int` | Concluded by a rule (§3.25): how many tones starting in it have a `duration`. Never written. | | `claims` | `int` | Concluded by a rule (§3.25): how many claims of `duration` they hold. Never written. | | `disputed` | `bool` | Concluded by a rule (§3.25): `claims` is greater than `tones`. Never written. | | `filled` | `int` | Concluded by a rule (§3.25). Never written. | | `miscounted` | `bool` | Concluded by a rule (§3.25). Never written. | **`Tone`** | Field | Class | Notes | |---|---|---| | `onset` | `int` | Where the tone starts. A rest is a tone too. | | `duration` | `int` | How long it lasts. | | `barstart` | `int` | Concluded by a rule (§3.25). Never written. | | `barend` | `int` | Concluded by a rule (§3.25). Never written. | | `pulse` | `int` | Concluded by a rule (§3.25). Never written. | | `across` | `bool` | Concluded by a rule (§3.25). Never written. | | `syncopated` | `bool` | Concluded by a rule (§3.25). Never written. | ### 3.24 `harmony` — derived fields | Field | Definition | |---|---| | `Note.pc` | `pitch % 12` | | `Note.nextbeat` | `beat + 1` | | `Note.d2` | `pitch - p2` | | `Note.d3` | `pitch - p3` | | `Note.i1` | `(pitch - p1) % 12` | | `Note.i2` | `(pitch - p2) % 12` | | `Note.i3` | `(pitch - p3) % 12` | | `Bar.end` | `start + length` | | `Tone.ends` | `onset + duration` | | `Tone.offbeat` | `(onset - barstart) % pulse` | | `Tone.nextpulse` | `onset - (onset - barstart) % pulse + pulse` | `%` takes the sign of its right side, as in Python, so `i1` to `i3` are always 0 to 11. That is an interval within the octave, a compound interval counting as its simple form: 7 is a fifth or a twelfth, and 0 a unison or an octave. A note that has crossed below the voice it is compared with reads the interval the other way up. ### 3.25 `harmony` — standing rules Each holds continuously, as in §3.17. A rule over two or three `Note`s binds them as `a`, `c` and `m`, or as `b` for a chord's bass note, in the order the cell names them. | Rule | Over | Concludes | While | |---|---|---|---| | `place_of` | `Note`, `Voice` | `place` | the note's `voice` names the voice; the note takes its `place` | | `sounding_1` | `Note` | `p1` | a note on the same `beat` is at place 1; the note takes its `pitch` | | `sounding_2` | `Note` | `p2` | as `sounding_1`, for place 2 | | `sounding_3` | `Note` | `p3` | as `sounding_1`, for place 3 | | `fifths_over_1` | `Note` | `Fifths` | `a.place > 1`; `m` is at place 1 on `a`'s beat; `a` and `c`, the note of `a`'s voice on the next beat, both have an `i1` of 7; `a` and `c` differ in `pitch`, and so do the notes at place 1 on the two beats. Concludes `Fifths.a.m` | | `fifths_over_2` | `Note` | `Fifths` | as `fifths_over_1` with `a.place > 2`, place 2 and `i2` | | `fifths_over_3` | `Note` | `Fifths` | as `fifths_over_1` with `a.place > 3`, place 3 and `i3` | | `octaves_over_1` | `Note` | `Octaves` | as `fifths_over_1` with `a.place > 1` and an `i1` of 0. Concludes `Octaves.a.m` | | `octaves_over_2` | `Note` | `Octaves` | as `octaves_over_1` with `a.place > 2`, place 2 and `i2` | | `octaves_over_3` | `Note` | `Octaves` | as `octaves_over_1` with `a.place > 3`, place 3 and `i3` | | `crossing` | `Note` | `Crossing` | `a` and `m` share a `beat`, `a`'s `place` is above `m`'s, and `a`'s `pitch` is below `m`'s. Concludes `Crossing.a.m` | | `spacing_3` | `Note` | `spacing` | the note is at place 3 and `d2 > 12` | | `spacing_4` | `Note` | `spacing` | the note is at place 4 and `d3 > 12` | | `below_range` | `Note`, `Voice` | `range` | the note's `voice` names the voice and its `pitch` is below the voice's `low`; concludes `"low"` | | `above_range` | `Note`, `Voice` | `range` | the note's `voice` names the voice and its `pitch` is above the voice's `high`; concludes `"high"` | | `chromatic` | `Note`, `Key` | `chromatic` | the note's `key` names a key, and no `Degree` of that key has the note's `pc` | | `major_root` | `Note` | `chord` | `b` is at place 1, and notes on its beat have an `i1` of 4 and of 7; concludes `"major"` | | `minor_root` | `Note` | `chord` | as `major_root`, with 3 and 7; concludes `"minor"` | | `diminished_root` | `Note` | `chord` | as `major_root`, with 3 and 6; concludes `"diminished"` | | `major_first` | `Note` | `chord` | as `major_root`, with 3 and 8; concludes `"major, first inversion"` | | `minor_first` | `Note` | `chord` | as `major_root`, with 4 and 9; concludes `"minor, first inversion"` | | `diminished_first` | `Note` | `chord` | as `major_root`, with 3 and 9; concludes `"diminished, first inversion"` | | `major_second` | `Note` | `chord` | as `major_root`, with 5 and 9; concludes `"major, second inversion"` | | `minor_second` | `Note` | `chord` | as `major_root`, with 5 and 8; concludes `"minor, second inversion"` | | `diminished_second` | `Note` | `chord` | as `major_root`, with 6 and 9; concludes `"diminished, second inversion"` | | `major_open` | `Note` | `chord` | `b` is at place 1, a note on its beat has an `i1` of 4, and every note on its beat has an `i1` of 0 or 4; concludes `"major, fifth omitted"` | | `minor_open` | `Note` | `chord` | as `major_open`, with 3; concludes `"minor, fifth omitted"` | | `seventh_root` | `Note` | `seventh` | `b` is at place 1, and notes on its beat have an `i1` of 4, of 7 and of 10; concludes `"dominant seventh"` | | `seventh_open` | `Note` | `seventh` | as `seventh_root`, with 4 and 10 and no note on the beat with an `i1` of 7; concludes `"dominant seventh, fifth omitted"` | | `seventh_first` | `Note` | `seventh` | as `seventh_root`, with 3, 6 and 8; concludes `"dominant seventh, first inversion"` | | `seventh_second` | `Note` | `seventh` | as `seventh_root`, with 3, 5 and 9; concludes `"dominant seventh, second inversion"` | | `seventh_third` | `Note` | `seventh` | as `seventh_root`, with 2, 6 and 9; concludes `"dominant seventh, third inversion"` | | `bar_start` | `Tone`, `Bar` | `barstart` | the tone's `onset` is at or after the bar's `start` and before its `end`; the tone takes the bar's `start` | | `bar_end` | `Tone`, `Bar` | `barend` | as `bar_start`; the tone takes the bar's `end` | | `bar_pulse` | `Tone`, `Bar` | `pulse` | as `bar_start`; the tone takes the bar's `pulse` | | `bar_claims` | `Bar`, `Tone` | `claims` | as `bar_start`, and the tone's `duration > -1000000000000000000`; the bar takes the number of claims of `duration` such tones hold | | `bar_tones` | `Bar`, `Tone` | `tones` | as `bar_start`, and the tone's `duration > -1000000000000000000`; the bar takes the number of distinct such tones | | `bar_disputed` | `Bar` | `disputed` | the bar's `claims` is greater than its `tones`; concludes `True` | | `bar_filled` | `Bar`, `Tone` | `filled` | as `bar_start`, and the bar has no `disputed`; the bar takes the sum of every such tone's `duration` | | `bar_miscounted` | `Bar` | `miscounted` | the bar's `filled` differs from its `length` | | `across_bar` | `Tone` | `across` | the tone's `ends` is after its `barend` | | `syncopated` | `Tone` | `syncopated` | `offbeat > 0`, and the tone's `ends` is after its `nextpulse` | `harmony` declares no standing constraint. Four notes that are contract rather than commentary: - **Consecutive means both voices move.** A fifth or an octave held by one voice while the other leaps is not marked. Fifths and octaves in contrary motion are marked, and so is a twelfth followed by a fifth. - **A chord takes every reading inside it.** Each chord rule reads exactly the intervals it names, so a dominant seventh is also a major triad, a chord with both a major and a minor third above its bass is read as both, and a chord of no shape named here has no reading. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a mark stands if any value on record makes it so. A fold reads every value too, so a tone whose `duration` a second source writes, even the same duration, would be added twice to its bar's `filled`; `tones` and `claims` count the tones and their claims over the one binding the fold reads, and while the claims are more, the bar is `disputed` and no `filled` is concluded for it. A tone with no `duration` is in neither count, and a tone whose `onset` holds two values starts in each bar it names, each of those fills being one source's. The rules that ask for something to be missing are answered for the note rather than for each value: `chromatic` holds of a note only when no value of its `pc` is a degree of its key, and `major_open`, `minor_open` and `seventh_open` read a chord only when no value on record supplies the interval they leave out. - **No rule hears the music.** Every rule compares numbers. What the rules do not check is listed in the Library Reference: hidden fifths and octaves, doubling, resolution, melodic intervals and more than four voices. ### 3.26 `harmony` — queries Called by name after `import harmony`. Only `filled_of` refuses because sources disagree, and only a disputed bar: otherwise a reader answers one value by the rule its row states, and `unsettled()` names what is in disagreement. | Query | Answers | |---|---| | `satb()` | Nothing. Writes the voices `bass`, `tenor`, `alto` and `soprano` at places 1 to 4, with the ranges 40 to 60, 48 to 67, 55 to 74 and 60 to 79. | | `key(name, tonic, mode)` | Nothing. Writes the key `name`, and for each pitch class of its scale a `Degree` named `name`, `_` and the pitch class: the major scale, or for `"minor"` the natural minor with its raised sixth and seventh. | | `chord(beat, k, bass, tenor, alto, soprano)` | Nothing. Writes four notes on `beat` in key `k`, named for their voice and beat, `bass1` to `soprano1` for beat 1. Writing a beat again replaces its notes. | | `bars(count, length, pulse)` | Nothing. Writes `count` bars `m1` onward, end to end from 0, then forgets the bars named `m` and each number from `count + 1` up to the number of bars the store held before the call. | | `melody(durations)` | Nothing. Writes a tone `t1` onward for each duration, end to end from 0, then forgets the tones named `t` and each number past the new end up to the number of tones the store held before the call. | | `voice_of(n)` | The `voice` of note `n`, `""` when it has none, and every voice in force in name order, joined by `" or "`, when sources disagree. | | `beat_of(n)` | The `beat` of note `n`, 0 when it has none, and the least in force when sources disagree. | | `filled_of(b)` | The `filled` of bar `b`, 0 when it has none, and the least in force when sources disagree. A bar with `disputed` is refused. | | `length_of(b)` | The `length` of bar `b`, 0 when it has none, and the least in force when sources disagree. | | `pairs(kind)` | For `"fifths"`, `"octaves"` or `"crossing"`, each pair of notes the relation holds between, as (`a`, `m`). | | `faults()` | One line for each consecutive fifth or octave, crossed voice, spacing, range and chromatic mark, sorted. A note is named by its voice and beat, each value in force joined by `" or "`. | | `readings(n)` | Every `chord` and `seventh` value concluded on note `n`, sorted. | | `rhythm_faults()` | One line for each miscounted bar, each disputed bar (`bar b: disputed`), each tone `across` its bar line and each syncopated tone, sorted. A bar's `filled` and `length` are each given with every value in force, joined by `" or "`. | | `unsettled()` | Every voice, note, bar and tone for which a field of §3.23 that is not concluded holds more than one value in force, as its kind in lower case and its name, `note tenor1`, sorted. | | `frequency(midi, a4)` | `a4 * 2.0 ** ((midi - 69) / 12)`, with `a4` 440.0 when not given. | | `cents(ratio)` | `1200.0 * math.log(ratio, 2.0)`. | | `beating(f1, h1, f2, h2)` | `abs(h1 * f1 - h2 * f2)`. | | `pcset(pcs)` | The distinct values of `pcs` modulo 12, sorted. | | `rotations(s)` | Each rotation of the sorted set `s`, transposed to begin on 0. | | `packed_key(r, right)` | What two rotations are compared by: `r`'s last element, then its elements from the next to last back to the second when `right` is true, or from the second up to the next to last when it is false. | | `most_packed(s, right)` | The rotation of `s` with the least `packed_key`, the earlier in order of rotation when two tie. | | `prime_form(pcs, right)` | The most packed rotation of `pcset(pcs)`, or of its inversion when that one's `packed_key` is less; `[]` for no pitch classes. `right` is true when not given. | | `interval_vector(pcs)` | Six counts: how many pairs of the set lie each interval class from 1 to 6 apart. | | `matrix(row)` | One list for each element of `row`: element `j` of list `i` is `(row[j] + row[0] - row[i]) % 12`. | | `all_interval(row)` | Whether the successive intervals of `row`, each modulo 12, are all different. | | `euclid(k, n)` | `n` characters, `x` for each of `k` onsets and `.` elsewhere, spread by Bjorklund's algorithm: all `.` when `k` is 0 or less, all `x` when `k` is `n` or more. | --- ### 3.27 `physics` — declared fields The writing scripts of §3.30 write `Quantity`, `Factor`, `Resistor` and `Group` under the source `"physics"`, and `Unit` under the source each is given, and you may write the same fields yourself. A **unit** is named by letters, digits and underscores, such as `"N"`, `"lbf_s"` or `"m_per_s2"`. Its **dimension** is the powers of five base dimensions it is made of: mass, length, time, electric current and temperature. A newton, a kilogram metre per second squared, is mass 1, length 1 and time -2. A unit's `factor` is what one of it is in the SI unit of the same dimension. A unit whose zero is not SI's, such as a degree Celsius, is not a factor and is not written. An **equation** is checked as a product of powers: write every power on its left side positive and every power on its right side negative, so `F = m a` is `F` to the 1, `m` to the -1 and `a` to the -1. **`Unit`** | Field | Class | Notes | |---|---|---| | `mass` | `int` | The unit's power of mass. | | `length` | `int` | The unit's power of length. | | `time` | `int` | The unit's power of time. | | `current` | `int` | The unit's power of electric current. | | `temperature` | `int` | The unit's power of temperature. | | `factor` | `real` | What one of the unit is in the SI unit of the same dimension: 4.4482216152605 for a pound-force, in newtons. | **`Quantity`** | Field | Class | Notes | |---|---|---| | `value` | `real` | The value, in `unit`. | | `unit` | `string` | The `Unit` it is written in. | | `expects` | `string` | The `Unit` its reader takes it in, where it is handed from one system to another. Absent for a quantity handed to no one. | | `factor` | `real` | Concluded by a rule (§3.29). Never written. | | `mass` | `int` | Concluded by a rule (§3.29). Never written. | | `length` | `int` | Concluded by a rule (§3.29). Never written. | | `time` | `int` | Concluded by a rule (§3.29). Never written. | | `current` | `int` | Concluded by a rule (§3.29). Never written. | | `temperature` | `int` | Concluded by a rule (§3.29). Never written. | | `efactor` | `real` | Concluded by a rule (§3.29), from `expects`. Never written. | | `emass` | `int` | Concluded by a rule (§3.29), from `expects`. Never written. | | `elength` | `int` | Concluded by a rule (§3.29), from `expects`. Never written. | | `etime` | `int` | Concluded by a rule (§3.29), from `expects`. Never written. | | `ecurrent` | `int` | Concluded by a rule (§3.29), from `expects`. Never written. | | `etemperature` | `int` | Concluded by a rule (§3.29), from `expects`. Never written. | | `unknown` | `bool` | Concluded by a rule (§3.29). Never written. | | `unexpected` | `bool` | Concluded by a rule (§3.29). Never written. | | `handoff` | `string` | Concluded by a rule (§3.29). Never written. | **`Factor`** | Field | Class | Notes | |---|---|---| | `equation` | `string` | The `Equation` the factor belongs to. | | `quantity` | `string` | The `Quantity` it is a power of. | | `power` | `int` | The power: positive on the left side of the equation, negative on the right. | | `mass` | `int` | Concluded by a rule (§3.29). Never written. | | `length` | `int` | Concluded by a rule (§3.29). Never written. | | `time` | `int` | Concluded by a rule (§3.29). Never written. | | `current` | `int` | Concluded by a rule (§3.29). Never written. | | `temperature` | `int` | Concluded by a rule (§3.29). Never written. | | `unknown` | `bool` | Concluded by a rule (§3.29). Never written. | **`Equation`** | Field | Class | Notes | |---|---|---| | `mass_factors` | `int` | Concluded by a rule (§3.29): how many of its factors hold a share of mass. Never written. | | `length_factors` | `int` | Concluded by a rule (§3.29): how many of its factors hold a share of length. Never written. | | `time_factors` | `int` | Concluded by a rule (§3.29): how many of its factors hold a share of time. Never written. | | `current_factors` | `int` | Concluded by a rule (§3.29): how many of its factors hold a share of current. Never written. | | `temperature_factors` | `int` | Concluded by a rule (§3.29): how many of its factors hold a share of temperature. Never written. | | `mass_claims` | `int` | Concluded by a rule (§3.29): how many claims of those shares they hold. Never written. | | `length_claims` | `int` | Concluded by a rule (§3.29): how many claims of those shares they hold. Never written. | | `time_claims` | `int` | Concluded by a rule (§3.29): how many claims of those shares they hold. Never written. | | `current_claims` | `int` | Concluded by a rule (§3.29): how many claims of those shares they hold. Never written. | | `temperature_claims` | `int` | Concluded by a rule (§3.29): how many claims of those shares they hold. Never written. | | `mass_disputed` | `bool` | Concluded by a rule (§3.29): `mass_claims` is greater than `mass_factors`. Never written. | | `length_disputed` | `bool` | Concluded by a rule (§3.29): `length_claims` is greater than `length_factors`. Never written. | | `time_disputed` | `bool` | Concluded by a rule (§3.29): `time_claims` is greater than `time_factors`. Never written. | | `current_disputed` | `bool` | Concluded by a rule (§3.29): `current_claims` is greater than `current_factors`. Never written. | | `temperature_disputed` | `bool` | Concluded by a rule (§3.29): `temperature_claims` is greater than `temperature_factors`. Never written. | | `mass` | `int` | Concluded by a rule (§3.29). Never written. | | `length` | `int` | Concluded by a rule (§3.29). Never written. | | `time` | `int` | Concluded by a rule (§3.29). Never written. | | `current` | `int` | Concluded by a rule (§3.29). Never written. | | `temperature` | `int` | Concluded by a rule (§3.29). Never written. | | `consistent` | `bool` | Concluded by a rule (§3.29). Never written. | | `unbalanced` | `bool` | Concluded by a rule (§3.29). Never written. | **`Resistor`** | Field | Class | Notes | |---|---|---| | `ohms` | `real` | Its resistance in ohms. | | `group` | `string` | The `Group` it is joined in. Absent for a resistor in none. | **`Group`** | Field | Class | Notes | |---|---|---| | `joined` | `string` | `"series"` or `"parallel"`. | | `ohms_resistors` | `int` | Concluded by a rule (§3.29), for a series group: how many resistors carry an `ohms` into its sum. Never written. | | `ohms_claims` | `int` | Concluded by a rule (§3.29): how many claims of `ohms` they hold. Never written. | | `ohms_disputed` | `bool` | Concluded by a rule (§3.29): `ohms_claims` is greater than `ohms_resistors`. Never written. | | `siemens_resistors` | `int` | Concluded by a rule (§3.29), for a parallel group: how many resistors carry a `siemens` into its sum. Never written. | | `siemens_claims` | `int` | Concluded by a rule (§3.29): how many claims of `siemens` they hold. Never written. | | `siemens_disputed` | `bool` | Concluded by a rule (§3.29): `siemens_claims` is greater than `siemens_resistors`. Never written. | | `ohms` | `real` | Concluded by a rule (§3.29), for a series group. Never written. | | `siemens` | `real` | Concluded by a rule (§3.29), for a parallel group. Never written. | ### 3.28 `physics` — derived fields | Field | Definition | |---|---| | `Quantity.si` | `value * factor` | | `Quantity.converted` | `value * (factor / efactor)` | | `Factor.smass` | `power * mass` | | `Factor.slength` | `power * length` | | `Factor.stime` | `power * time` | | `Factor.scurrent` | `power * current` | | `Factor.stemperature` | `power * temperature` | | `Resistor.siemens` | `1.0 / ohms` | | `Group.parallel` | `1.0 / siemens` | `Quantity.si` is the quantity's value in the SI unit of its dimension, and `converted` its value in the unit it expects. `converted` takes the ratio of the two factors first, so a value expected in its own unit comes back as it was, and it is a real wherever the value in the expected unit is one, for any factors from 10^-150 to 10^150. Each is absent until the rules have concluded the fields it reads, so a quantity in a unit the list does not hold has neither. A factor's `s` fields are its share of each base dimension, and an equation sums them. A resistor's `siemens` is its conductance, and a group's `parallel` is the resistance of a parallel group, the reciprocal of the conductances its resistors sum to. ### 3.29 `physics` — standing rules Each holds continuously, as in §3.17. A rule over a `Quantity` and a `Unit` binds them as `q` and `u`, a rule over a `Factor` as `f`, an `Equation` as `e`, a `Group` as `g` and a `Resistor` as `r`. | Rule | Over | Concludes | While | |---|---|---|---| | `factor_of` | `Quantity`, `Unit` | `factor` | the quantity's `unit` names the unit; the quantity takes the unit's `factor` | | `mass_of` | `Quantity`, `Unit` | `mass` | as `factor_of`; the quantity takes the unit's `mass` | | `length_of` | `Quantity`, `Unit` | `length` | as `factor_of`; the quantity takes the unit's `length` | | `time_of` | `Quantity`, `Unit` | `time` | as `factor_of`; the quantity takes the unit's `time` | | `current_of` | `Quantity`, `Unit` | `current` | as `factor_of`; the quantity takes the unit's `current` | | `temperature_of` | `Quantity`, `Unit` | `temperature` | as `factor_of`; the quantity takes the unit's `temperature` | | `unknown_unit` | `Quantity` | `unknown` | the quantity's `unit` is not empty and no `factor` is concluded for it; concludes `True` | | `efactor_of` | `Quantity`, `Unit` | `efactor` | the quantity's `expects` names the unit; the quantity takes the unit's `factor` | | `emass_of` | `Quantity`, `Unit` | `emass` | as `efactor_of`; the quantity takes the unit's `mass` | | `elength_of` | `Quantity`, `Unit` | `elength` | as `efactor_of`; the quantity takes the unit's `length` | | `etime_of` | `Quantity`, `Unit` | `etime` | as `efactor_of`; the quantity takes the unit's `time` | | `ecurrent_of` | `Quantity`, `Unit` | `ecurrent` | as `efactor_of`; the quantity takes the unit's `current` | | `etemperature_of` | `Quantity`, `Unit` | `etemperature` | as `efactor_of`; the quantity takes the unit's `temperature` | | `unexpected_unit` | `Quantity` | `unexpected` | the quantity's `expects` is not empty and no `efactor` is concluded for it; concludes `True` | | `handoff_convert` | `Quantity` | `handoff` | `unit` differs from `expects`, and the quantity's five powers equal the five of the expected unit; concludes `"convert"` | | `handoff_mass` | `Quantity` | `handoff` | `mass` differs from `emass`; concludes `"incompatible"` | | `handoff_length` | `Quantity` | `handoff` | `length` differs from `elength`; concludes `"incompatible"` | | `handoff_time` | `Quantity` | `handoff` | `time` differs from `etime`; concludes `"incompatible"` | | `handoff_current` | `Quantity` | `handoff` | `current` differs from `ecurrent`; concludes `"incompatible"` | | `handoff_temperature` | `Quantity` | `handoff` | `temperature` differs from `etemperature`; concludes `"incompatible"` | | `factor_mass` | `Factor`, `Quantity`, `Unit` | `mass` | the factor's `quantity` names the quantity and the quantity's `unit` names the unit; the factor takes the unit's `mass` | | `factor_length` | `Factor`, `Quantity`, `Unit` | `length` | as `factor_mass`; the factor takes the unit's `length` | | `factor_time` | `Factor`, `Quantity`, `Unit` | `time` | as `factor_mass`; the factor takes the unit's `time` | | `factor_current` | `Factor`, `Quantity`, `Unit` | `current` | as `factor_mass`; the factor takes the unit's `current` | | `factor_temperature` | `Factor`, `Quantity`, `Unit` | `temperature` | as `factor_mass`; the factor takes the unit's `temperature` | | `factor_unknown` | `Factor` | `unknown` | the factor's `quantity` is not empty and no `mass` is concluded for it; concludes `True` | | `equation_mass_factors` | `Equation`, `Factor` | `mass_factors` | the factor's `equation` names the equation and its `smass > -1000000000`; the equation takes the number of distinct such factors | | `equation_length_factors` | `Equation`, `Factor` | `length_factors` | the factor's `equation` names the equation and its `slength > -1000000000`; the equation takes the number of distinct such factors | | `equation_time_factors` | `Equation`, `Factor` | `time_factors` | the factor's `equation` names the equation and its `stime > -1000000000`; the equation takes the number of distinct such factors | | `equation_current_factors` | `Equation`, `Factor` | `current_factors` | the factor's `equation` names the equation and its `scurrent > -1000000000`; the equation takes the number of distinct such factors | | `equation_temperature_factors` | `Equation`, `Factor` | `temperature_factors` | the factor's `equation` names the equation and its `stemperature > -1000000000`; the equation takes the number of distinct such factors | | `equation_mass_claims` | `Equation`, `Factor` | `mass_claims` | the factor's `equation` names the equation and its `smass > -1000000000`; the equation takes the number of claims of `smass` those factors hold | | `equation_length_claims` | `Equation`, `Factor` | `length_claims` | the factor's `equation` names the equation and its `slength > -1000000000`; the equation takes the number of claims of `slength` those factors hold | | `equation_time_claims` | `Equation`, `Factor` | `time_claims` | the factor's `equation` names the equation and its `stime > -1000000000`; the equation takes the number of claims of `stime` those factors hold | | `equation_current_claims` | `Equation`, `Factor` | `current_claims` | the factor's `equation` names the equation and its `scurrent > -1000000000`; the equation takes the number of claims of `scurrent` those factors hold | | `equation_temperature_claims` | `Equation`, `Factor` | `temperature_claims` | the factor's `equation` names the equation and its `stemperature > -1000000000`; the equation takes the number of claims of `stemperature` those factors hold | | `equation_mass_disputed` | `Equation` | `mass_disputed` | the equation's `mass_claims` is greater than its `mass_factors`; concludes `True` | | `equation_length_disputed` | `Equation` | `length_disputed` | the equation's `length_claims` is greater than its `length_factors`; concludes `True` | | `equation_time_disputed` | `Equation` | `time_disputed` | the equation's `time_claims` is greater than its `time_factors`; concludes `True` | | `equation_current_disputed` | `Equation` | `current_disputed` | the equation's `current_claims` is greater than its `current_factors`; concludes `True` | | `equation_temperature_disputed` | `Equation` | `temperature_disputed` | the equation's `temperature_claims` is greater than its `temperature_factors`; concludes `True` | | `equation_mass` | `Equation`, `Factor` | `mass` | the factor's `equation` names the equation and the equation has no `mass_disputed`; the equation takes the sum of its factors' `smass` | | `equation_length` | `Equation`, `Factor` | `length` | as `equation_mass`, with no `length_disputed`, summing `slength` | | `equation_time` | `Equation`, `Factor` | `time` | as `equation_mass`, with no `time_disputed`, summing `stime` | | `equation_current` | `Equation`, `Factor` | `current` | as `equation_mass`, with no `current_disputed`, summing `scurrent` | | `equation_temperature` | `Equation`, `Factor` | `temperature` | as `equation_mass`, with no `temperature_disputed`, summing `stemperature` | | `consistent` | `Equation` | `consistent` | the equation's `mass`, `length`, `time`, `current` and `temperature` are all 0, and no factor of it is `unknown`; concludes `True` | | `unbalanced_mass` | `Equation` | `unbalanced` | the equation's `mass` is not 0 and no factor of it is `unknown`; concludes `True` | | `unbalanced_length` | `Equation` | `unbalanced` | as `unbalanced_mass`, for `length` | | `unbalanced_time` | `Equation` | `unbalanced` | as `unbalanced_mass`, for `time` | | `unbalanced_current` | `Equation` | `unbalanced` | as `unbalanced_mass`, for `current` | | `unbalanced_temperature` | `Equation` | `unbalanced` | as `unbalanced_mass`, for `temperature` | | `group_ohms_resistors` | `Group`, `Resistor` | `ohms_resistors` | the group is joined `"series"`, the resistor's `group` names it and its `ohms > -1.0e300`; the group takes the number of distinct such resistors | | `group_siemens_resistors` | `Group`, `Resistor` | `siemens_resistors` | the group is joined `"parallel"`, the resistor's `group` names it and its `siemens > -1.0e300`; the group takes the number of distinct such resistors | | `group_ohms_claims` | `Group`, `Resistor` | `ohms_claims` | the group is joined `"series"`, the resistor's `group` names it and its `ohms > -1.0e300`; the group takes the number of claims of `ohms` those resistors hold | | `group_siemens_claims` | `Group`, `Resistor` | `siemens_claims` | the group is joined `"parallel"`, the resistor's `group` names it and its `siemens > -1.0e300`; the group takes the number of claims of `siemens` those resistors hold | | `group_ohms_disputed` | `Group` | `ohms_disputed` | the group's `ohms_claims` is greater than its `ohms_resistors`; concludes `True` | | `group_siemens_disputed` | `Group` | `siemens_disputed` | the group's `siemens_claims` is greater than its `siemens_resistors`; concludes `True` | | `series` | `Group`, `Resistor` | `ohms` | the group is joined `"series"`, the resistor's `group` names it and the group has no `ohms_disputed`; the group takes the sum of its resistors' `ohms` | | `parallel` | `Group`, `Resistor` | `siemens` | the group is joined `"parallel"`, the resistor's `group` names it and the group has no `siemens_disputed`; the group takes the sum of its resistors' `siemens` | `physics` declares no standing constraint. Five notes that are contract rather than commentary: - **Only a unit in the list is reasoned about.** A quantity in a unit no `Unit` names gets no `factor`, no dimension and no `si`; it is marked `unknown`, and `checks()` names it. An equation with a factor in such a unit is judged neither `consistent` nor `unbalanced`. - **Consistent is not true.** A consistent equation has the same dimensions on both sides. It is not thereby a law: `E = m v` and `E = m v²` differ in dimension, but `E = m v²` and `E = 2 m v²` do not. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and `unsettled()` names the fact. - **A sum is not drawn from a member bound to it twice.** A sum reads every value of what it sums, so a factor whose share two values give, or a resistor whose `ohms` a second source writes, even the same `ohms`, would be added twice, a result no circuit or equation has. The `_factors`, `_resistors` and `_claims` fields count the members and their claims over the one binding the sum reads, and while the claims are more, the sum is disputed and not concluded, nor anything that rests on it. A member with no value of the sum is in neither count, so it hides no dispute. A factor whose `equation`, or a resistor whose `group`, holds two values counts in each it names, and each of those sums is one source's. - **No rule reads the physics.** Every rule compares or adds numbers. Whether an equation is true, whether a quantity is plausible and whether a circuit is built of series and parallel groups are not asked. ### 3.30 `physics` — queries Called by name after `import physics`. Only `resistance` refuses because sources disagree, and only a disputed group: otherwise a reader answers one value by the rule its row states, and `unsettled()` names what is in disagreement. The writers and readers of the first two groups are the interface to the facts; the third group computes values from its arguments and writes nothing. | Query | Answers | |---|---| | `unit(name, mass, length, time, current, temperature, factor, source)` | Nothing. Writes the unit `name` with its five powers and its `factor`, each under `source`. | | `si_units()` | Nothing. Writes the list of units: `kg`, `m`, `s`, `A` and `K`, the dimensionless `one` and `rad`, `g`, `km`, `cm`, `mm`, `min`, `h`, `Hz`, `m_per_s`, `km_per_h`, `m_per_s2`, `N`, `N_s`, `kg_m_per_s`, `J`, `W`, `Pa`, `C`, `V`, `ohm`, `kWh` and `eV` under the source `"SI Brochure 2019"`, and `in`, `ft`, `mi`, `mph`, `lb`, `lbf`, `lbf_s`, `ft_lbf`, `psi`, `atm` and `cal` under the source `"NIST SP 811"`. | | `quantity(name, value, unit)` | Nothing. Writes the quantity `name` with its `value` and `unit`. Writing a name again corrects it. | | `expect(name, unit)` | Nothing. Writes the unit the quantity `name` is taken in. | | `factor(equation, quantity, power)` | Nothing. Writes the factor named for the equation, `-` and the quantity, with the `equation`, the `quantity` and the `power`. | | `resistor(name, ohms, group)` | Nothing. Writes the resistor `name` with its `ohms` and its `group`. | | `group(name, joined)` | Nothing. Writes the group `name`, `"series"` or `"parallel"`. | | `si(name)` | The `si` of quantity `name`, 0.0 when it has none, and the least in force when sources disagree. | | `converted(name)` | The `converted` of quantity `name`, 0.0 when it has none, and the least in force when sources disagree. | | `resistance(name)` | The resistance of group `name` in ohms: its `ohms` when joined in series, its `parallel` when joined in parallel. 0.0 when it has none, and the least in force when sources disagree. A group with `ohms_disputed` or `siemens_disputed` is refused. | | `disputed_equations()` | The equations with any of the five `_disputed` fields, sorted. | | `disputed_groups()` | The groups with `ohms_disputed` or `siemens_disputed`, sorted. | | `dimension(name)` | What is left over of equation `name`'s dimensions, as the powers of `M`, `L`, `T`, `I` and `Θ` that are not 0, such as `"L1 T-1"`; `"disputed"` when the equation is disputed, `"consistent"` when none is, `"unknown unit"` when a factor's unit is not recorded and `"no factors"` when the equation has none. | | `checks()` | One line for each quantity in a unit the list does not hold (`unknown unit: q in u`), each quantity expected in one it does not hold (`unknown unit: q expected in u`), each unbalanced equation that is not disputed (`unbalanced: e, D left over`), each hand-over (`handed over: q in u where x is expected, convert` or `incompatible`), each disputed equation (`disputed: equation e`) and each disputed group (`disputed: group g`), sorted. | | `unsettled()` | Each unit, quantity, factor, group and resistor that holds two different values in force for a field you write: a unit's `mass`, `length`, `time`, `current`, `temperature` or `factor`, a quantity's `value`, `unit` or `expects`, a factor's `equation`, `quantity` or `power`, a group's `joined`, or a resistor's `ohms` or `group`. Given as `unit x`, `quantity x`, `factor x`, `group x` or `resistor x`, sorted. | | `small_period(length, g)` | `2.0 * math.pi * math.sqrt(length / g)`, and where `length / g` passes the range of a real or falls below the smallest normal one, `2.0 * math.pi * (math.sqrt(length) / math.sqrt(g))`. A length below 0 or a `g` not above 0 is refused with `ValueError`. | | `agm(a, b)` | The arithmetic–geometric mean of `a` and `b`, iterated at most 40 times and stopped when the two means differ by at most `1e-15` of the first. A number below 0 is refused with `ValueError`. Where the sum of the pair passes the range of a real, the mean is the sum of their halves, and where their product passes it or falls below the smallest normal real, the geometric mean is the product of their square roots. | | `period(theta0, length, g)` | The exact period of a pendulum released at rest from `theta0` radians: `small_period(length, g)` divided by `agm(1.0, math.cos(theta0 / 2.0))`. An amplitude outside -π to π is refused with `ValueError`. | | `pendulum(theta0, length, g, dt)` | The same period by the fourth-order Runge–Kutta method at steps of `dt` seconds, four times the time to swing down to the vertical, integrated for up to `period(theta0, length, g)`. An amplitude not above 0 or above π, a length not above 0 or a step not above 0 is refused with `ValueError`, and so is a step too long to reach the vertical in that time. | | `orbit(e, method, periods, steps)` | For a body released at its closest point on a Kepler orbit of eccentricity `e`, `GM` 1 and semi-major axis 1, stepped by `"euler"`, `"verlet"` or any other name for the fourth-order Runge–Kutta method, `steps` a period for `periods` periods: the list of the relative error in energy, the relative error in angular momentum, and the distance from the start, a `math.hypot` where its squares fall below the smallest normal real. An eccentricity outside 0 to below 1 is refused with `ValueError`. | | `heat(cells, r, steps)` | The temperature at the middle of a rod of unit length and diffusivity, held at 0 at both ends and started as a triangle rising to 1, after `steps` steps of forward differences in time and centred differences in space over `cells` cells, `r` the time step over the square of the spacing. | | `heat_exact(time)` | The same temperature at `time` from the sum over odd `n`, 200 terms, of `8 / (n² π²)` times `e` to the `-n² π² time`. | | `solve(a, b)` | The solution of the linear system `a · x = b` by Gaussian elimination with partial pivoting, as a list; `[]` when the system is singular, that is where a pivot is 0. Where `x` passes the range of a real, or a pivot or a multiplier falls below the smallest normal real, while `a` and `b` are reals, it is solved again with each row of `a` scaled by a power of two that brings its largest entry near 1, and `b` by another, and `x` scaled back. | | `bridge(volts, r1, r2, r3, r4, rg)` | The current in amperes through the meter of a Wheatstone bridge, `r1` above `r2` and `r3` above `r4`, the meter `rg` across their middles. 0 when `r1 / r2 = r3 / r4`. A resistance not above 0 is refused with `ValueError`. Where a conductance or a current on the way passes the range of a real, each node's equation is taken with its resistances scaled by a power of two, and a source past 1 volt with its volts scaled by another, and the current scaled back. | | `ising(n, temperature, sweeps, seed)` | The mean of \|M\| per spin over the second half of `sweeps` sweeps of an `n` by `n` square magnet with wrapped edges, started with every spin up and flipped by the Metropolis rule at `temperature`, from a seeded generator, so a run is the same every time. | ### 3.31 `chemistry` — declared fields The writing scripts of §3.34 write `Element`, `Atom`, `Bond`, `Species` and `Term` under the source `"chemistry"`, except `element()` and `elements()`, which write `Element` under the source `"CIAAW"`; you may write the same fields yourself. A **weight** is a standard atomic weight, or a sum of them, in g/mol. A **valence** is the number of bonds an element usually forms in an organic molecule, and 0 for an element that forms none there. A **bond order** is 1, 2 or 3. An **enthalpy of formation** is in kJ/mol at 298.15 K, and a **reaction's enthalpy** in kJ. Hydrogens are never written: an atom carries the hydrogens its valence leaves over (§3.33). **`Element`** | Field | Class | Notes | |---|---|---| | `z` | `int` | The element's atomic number. The element of atomic number 1 is the hydrogen the rules count. | | `valence` | `int` | The number of bonds it forms, 0 where it forms none here. An element of valence 0 gives its atoms no `valence` and no hydrogens. | | `weight` | `real` | Its standard atomic weight. | An `Element` is named by its symbol. `elements()` writes these thirteen: | Symbol | `z` | `valence` | `weight` | |---|---|---|---| | `H` | 1 | 1 | 1.008 | | `C` | 6 | 4 | 12.011 | | `N` | 7 | 3 | 14.007 | | `O` | 8 | 2 | 15.999 | | `Na` | 11 | 0 | 22.990 | | `P` | 15 | 3 | 30.974 | | `S` | 16 | 2 | 32.06 | | `Cl` | 17 | 1 | 35.45 | | `K` | 19 | 0 | 39.098 | | `Ca` | 20 | 0 | 40.078 | | `Cr` | 24 | 0 | 51.996 | | `Mn` | 25 | 0 | 54.938 | | `Fe` | 26 | 0 | 55.845 | **`Atom`** | Field | Class | Notes | |---|---|---| | `element` | `string` | The symbol of its `Element`. | | `molecule` | `string` | The name of the molecule it belongs to. | | `valence` | `int` | Concluded by a rule (§3.33). Never written. | | `weight` | `real` | Concluded by a rule (§3.33). Never written. | | `bond_halves` | `int` | Concluded by a rule (§3.33): how many halves of its bonds carry an `order`. Never written. | | `bond_claims` | `int` | Concluded by a rule (§3.33): how many claims of `order` they hold. Never written. | | `bonds_disputed` | `bool` | Concluded by a rule (§3.33): `bond_claims` is greater than `bond_halves`. Never written. | | `bonds` | `int` | Concluded by a rule (§3.33). Never written. | | `hweight` | `real` | Concluded by a rule (§3.33). Never written. | | `overbonded` | `bool` | Concluded by a rule (§3.33). Never written. | | `carbonyl` | `bool` | Concluded by a rule (§3.33). Never written. | | `group` | `string` | Concluded by a rule (§3.33), on the atom that carries the group. Never written. | **`Bond`** A `Bond` is half a bond. `bond()` writes both halves, named `a-b` and `b-a`, so that each atom reaches the other. | Field | Class | Notes | |---|---|---| | `a` | `string` | The atom the half starts from. | | `b` | `string` | The atom it reaches. | | `order` | `int` | 1, 2 or 3. | | `belement` | `string` | Concluded by a rule (§3.33). Never written. | | `bhydrogens` | `int` | Concluded by a rule (§3.33). Never written. | | `bcarbonyl` | `bool` | Concluded by a rule (§3.33). Never written. | **`Molecule`** A `Molecule` is named by the `molecule` its atoms give, and declares no field you write. | Field | Class | Notes | |---|---|---| | `weight_atoms` | `int` | Concluded by a rule (§3.33): how many of its atoms have a `mass`. Never written. | | `weight_claims` | `int` | Concluded by a rule (§3.33): how many claims of `mass` they hold. Never written. | | `weight_disputed` | `bool` | Concluded by two rules (§3.33): `weight_claims` is greater than `weight_atoms`, or an atom of it has `bonds_disputed`. Never written. | | `hydrogen_atoms` | `int` | Concluded by a rule (§3.33): how many of its atoms have `hydrogens`. Never written. | | `hydrogen_claims` | `int` | Concluded by a rule (§3.33): how many claims of `hydrogens` they hold. Never written. | | `hydrogens_disputed` | `bool` | Concluded by two rules (§3.33): `hydrogen_claims` is greater than `hydrogen_atoms`, or an atom of it has `bonds_disputed`. Never written. | | `weight` | `real` | Concluded by a rule (§3.33). Never written. | | `hydrogens` | `int` | Concluded by a rule (§3.33). Never written. | | `heavy` | `int` | Concluded by a rule (§3.33). Never written. | **`Species`** | Field | Class | Notes | |---|---|---| | `formation` | `real` | The standard enthalpy of formation of the substance in its state, in kJ/mol. A species is named by you, such as `"water_l"` for liquid water. | **`Term`** A `Term` is named by `term()` for its reaction and species, `reaction`, `-` and `species`. | Field | Class | Notes | |---|---|---| | `reaction` | `string` | The `Reaction` it belongs to. | | `species` | `string` | The `Species` it counts. | | `coefficient` | `int` | Positive for a product, negative for a reactant. | | `formation` | `real` | Concluded by a rule (§3.33). Never written. | | `missing` | `bool` | Concluded by a rule (§3.33). Never written. | **`Reaction`** A `Reaction` is named by you, and declares no field you write. | Field | Class | Notes | |---|---|---| | `terms` | `int` | Concluded by a rule (§3.33): how many of its terms have a `contribution`. Never written. | | `claims` | `int` | Concluded by a rule (§3.33): how many claims of `contribution` they hold. Never written. | | `disputed` | `bool` | Concluded by a rule (§3.33): `claims` is greater than `terms`. Never written. | | `enthalpy` | `real` | Concluded by a rule (§3.33). Never written. | | `incomplete` | `bool` | Concluded by a rule (§3.33). Never written. | ### 3.32 `chemistry` — derived fields | Field | Definition | |---|---| | `Atom.hydrogens` | `valence - bonds` | | `Atom.mass` | `weight + hydrogens * hweight` | | `Term.contribution` | `coefficient * formation` | `hydrogens` is what the atom's valence leaves over after its bonds: an atom with no bond carries its whole valence, as the oxygen of water and the carbon of methane do. It is negative for an atom bonded past its valence, and `overbonded` marks that atom (§3.33). `mass` is the atom's weight with those hydrogens. An atom of an element that has not been written has no `valence`, no `hydrogens` and no `mass`. An atom of an element of valence 0, a metal, takes its own `bonds` as its `valence` (§3.33), so it carries no hydrogens and its `mass` is its weight. ### 3.33 `chemistry` — standing rules Each holds continuously, as in §3.17. A rule over an `Atom` and a `Bond` binds them as `a` or `c`, `o` or `n`, and `x` or `y`, in the order the cell names them. A functional group is concluded on the atom that carries it: the carbonyl carbon of an acid, an ester, an amide, an aldehyde and a ketone, the oxygen of an alcohol, and the nitrogen of an amine. | Rule | Over | Concludes | While | |---|---|---|---| | `valence_of` | `Atom`, `Element` | `valence` | the atom's `element` names an element whose `valence > 0`; the atom takes it | | `metal_valence` | `Atom`, `Element` | `valence` | the atom's `element` names an element whose `valence == 0`, and the atom's `bonds >= 0`; the atom takes its own `bonds` | | `weight_of` | `Atom`, `Element` | `weight` | the atom's `element` names an element; the atom takes its `weight` | | `hydrogen_weight` | `Atom`, `Element` | `hweight` | the atom has an `element`, and the element of `z == 1` has a `weight`; the atom takes it | | `bond_halves` | `Atom`, `Bond` | `bond_halves` | a bond's `a` names the atom and its `order > -1000000000000000000`; the atom takes the number of distinct such bonds | | `bond_claims` | `Atom`, `Bond` | `bond_claims` | a bond's `a` names the atom and its `order > -1000000000000000000`; the atom takes the number of claims of `order` those bonds hold | | `bonds_disputed` | `Atom` | `bonds_disputed` | the atom's `bond_claims` is greater than its `bond_halves`; concludes `True` | | `bonds_of` | `Atom`, `Bond` | `bonds` | a bond's `a` names the atom and the atom has no `bonds_disputed`; the atom takes the sum of every such bond's `order` | | `unbonded` | `Atom` | `bonds` | the atom has an `element` and no bond's `a` names it; concludes 0 | | `overbonded` | `Atom` | `overbonded` | the atom's `hydrogens < 0` | | `far_element` | `Bond`, `Atom` | `belement` | the bond's `b` names the atom; the bond takes the atom's `element` | | `far_hydrogens` | `Bond`, `Atom` | `bhydrogens` | the bond's `b` names the atom; the bond takes the atom's `hydrogens` | | `far_carbonyl` | `Bond`, `Atom` | `bcarbonyl` | the bond's `b` names an atom that is `carbonyl` | | `molecule_weight_atoms` | `Molecule`, `Atom` | `weight_atoms` | an atom's `molecule` names the molecule and its `mass > -1.0e300`; the molecule takes the number of distinct such atoms | | `molecule_weight_claims` | `Molecule`, `Atom` | `weight_claims` | an atom's `molecule` names the molecule and its `mass > -1.0e300`; the molecule takes the number of claims of `mass` those atoms hold | | `molecule_weight_disputed` | `Molecule` | `weight_disputed` | the molecule's `weight_claims` is greater than its `weight_atoms`; concludes `True` | | `molecule_hydrogen_atoms` | `Molecule`, `Atom` | `hydrogen_atoms` | an atom's `molecule` names the molecule and its `hydrogens > -1000000000000000000`; the molecule takes the number of distinct such atoms | | `molecule_hydrogen_claims` | `Molecule`, `Atom` | `hydrogen_claims` | an atom's `molecule` names the molecule and its `hydrogens > -1000000000000000000`; the molecule takes the number of claims of `hydrogens` those atoms hold | | `molecule_hydrogens_disputed` | `Molecule` | `hydrogens_disputed` | the molecule's `hydrogen_claims` is greater than its `hydrogen_atoms`; concludes `True` | | `molecule_atom_weight_disputed` | `Molecule`, `Atom` | `weight_disputed` | an atom whose `molecule` names the molecule has `bonds_disputed`; concludes `True` | | `molecule_atom_hydrogens_disputed` | `Molecule`, `Atom` | `hydrogens_disputed` | as `molecule_atom_weight_disputed`; concludes `True` | | `molecule_weight` | `Molecule`, `Atom` | `weight` | an atom's `molecule` names the molecule and the molecule has no `weight_disputed`; the molecule takes the sum of every such atom's `mass` | | `molecule_hydrogens` | `Molecule`, `Atom` | `hydrogens` | an atom's `molecule` names the molecule and the molecule has no `hydrogens_disputed`; the molecule takes the sum of every such atom's `hydrogens` | | `molecule_heavy` | `Molecule`, `Atom` | `heavy` | an atom's `molecule` names the molecule; the molecule takes the number of distinct such atoms | | `carbonyl` | `Atom`, `Bond` | `carbonyl` | the atom's `element` is `"C"`, and a bond from it has an `order` of 2 and a `belement` of `"O"` | | `carboxylic_acid` | `Atom`, `Bond` | `group` | the atom is `carbonyl`, and a bond from it has an `order` of 1, a `belement` of `"O"` and a `bhydrogens` of 1; concludes `"carboxylic acid"` | | `ester` | `Atom`, `Bond` | `group` | the atom's `carbonyl` is True, a bond from it of `order` 1 reaches an atom whose `element` is `"O"` and whose `hydrogens` are 0, and a bond from that oxygen has a `belement` of `"C"` and a `b` other than the first atom; concludes `"ester"` | | `amide` | `Atom`, `Bond` | `group` | the atom is `carbonyl`, and a bond from it has an `order` of 1 and a `belement` of `"N"`; concludes `"amide"` | | `aldehyde` | `Atom` | `group` | the atom is `carbonyl` with `hydrogens >= 1`, and no bond from it has an `order` of 1 and a `belement` of `"O"` or of `"N"`; concludes `"aldehyde"` | | `ketone` | `Atom`, `Bond` | `group` | the atom is `carbonyl`, and two bonds from it, each of `order` 1 and `belement` `"C"`, reach different atoms; concludes `"ketone"` | | `alcohol` | `Atom`, `Bond` | `group` | the atom's `element` is `"O"` and its `hydrogens` is 1, and a bond from it has a `belement` of `"C"` and no `bcarbonyl`; concludes `"alcohol"` | | `amine` | `Atom`, `Bond` | `group` | the atom's `element` is `"N"`, a bond from it has a `belement` of `"C"`, no bond from it has a `bcarbonyl`, and no bond from it has an `order > 1`; concludes `"amine"` | | `term_formation` | `Term`, `Species` | `formation` | the term's `species` names a species; the term takes its `formation` | | `term_missing` | `Term` | `missing` | the term names a `species` and has no `formation` | | `reaction_terms` | `Reaction`, `Term` | `terms` | a term's `reaction` names the reaction and its `contribution > -1.0e300`; the reaction takes the number of distinct such terms | | `reaction_claims` | `Reaction`, `Term` | `claims` | a term's `reaction` names the reaction and its `contribution > -1.0e300`; the reaction takes the number of claims of `contribution` those terms hold | | `reaction_disputed` | `Reaction` | `disputed` | the reaction's `claims` is greater than its `terms`; concludes `True` | | `reaction_enthalpy` | `Reaction`, `Term` | `enthalpy` | a term's `reaction` names the reaction and the reaction has no `disputed`; the reaction takes the sum of every such term's `contribution` | | `reaction_incomplete` | `Reaction`, `Term` | `incomplete` | a term of the reaction is `missing` | `chemistry` declares no standing constraint. Six notes that are contract rather than commentary: - **Hydrogens are concluded, not written.** The structure is a graph of the heavy atoms and the bonds between them, as a skeletal drawing is. Each atom carries the hydrogens its valence leaves over, and an atom with no bond carries its whole valence. Nothing is concluded until the element is written: before `elements()` is called, or for a symbol with no `Element`, an atom has no valence, no hydrogens and no mass, and `weight()` answers 0.0 for a molecule none of whose atoms has one. An atom of an element of valence 0 takes its own bonds as its valence, so a metal carries no hydrogens and adds its weight to its molecule's. - **A group takes every reading inside it.** Each group rule reads exactly the bonds it names, so an atom that fits two rules carries both groups, and an atom that fits none carries none. A nitrogen is read as an amine only while every bond it has is single, so the nitrogen of a nitrile or an imine carries no group. - **A molecule's formula and weight are sums over its atoms.** `Molecule.hydrogens` adds the hydrogens of every atom, and an overbonded atom adds a negative number. `overbonded` and `faults()` name it. - **A reaction's enthalpy is the sum over the terms the store holds.** A term whose species has no `formation` adds nothing, and the reaction is `incomplete`: its `enthalpy` is the sum of the terms that have one. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and `unsettled()` names the fact. - **A sum is not drawn from a member bound to it twice.** A sum reads every value of what it sums, so a sulfur atom whose element's `weight` holds two values would be weighed at both, and a bond whose `order` a second source writes, even the same order, counted twice. The `_halves`, `_atoms`, `terms` and `_claims` fields count the members and their claims over the one binding the sum reads, and while the claims are more, the sum is disputed and not concluded, nor anything that rests on it. An atom whose bonds are disputed has no `hydrogens` or `mass`, so it disputes its molecule's weight and hydrogens rather than leave them. A member with no value of the sum is in neither count, so it hides no dispute. An atom whose `molecule`, a bond whose `a` or a term whose `reaction` holds two values counts in each it names, and each of those sums is one source's. ### 3.34 `chemistry` — queries Called by name after `import chemistry`. The first six write facts and answer nothing. The next eight read what the rules concluded; a read refuses only what is disputed, as its cell states, and otherwise answers by the rule its cell states, and `unsettled()` names what is in disagreement. The last thirteen are value scripts that return a value and write nothing. | Query | Answers | |---|---| | `element(symbol, z, valence, weight)` | Nothing. Writes the `Element` named `symbol` with those three fields, under the source `"CIAAW"`. | | `elements()` | Nothing. Writes the thirteen elements of §3.31, each with its abridged standard atomic weight and its usual valence in an organic molecule. | | `atom(name, symbol, molecule)` | Nothing. Writes an `Atom` named `name`, of the element `symbol`, in `molecule`. | | `bond(a, b, order)` | Nothing. Writes the bond between atoms `a` and `b` as its two halves, `a-b` and `b-a`, each of `order`. Writing a bond again replaces it. | | `species(name, formation)` | Nothing. Writes a `Species` named `name` with its enthalpy of formation, in kJ/mol. | | `term(reaction, species, coefficient)` | Nothing. Writes the `Term` named `reaction`, `-` and `species`, counting `species` in `reaction` with `coefficient`: positive for a product, negative for a reactant. | | `weight(name)` | The `weight` of molecule `name`, in g/mol: the least value in force where values disagree, and 0.0 when it has none. A molecule with `weight_disputed` is refused. | | `enthalpy(reaction)` | The `enthalpy` of `reaction`, in kJ: the least value in force where values disagree, and 0.0 when it has none. A reaction with `disputed` is refused. | | `formula(name)` | The formula of molecule `name` in the Hill order: carbon first, then hydrogen, then the other elements alphabetically, or every element alphabetically when there is no carbon. A count of 1 is not written. The hydrogens are the ones the rules concluded, and each atom is counted once. A molecule with `hydrogens_disputed`, or one of whose atoms holds two different `element` values, is refused. | | `disputed_molecules()` | The molecules with `weight_disputed` or `hydrogens_disputed`, sorted. | | `disputed_reactions()` | The reactions with `disputed`, sorted. | | `groups(name)` | The functional groups on the atoms of molecule `name`, each named once, sorted. | | `faults()` | One line for each atom bonded past its valence, `overbonded: ` and the atom, for each reaction with a species whose enthalpy of formation is not recorded, `incomplete: ` and the reaction, and for each atom with `bonds_disputed`, molecule in `disputed_molecules()` and reaction in `disputed_reactions()`, `disputed: atom `, `disputed: molecule ` or `disputed: reaction ` and its name, sorted. | | `unsettled()` | Each element, atom, bond, species and term that holds two different values in force for a field you write: an element's `z`, `valence` or `weight`, an atom's `element` or `molecule`, a bond's `a`, `b` or `order`, a species' `formation`, or a term's `reaction`, `species` or `coefficient`. Given as its kind in lower case and its name, `element S`, sorted. | | `parse(formula)` | How many atoms of each element `formula` holds, as a dict: `"Ca(OH)2"` is one calcium, two oxygens and two hydrogens. Brackets nest. A charge written after a caret is left out. | | `charge(formula)` | The charge written after a caret: `"^2-"` is -2, `"^+"` is 1, and no caret is 0. | | `molar_mass(formula)` | The molar mass of `formula` in g/mol, from the `weight` of each element in the store, counted by `parse`. 0.0 when an element in it has no weight. | | `gcd(a, b)` | The greatest common divisor of the absolute values of `a` and `b`. | | `balance(reactants, products)` | The least whole-number coefficients that balance the equation, reactants first, each element and the charge being the same on both sides. `[]` unless the equation has exactly one balance up to scale with every coefficient positive. | | `charge_ph(acid, base, pkas)` | The pH at which the charges in a solution balance: a weak acid of total concentration `acid` mol/L with the acid constants `pkas`, one for each proton it gives up, beside `base` mol/L of a strong base's cation. Water's ion product is taken as 1.0e-14. Found by bisection on the pH between -2 and 16. A concentration below 0 is refused with `ValueError`. Where an acid constant is so large that a term of the balance passes the largest real, the share of protons given up is taken from the terms' common logarithms less the largest of them. | | `ph(acid, pkas)` | `charge_ph(acid, 0.0, pkas)`: the pH of a weak acid of concentration `acid` mol/L in water. | | `titration(acid, va, base, vb, pkas)` | The pH after `vb` mL of a strong base of concentration `base` mol/L is added to `va` mL of a weak acid of concentration `acid`: `charge_ph` of the two concentrations after dilution. A volume below 0 is refused with `ValueError`. Where the total volume or a concentration after dilution passes the largest real, it is the concentration times the share of the volume, of halves. | | `consecutive(k1, k2, t, dt)` | For A to B to C, first order with rate constants `k1` and `k2`, from pure A: the fractions of A, B and C at time `t`, integrated by the fourth-order Runge-Kutta method in steps of `dt`. A rate constant or a time below 0, or a step not above 0, is refused with `ValueError`, and so is a step so long for the rates that the integration diverges past the range of a real. | | `consecutive_exact(k1, k2, t)` | The same three fractions in closed form, for `k1` different from `k2`. A rate constant or a time below 0 is refused with `ValueError`. | | `peak_time(k1, k2)` | When B is at its most: `ln(k1 / k2) / (k1 - k2)`, and `1 / k1` when the two are equal; where `k1 / k2` is not a normal real, its logarithm is `ln k1 - ln k2`. A rate constant below 0 is refused with `ValueError`. | | `equilibrium(kf, kr, a0, b0, t, dt)` | For A plus B to C and back, with forward rate constant `kf` and reverse `kr`, from `a0` and `b0` mol/L of A and B and no C: the concentration of C at time `t`, integrated by the fourth-order Runge-Kutta method in steps of `dt`. | | `equilibrium_exact(k, a0, b0)` | The concentration of C at equilibrium, where C over the product of A and B equals the equilibrium constant `k`, which is `kf / kr`: the smaller root of `k x^2 - (k (a0 + b0) + 1) x + k a0 b0 = 0`, taken as `2 k a0 b0 / (p + r)` with `p = k a0 + k b0 + 1` and `r` the root of `(k a0 - k b0)^2 + 2 (k a0 + k b0) + 1`, which is the same root and subtracts nothing, and where `k` times the larger concentration is above 1, the same divided through by `k` and by 8, so that no step passes the range of a real. A constant or a concentration below 0 is refused with `ValueError`; a constant of 0 gives 0. | --- ### 3.35 `biology` — declared fields The four writing scripts of §3.37 write `Compound`, `Reaction`, `Family` and `Person` under the sources `"medium"`, `"network"` and `"pedigree"`, and you may write the same fields yourself. A **compound** and a **reaction** are named by you, and so are a **family** and a **person**; a reaction's `s1`, `s2`, `p1` and `p2`, a person's `family`, `mother` and `father`, and a family's name in `Person.family` are each the name of another subject. A **medium** is what a growth medium supplies. A **scope** is every compound the network can make from it. A **mode** is how the trait a family is recorded for is inherited: `"autosomal dominant"`, `"autosomal recessive"` or `"X-linked recessive"`. **`Compound`** | Field | Class | Notes | |---|---|---| | `medium` | `bool` | True for a compound the growth medium supplies. | | `reached` | `bool` | Concluded by a rule (§3.36). Never written. | **`Reaction`** | Field | Class | Notes | |---|---|---| | `s1` | `string` | The name of its first substrate, a `Compound`. | | `s2` | `string` | The name of its second substrate. Absent for a reaction with one. | | `p1` | `string` | The name of its first product. | | `p2` | `string` | The name of its second product. Absent for a reaction with one. | | `runs` | `bool` | Concluded by a rule (§3.36). Never written. | **`Family`** | Field | Class | Notes | |---|---|---| | `mode` | `string` | `"autosomal dominant"`, `"autosomal recessive"` or `"X-linked recessive"`. No rule concludes anything for a family with any other mode. | | `unexplained` | `int` | Concluded by a rule (§3.36). Never written. | **`Person`** | Field | Class | Notes | |---|---|---| | `family` | `string` | The name of the `Family` the person is recorded in. | | `mother` | `string` | The name of the person's mother, a `Person`. Absent where not recorded. | | `father` | `string` | The name of the person's father. Absent where not recorded. | | `sex` | `string` | `"F"` or `"M"`. | | `affected` | `bool` | Whether the person shows the trait. | | `inbred` | `bool` | Concluded by a rule (§3.36). Never written. | | `carrier` | `bool` | Concluded by a rule (§3.36). Never written. | | `unexplained` | `bool` | Concluded by a rule (§3.36). Never written. | **`Parent`** and **`Ancestor`** declare no field. Each is a relation between two people, `Parent.c.p` for a child `c` and a parent `p`, and `Ancestor.x.y` for a person `x` and an ancestor `y`, concluded by the rules of §3.36 and never written. They are declared so that reading one that does not stand answers empty. ### 3.36 `biology` — standing rules Each holds continuously, as in §3.17. A rule over several subjects binds them as the cell names them: a compound as `a`, `b` or `c`, a reaction as `r`, a family as `y`, and a person as `c` for a child, `m` for a mother, `f` for a father, `p` for a parent and `x`, `y` and `z` along a line of descent. | Rule | Over | Concludes | While | |---|---|---|---| | `supplied` | `Compound` | `reached` | the compound's `medium` is True | | `runs_one` | `Reaction`, `Compound` | `runs` | the reaction's `s1` names the compound, the compound is `reached`, and the reaction has no `s2` | | `runs_two` | `Reaction`, `Compound` | `runs` | the reaction's `s1` names a compound that is `reached` and its `s2` names a compound that is `reached` | | `makes_first` | `Reaction`, `Compound` | `reached` | the reaction `runs` and its `p1` names the compound | | `makes_second` | `Reaction`, `Compound` | `reached` | the reaction `runs` and its `p2` names the compound | | `parent_mother` | `Person` | `Parent` | the child's `mother` names a person. Concludes `Parent.c.m` | | `parent_father` | `Person` | `Parent` | the child's `father` names a person. Concludes `Parent.c.f` | | `ancestor_parent` | `Person` | `Ancestor` | `Parent.x.y` holds. Concludes `Ancestor.x.y` | | `ancestor_further` | `Person` | `Ancestor` | `Ancestor.x.y` and `Parent.y.z` hold. Concludes `Ancestor.x.z` | | `inbred_shared` | `Person` | `inbred` | the child's `mother` and `father` have an ancestor in common | | `inbred_father_line` | `Person` | `inbred` | the child's `father` is an ancestor of the child's `mother` | | `inbred_mother_line` | `Person` | `inbred` | the child's `mother` is an ancestor of the child's `father` | | `recessive_parent` | `Family`, `Person` | `carrier` | the family's `mode` is `"autosomal recessive"`, a child in the family is `affected`, and `Parent.c.p` holds for a parent who is not `affected`; the parent is the carrier | | `recessive_child` | `Family`, `Person` | `carrier` | the family's `mode` is `"autosomal recessive"`, a child in the family is not `affected`, and `Parent.c.p` holds for a parent who is `affected`; the child is the carrier | | `x_linked_mother` | `Family`, `Person` | `carrier` | the family's `mode` is `"X-linked recessive"`, a child in the family has `sex` `"M"` and is `affected`, and the child's `mother` is not `affected`; the mother is the carrier | | `x_linked_daughter` | `Family`, `Person` | `carrier` | the family's `mode` is `"X-linked recessive"`, a child in the family has `sex` `"F"` and is not `affected`, and the child's `father` is `affected`; the daughter is the carrier | | `dominant_unexplained` | `Family`, `Person` | `unexplained` | the family's `mode` is `"autosomal dominant"`, a child in the family is `affected`, and neither the child's `mother` nor its `father` is `affected`; the child is unexplained | | `recessive_unexplained` | `Family`, `Person` | `unexplained` | the family's `mode` is `"autosomal recessive"`, a child in the family is not `affected`, and both the child's `mother` and its `father` are `affected`; the child is unexplained | | `x_linked_daughter_unexplained` | `Family`, `Person` | `unexplained` | the family's `mode` is `"X-linked recessive"`, a child in the family has `sex` `"F"` and is `affected`, and the child's `father` is not `affected`; the daughter is unexplained | | `x_linked_son_unexplained` | `Family`, `Person` | `unexplained` | the family's `mode` is `"X-linked recessive"`, a child in the family has `sex` `"M"` and is not `affected`, and the child's `mother` is `affected`; the son is unexplained | | `family_unexplained` | `Family`, `Person` | `unexplained` | a person in the family is `unexplained`; the family takes the number of distinct such people | `biology` declares no standing constraint. Five notes that are contract rather than commentary: - **A cycle of reactions does not hold itself up.** A compound is `reached` only through a chain of reactions that begins at the medium. Two reactions that make each other's substrate from each other's product reach nothing unless the medium, or another chain from it, supplies one of them; when the medium stops supplying it, the scope withdraws the whole cycle. - **A scope assumes every reaction can run.** `runs` asks that each substrate be `reached` and nothing more. The rules do not check energy, balance, direction, enzyme or concentration. - **Every pedigree rule assumes the trait shows in everyone who has its genotype, and that no new mutation arose in the family.** A person `unexplained` is where one of those, or the record itself, does not hold. Each of `carrier` and `unexplained` is concluded only from the generation it names: a carrier is not carried back through a grandparent, and a sister of an affected son is not concluded a carrier. - **A person written with no parent has no parent.** The scripts of §3.37 pass `""` for a parent not recorded, which writes nothing; they do not withdraw a parent an earlier call recorded. Correct a parent by writing the name again. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. A rule that asks for something to be absent is answered for the subject: a reaction to which another source gives an `s2` is no longer one with a single substrate, and runs only when that compound is `reached` as well. A family's `unexplained` counts each person once, however many rules or values conclude them `unexplained`. ### 3.37 `biology` — queries Called by name after `import biology`. No query refuses because sources disagree: a reader answers every value in force, and `unsettled()` names what is in disagreement. The four writers write under the sources `"medium"`, `"network"` and `"pedigree"`, so writing the same fact again is a correction and a write under another source is a disagreement. | Query | Answers | |---|---| | `medium(name)` | Nothing. Writes `Compound.name.medium` True under the source `"medium"`. | | `reaction(name, s1, s2, p1, p2)` | Nothing. Writes the reaction `name`'s `s1` and `p1` under the source `"network"`, and its `s2` and `p2` only when they are not `""`. | | `family(name, mode)` | Nothing. Writes the family `name`'s `mode` under the source `"pedigree"`. | | `person(name, family, sex, affected, mother, father)` | Nothing. Writes the person `name`'s `family`, `sex` and `affected` under the source `"pedigree"`, and its `mother` and `father` only when they are not `""`. | | `scope()` | Every compound the network can make from its medium, the medium's own included, sorted. | | `blocked()` | Every reaction with a recorded `s1` that does not run, sorted. | | `needs(target, candidates)` | Each candidate that, added to the medium alone, would make `target` `reached`, in the order given. Each is a hypothesis: nothing is written, and the medium is left as it was. | | `people(name)` | Every person recorded in family `name`, sorted. | | `ancestors(name)` | Every recorded ancestor of person `name`, sorted. | | `inbred()` | Every child whose parents are related by descent, sorted. | | `carriers(name)` | Every member of family `name` that the mode requires to carry the allele, sorted. | | `unexplained(name)` | Every member of family `name` whose record the mode cannot explain, sorted. | | `unsettled()` | Every compound, reaction, family and person for which a field it writes among `medium`, `s1`, `s2`, `p1`, `p2`, `mode`, `family`, `mother`, `father`, `sex` and `affected` holds two different values in force, as its kind in lower case, its name and the field, `person nell affected`, sorted. | | `complement(dna)` | The reverse complement of a strand of `A`, `T`, `C` and `G`: the other strand, read in its own direction. | | `transcribe(dna)` | The messenger RNA a coding strand is copied into: `dna` with `U` for each `T`. | | `translate(rna, table)` | The protein `rna` codes for, in one-letter amino acids, read from the first `AUG` to the first stop codon, or to the last whole codon when none comes. `table` 1 is the standard code and 2 the vertebrate mitochondrial code. `""` when there is no `AUG`. | | `gc(dna)` | The share of `dna`'s bases that are `G` or `C`, 0.0 for an empty strand. | | `gametes(genotype)` | The gametes a genotype written two letters a gene, `"AaBb"`, makes: one allele of each gene, every combination once, in order. | | `zygote(a, b)` | The genotype two gametes make, each gene's letters in character order, so a dominant capital comes first. | | `cross(a, b)` | How many of the pairings of the two parents' gametes give each genotype. | | `phenotypes(a, b)` | The same pairings by what they show: each gene's first letter, so `"AB"` shows both dominant traits. | | `chi_square(observed, ratio)` | The sum over classes of `(observed - expected)^2 / expected`, where `expected` is the total of `observed` shared out in the proportions of `ratio`. A class `ratio` gives a share of 0 adds nothing where none were observed in it, and makes the statistic `inf` where some were. A count or a share below 0 is refused with `ValueError`. Where a sum or a square on the way passes the range of a real, or falls below the smallest normal one, it is taken again with the counts and the shares each scaled by a power of two and the statistic scaled back. | | `hardy_weinberg(aa, ab, bb)` | A list: the first allele's frequency `p` from the counts of the three genotypes, and the chi-square of the counts against `p^2 : 2pq : q^2`; `[1.0, 0.0]` or `[0.0, 0.0]` for a sample of one homozygote. | | `logistic(r, k, n0, t, dt)` | The population at time `t` from `n0`, growing at rate `r` toward capacity `k` by `dN/dt = rN(1 - N/k)`, stepped by fourth-order Runge–Kutta in steps of `dt`. A capacity not above 0 or a population below 0 is refused with `ValueError`. Where a step passes the range of a real, the steps are taken again with `n0` and `k` scaled by a power of two and the population scaled back. | | `logistic_exact(r, k, n0, t)` | The same population from the equation's solution, `k / (1 + (k - n0) / n0 * exp(-r t))`; 0 for an `n0` of 0 and `k` for an `n0` of `k`. The same refusals as `logistic`. Where the factor, the exponential or their product passes the range of a real, or the exponential falls below the smallest normal one, each is carried as a mantissa and a power of two. | | `predator_prey(alpha, beta, gamma, delta, x0, y0, t, dt)` | A list: prey `x` and predators `y` at time `t` by fourth-order Runge–Kutta, for `dx/dt = alpha x - beta x y` and `dy/dt = delta x y - gamma y`, and the relative change in `delta x - gamma ln x + beta y - alpha ln y`, which the exact motion keeps. Where a step passes the range of a real, the steps are taken again with `x0` and `y0` scaled by powers of two and `delta` and `beta` by the same powers the other way, and where the populations pass it even so, they are refused with `ValueError`. Where that quantity passes the range, it is taken with the four rates scaled by a power of two. | | `drift(n, p0, generations, seed)` | A list: the frequency of an allele after `generations` of a population of `n` diploid individuals, each generation drawing its `2n` gene copies at random from the last, and the generation the allele was fixed or lost in, -1.0 if neither. A seed gives the same run every time. | | `fixation(n, p0, runs, generations, seed)` | The share of `runs` populations, drawn one after another from one stream, in which the allele is fixed within `generations`. | | `ring(start, steps)` | The states of a ring of genes, one character a gene, `"1"` for on, from `start` through `steps` steps, where at each step all at once a gene is on exactly when the gene before it in the ring was off. | | `period(start)` | How many steps the ring takes to return to a state it has been in, from `start`: 1 for a state that stays as it is. | ### 3.38 `astronomy` — declared fields The writing scripts of §3.41 write `Site`, `Star`, `Night` and `Booking` under the sources `"sites"`, `"catalogue"`, `"nights"` and `"bookings"`, and `up()` writes `Up` under `"ephemeris"`. You may write the same fields yourself. A **site**, a **star**, a **night**, an **up** and a **booking** are each named by you, except an `Up`, which `up()` names `__` after the star, the site and the day of the start it is given. A night's and a booking's `site`, a booking's `star` and an up's `star` and `site` are each the name of another subject. Angles are in degrees, latitude and declination positive north, longitude positive east, and right ascension from 0 to 360. A **magnitude** is the star's brightness on the astronomers' scale, on which a smaller number is brighter and a negative one is brighter than zero. All times are UT. Three facts are written with a **window**, a stretch of time for which they hold: a night's `site`, a booking's `site` and `star`, and an up's `star` and `site`. Each of those windows is also recorded as two facts of its own that hold at all times, so a window can be read when it is not now: `opens` and `closes` for a night, `starts` and `ends` for a booking, `rises` and `sets` for an up. **`Site`** | Field | Class | Notes | |---|---|---| | `lat` | `real` | Latitude in degrees, north positive. | | `lon` | `real` | Longitude in degrees, east positive. | | `limit` | `real` | The faintest magnitude the site's instrument reaches. | | `circumpolar_above` | `real` | Computed from `lat` (§3.39). Never written. | | `hidden_below` | `real` | Computed from `lat` (§3.39). Never written. | | `circumpolar_below` | `real` | Computed from `lat` (§3.39). Never written. | | `hidden_above` | `real` | Computed from `lat` (§3.39). Never written. | **`Star`** | Field | Class | Notes | |---|---|---| | `ra` | `real` | Right ascension in degrees. | | `dec` | `real` | Declination in degrees, north positive. | | `mag` | `real` | Magnitude. | **`Night`** | Field | Class | Notes | |---|---|---| | `site` | `string` | The name of the `Site` the night is dark at. Written with the night as its window. | | `opens` | `datetime` | When the night begins. Valid at all times. | | `closes` | `datetime` | When the night ends. Valid at all times. | **`Up`** | Field | Class | Notes | |---|---|---| | `star` | `string` | The name of the `Star` above the horizon. Written with the stretch it is above as its window. | | `site` | `string` | The name of the `Site` it is above the horizon of. Written with the same window. | | `rises` | `datetime` | When the stretch begins. Valid at all times. | | `sets` | `datetime` | When the stretch ends. Valid at all times. | **`Booking`** | Field | Class | Notes | |---|---|---| | `site` | `string` | The name of the `Site` the instrument is booked at. Written with the booking as its window. | | `star` | `string` | The name of the `Star` it is booked for. Written with the same window. | | `starts` | `datetime` | When the booking begins. Valid at all times. | | `ends` | `datetime` | When the booking ends. Valid at all times. | | `observable` | `bool` | Concluded by a rule (§3.40), and holds for the overlap of the booking, a night and an up alone. Never written. | **`Circumpolar`**, **`Hidden`** and **`Visible`** declare no field. Each is a relation between a star and a site, `Circumpolar.s.t` for a star `s` and a site `t`, concluded by the rules of §3.40 and never written. They are declared so that reading one that does not stand answers empty. ### 3.39 `astronomy` — derived fields | Field | Definition | |---|---| | `Site.circumpolar_above` | `90 - lat` | | `Site.hidden_below` | `lat - 90` | | `Site.circumpolar_below` | `-90 - lat` | | `Site.hidden_above` | `90 + lat` | Each is a limit of declination, in degrees, set by the site's latitude alone. At a northern site, a star whose declination is above `circumpolar_above` never sets, and one whose declination is below `hidden_below` never rises. At a southern site the limits are the other pair: a star below `circumpolar_below` never sets and one above `hidden_above` never rises. All four are absent until the site's `lat` is written. A site at latitude 0 is read as a northern site. ### 3.40 `astronomy` — standing rules Each holds continuously, as in §3.17. A rule over a star and a site binds them as `s` and `t`; a rule over a booking, a night and an up binds them as `b`, `n` and `u`. | Rule | Over | Concludes | While | |---|---|---|---| | `circumpolar_north` | `Star`, `Site` | `Circumpolar` | the site's `lat >= 0` and the star's `dec` is above the site's `circumpolar_above`; concludes `Circumpolar.s.t` | | `circumpolar_south` | `Star`, `Site` | `Circumpolar` | the site's `lat < 0` and the star's `dec` is below the site's `circumpolar_below`; concludes `Circumpolar.s.t` | | `hidden_north` | `Star`, `Site` | `Hidden` | the site's `lat >= 0` and the star's `dec` is below the site's `hidden_below`; concludes `Hidden.s.t` | | `hidden_south` | `Star`, `Site` | `Hidden` | the site's `lat < 0` and the star's `dec` is above the site's `hidden_above`; concludes `Hidden.s.t` | | `visible_north` | `Star`, `Site` | `Visible` | the site's `lat >= 0`, the star's `dec` is no lower than the site's `hidden_below`, and the star's `mag` is no fainter than the site's `limit`; concludes `Visible.s.t` | | `visible_south` | `Star`, `Site` | `Visible` | the site's `lat < 0`, the star's `dec` is no higher than the site's `hidden_above`, and the star's `mag` is no fainter than the site's `limit`; concludes `Visible.s.t` | | `observable` | `Booking`, `Night`, `Up` | `observable` | the night's `site` and the up's `site` both name the booking's `site`, and the up's `star` names the booking's `star`; the booking is `observable` | `astronomy` declares no standing constraint. Six notes that are contract rather than commentary: - **The limits are geometry, not weather.** A star never sets where its lowest altitude, the absolute value of the sum of the site's latitude and the star's declination, less 90 degrees, is above the horizon, and never rises where its highest, 90 degrees less the absolute value of the difference, is below it. The rules take the horizon to be the geometric one: no refraction, no terrain, no twilight and no cloud. - **A star on a limit is not on its far side.** A star whose declination is exactly `circumpolar_above` is not `Circumpolar`, and one exactly at `hidden_below` is not `Hidden` and is `Visible` if it is bright enough. The same holds for the southern pair. - **`Visible` includes what never sets.** A circumpolar star is above the horizon at all times, so it is `Visible` where it is bright enough. A star that is `Hidden` is not `Visible`, and a star fainter than the site's `limit` is neither `Visible` nor kept from being `Hidden` or `Circumpolar`. The three relations are independent conclusions. - **A booking is observable for an overlap.** `observable` holds for the stretch where the booking's window, a night at its site and the star's time above that site's horizon all overlap, and for no other. It is not concluded for a star that never rises, because `up()` writes nothing for one, and the rule does not read the star's magnitude or the site's `limit`. A booking at a site with no `Night`, or for a star with no `Up` at it, is not observable. - **The sky does not write itself.** A star's rising and setting are facts you write with `up()` (§3.41); nothing concludes one from the star and the site alone, and a rise is not corrected when a star's or a site's coordinates are. Call `up()` again for the same star, site and day to replace it. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. A star whose `dec` is given two values is `Hidden` at a site if either is below `hidden_below`, and `Visible` if either is not. `unsettled()` names the fact. `up()` and `window()` are the readers that refuse: `up()` needs one value of the star's `ra` and `dec` and of the site's `lat` and `lon`, and `window()` one value of the booking's `starts` and `ends`, and each is refused while any of them has two. `unsettled()` does not name a booking. ### 3.41 `astronomy` — queries Called by name after `import astronomy`. The first five write facts and answer nothing. The next nine read what the rules concluded or what was written, and two of them take a claim; no read refuses because sources disagree, except `window()` as §3.40 says: it answers by the rule its cell states, and `unsettled()` names what is in disagreement about a site or a star. The last fourteen are value scripts that return a value and write nothing. Angles are in degrees, times in UT and Julian dates in days. | Query | Answers | |---|---| | `site(name, latitude, longitude, faintest)` | Nothing. Writes the `Site` named `name`'s `lat`, `lon` and `limit` under the source `"sites"`. | | `star(name, right_ascension, declination, magnitude)` | Nothing. Writes the `Star` named `name`'s `ra`, `dec` and `mag` under the source `"catalogue"`. | | `night(name, where, start, end)` | Nothing. Writes the `Night` named `name`'s `site` as `where`, with the window from `start` to `end`, and its `opens` and `closes` as those two instants, under the source `"nights"`. | | `book(name, where, target, start, end)` | Nothing. Writes the `Booking` named `name`'s `site` as `where` and `star` as `target`, each with the window from `start` to `end`, and its `starts` and `ends` as those two instants, under the source `"bookings"`. | | `up(target, where, start)` | Nothing. Writes, under the source `"ephemeris"`, the `Up` named `__`, the date being `start`'s: the star `target` above the horizon of the site `where` from its rising to its setting, on the first passage that has not ended by `start`, that passage included if it began before `start`. A star that never sets is written above the horizon for the day from `start`, and one that never rises is written nothing. Rising and setting are for the geometric horizon, from the sidereal rate. Pass a night's start to get that night's passage. | | `number(c)` | The number the claim `c` holds: a real as it is, an integer as a real, and 0.0 for any other value. | | `stars_in(relation, where)` | The stars in the relation named `"circumpolar"`, `"hidden"` or `"visible"` for the site `where`, sorted. Any other name reads `"visible"`. | | `circumpolar(where)` | The stars that never set at the site `where`, sorted. | | `hidden(where)` | The stars that never rise at the site `where`, sorted. | | `visible(where)` | The stars that rise at the site `where`, or never set, and are no fainter than its `limit`, sorted. | | `observable_at(t)` | The bookings observable at the instant `t`, sorted. A booking is read at `t` only where its own window holds it. | | `instant_of(c)` | The instant the claim `c` holds, as a list of one, and `[]` for any value that is not an instant. | | `window(booking)` | The stretch the booking named `booking` is observable for, as its first and last instants, written as text, or `[]` where it never is. It opens where the last of the booking, a night and a rising does. The booking must have been written. | | `unsettled()` | Each site and star that holds two different values in force for a field you write: a site's `lat`, `lon` or `limit`, or a star's `ra`, `dec` or `mag`. Given as `site` or `star`, its name and the field, `star vega dec`, sorted. | | `jd(year, month, day)` | The Julian date of a calendar date, `day` carrying its fraction, by Meeus's formula 7.1: in the Julian calendar before 1582 October 15 and the Gregorian from then, as astronomers date events. | | `jd_of(t)` | The Julian date of the instant `t`. | | `instant(j)` | The instant of the Julian date `j`, to the nanosecond. A Julian date held as a real steps in about 40 microseconds, so the instant is the real's and not the decimal written for it. | | `gmst(j)` | Greenwich mean sidereal time at the Julian date `j`, in degrees from 0 to 360, by Meeus's formula 12.4. A date so far from 2000 that the angle passes the largest real is refused with `ValueError`. | | `lst(j, longitude)` | Local mean sidereal time at a longitude, east positive: `gmst(j)` plus the longitude taken modulo 360 degrees by `math.fmod`, from 0 to 360. | | `hms(degrees)` | An angle of the sky's rotation as `[hours, minutes, seconds]`, at 15 degrees an hour, each a real; for an angle from 0 to 360. | | `altitude(declination, latitude, hour_angle)` | A body's altitude above the horizon in degrees, from its declination, the observer's latitude and its hour angle, which is 0 at transit. No refraction is allowed for. Each angle is taken modulo 360 degrees by `math.fmod` first. | | `semi_arc(declination, latitude, horizon)` | The hour angle in degrees at which a body crosses the altitude `horizon`, rising and setting symmetrically about its transit: 0 for one that never reaches it, 180 for one that never falls below it. Each angle is taken modulo 360 degrees by `math.fmod` first. | | `rise_set(ra, declination, latitude, longitude, day)` | A star's rising, transit and setting at a site, as `[rising, transit, setting]`, `[transit]` for a star that never sets and `[]` for one that never rises. The transit is the first at or after the instant `day`, and the rising may fall before it. Over the geometric horizon. Each angle is taken modulo 360 degrees by `math.fmod` first. | | `sun(j)` | The Sun's right ascension and declination at the Julian date `j`, as `[ra, dec]`, by the Astronomical Almanac's low-precision formulas, good to about 0.01 degrees from 1950 to 2050. | | `day_length(latitude, j)` | The hours from sunrise to sunset at a latitude on the day of the Julian date `j`: the Sun's semi-arc to -0.833 degrees, its upper limb at the horizon after refraction, at 15 degrees an hour. 24 where the Sun never sets and 0 where it never rises. | | `kepler(mean_anomaly, e)` | The eccentric anomaly `E` with `E - e sin E = M` for the mean anomaly `M` in radians and an eccentricity `e` from 0 up to 1: `[E, steps]`, found by Newton's method from `M`, or from pi where `e` is above 0.8, stopped when a step changes `E` by less than 1e-15, in at most 64 steps. An `M` past pi is taken to within pi of 0 first by `math.fmod`, which is exact, and the turns are added back to `E`; an `M` below 0 is solved for its size and `E` given its sign, as the equation is odd. Another eccentricity is refused with `ValueError`. | | `true_anomaly(eccentric_anomaly, e)` | The true anomaly in radians, the angle from perihelion seen from the focus, from the eccentric anomaly. | | `two_body(e, orbits, per_orbit)` | A body on an orbit of eccentricity `e`, from 0 up to 1, about a mass with GM equal to 1 and a semi-major axis of 1, from perihelion, by fourth-order Runge-Kutta at `per_orbit` steps an orbit for `orbits` orbits: `[the energy at the start, the energy at the end, the distance from where Kepler's equation puts it then]`. The energy is -0.5 for every such orbit, so how far the end differs is the integration's error. The work grows with the number of steps. | ### 3.42 `geography` — declared fields The scripts of §3.44 write `Region`, `Border`, `Place` and `Box` under the sources `"regions"`, `"map"` and `"places"`, and you may write the same fields yourself. A **region**, a **border**, a **place** and a **box** are each named by you. A region's `parent` is the name of another region, and a border's `a` and `b` are the names of the two regions it lies between. A **level** is any word you use for what kind of region it is, such as `"country"`, `"county"` or `"municipality"`. Latitude and longitude are in degrees, north and east positive. **`Region`** | Field | Class | Notes | |---|---|---| | `parent` | `string` | The name of the region this one lies in directly. Absent for a region that lies in none you record. | | `level` | `string` | What kind of region it is, in any word you use. | | `colour` | `string` | The colour a map gives it. | | `holds` | `int` | Concluded by a rule (§3.43). Never written. How many regions lie within it at any depth, each counted once. Absent for a region that holds none. | **`Border`** | Field | Class | Notes | |---|---|---| | `a` | `string` | The name of the first region, a `Region`. | | `b` | `string` | The name of the second region. A border is named `_` by the script that writes it. | **`Place`** | Field | Class | Notes | |---|---|---| | `lat` | `real` | Latitude in degrees, from -90 to 90, north positive. | | `lon` | `real` | Longitude in degrees, from -180 to 180, east positive. | **`Box`** | Field | Class | Notes | |---|---|---| | `south` | `real` | The southern edge, a latitude in degrees. | | `north` | `real` | The northern edge, a latitude in degrees. A box whose `south` lies north of its `north` holds no place. | | `west` | `real` | The western edge, a longitude in degrees. | | `east` | `real` | The eastern edge, a longitude in degrees. A box whose `west` lies east of its `east` crosses the antimeridian, 180°, and holds the longitudes from `west` round to `east`. A box whose two edges are equal is that one meridian. | **`Within`**, **`Neighbour`**, **`Clash`** and **`Inside`** declare no field. Each is a relation between two subjects, concluded by the rules of §3.43 and never written: `Within.r.p` for a region `r` and a region `p` it lies within, `Neighbour.x.y` and `Clash.x.y` for two regions, and `Inside.p.b` for a place `p` and a box `b`. They are declared so that reading one that does not stand answers empty. ### 3.43 `geography` — standing rules Each holds continuously, as in §3.17. A rule over several subjects binds them as the cell names them: a region as `r`, `x` or `y` and, above it, as `p` and `q` along a line of containment, or as `o` for the region that holds the others; a border as `b`; and a place as `p` and a box as `b`. | Rule | Over | Concludes | While | |---|---|---|---| | `within_parent` | `Region` | `Within` | the region's `parent` names a region. Concludes `Within.r.p` | | `within_further` | `Region` | `Within` | `Within.r.p` holds and the region `p` has a `parent` that names a region `q`. Concludes `Within.r.q` | | `holds` | `Region` | `holds` | `Within.r.o` holds for some regions `r`; the region `o` takes the number of distinct such regions | | `neighbour_ab` | `Border`, `Region` | `Neighbour` | the border's `a` names a region `x` and its `b` names a region `y`. Concludes `Neighbour.x.y` | | `neighbour_ba` | `Border`, `Region` | `Neighbour` | the same border, the other way. Concludes `Neighbour.y.x` | | `clash` | `Region` | `Clash` | `Neighbour.x.y` holds and the two regions have the same `colour`. Concludes `Clash.x.y` | | `inside` | `Place`, `Box` | `Inside` | the box's `west` is not east of its `east`, the place's `lat` is from the box's `south` to its `north`, and its `lon` is from the box's `west` to its `east`, the edges included | | `inside_before_antimeridian` | `Place`, `Box` | `Inside` | the box's `west` lies east of its `east`, the place's `lat` is from the box's `south` to its `north`, and its `lon` is at or east of the box's `west` | | `inside_after_antimeridian` | `Place`, `Box` | `Inside` | the box's `west` lies east of its `east`, the place's `lat` is from the box's `south` to its `north`, and its `lon` is at or west of the box's `east` | `geography` declares no standing constraint. Six notes that are contract rather than commentary: - **A region is a name `region()` has recorded.** `Within` runs only between regions that have a field written, so a `parent` that names a region nobody recorded concludes nothing until that region is recorded, and the readers of §3.44 list only regions recorded with a `level`. Record the outermost region too, with `""` for its parent. - **A move withdraws what it no longer supports.** Writing a region under the same source with another `parent` replaces the first, and `Within` and `holds` follow: the region leaves every region above its old parent. Passing `""` for a parent writes nothing, so it does not withdraw a parent an earlier call recorded; write the parent you mean. - **A box across the antimeridian is the two ranges it covers.** Its longitudes are compared as written, with no wrapping: a place is within when its `lon` is at or east of the box's `west`, or at or west of its `east`. - **A colour clash is between neighbours.** `Clash.x.y` holds for each border whose two regions have the same `colour`, both ways round. A region with no `colour` clashes with nothing. - **`holds` counts regions, not levels.** It is the number of regions within a region at any depth, whatever their `level`. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. A region two sources place in two parents lies within both of them, and everything above each; a place two sources put at two latitudes lies in every box either latitude falls in, and a region reached by two paths is held once. `unsettled()` names what the sources disagree about. ### 3.44 `geography` — queries Called by name after `import geography`. No query refuses because sources disagree: a reader answers every value in force, and `unsettled()` names what is in disagreement. The five writers write under the sources `"regions"`, `"map"` and `"places"`, so writing the same fact again is a correction and a write under another source is a disagreement. The calculations write nothing and return unrounded numbers. Angles that are arguments or results are in degrees, except where a script says radians; distances are in metres. | Query | Answers | |---|---| | `region(name, parent, level)` | Nothing. Writes the region `name`'s `level` under the source `"regions"`, and its `parent` only when it is not `""`. | | `border(a, b)` | Nothing. Writes a border named `_` between the regions `a` and `b`, its `a` and `b` under the source `"map"`. | | `colour(name, c)` | Nothing. Writes the region `name`'s `colour` under the source `"map"`. | | `place(name, lat, lon)` | Nothing. Writes the place `name`'s `lat` and `lon` under the source `"places"`. | | `box(name, south, north, west, east)` | Nothing. Writes the box `name`'s four edges under the source `"places"`. | | `paint(palette)` | Nothing. Writes, under the source `"map"`, the colour that `dsatur()` chooses for each region, colour number k as `palette[k]`. The palette needs as many colours as the map does; a shorter one is refused part way, after the colours it reached are written. | | `regions()` | Every region recorded with a `level`, sorted. | | `within(name)` | Every region the region `name` lies within, at any depth, sorted. Empty for a name that is not a recorded region. | | `regions_in(name, at)` | Every region within the region `name` whose `level` is `at`, or at any level when `at` is `""`, sorted. | | `neighbours(name)` | Every recorded region that shares a border with the region `name`, sorted. | | `clashes()` | Every pair of neighbours the map gives one colour, as `"x y"` with `x` before `y`, sorted. | | `places_in(name)` | Every place within the box `name`, edges included, sorted. | | `unsettled()` | Every region, border, place and box for which a field it writes among `parent`, `level`, `colour`, `a`, `b`, `lat`, `lon`, `south`, `north`, `west` and `east` holds two different values in force, as its kind in lower case, its name and the field, `place oslo lat`, sorted. | | `dsatur()` | A colour number, from 0, for every region named in a border, as a dictionary from region to number, chosen by Brélaz's DSatur: each step colours the region whose neighbours already show the most colours, the most neighbours breaking a tie and then the name, with the lowest number none of them shows. No two neighbours get one number. Not guaranteed to use the fewest. Writes nothing. | | `mean_radius()` | The Earth's mean radius, 6371008.8 metres, which is `(2a + b) / 3` of the WGS84 ellipsoid as the IUGG rounds it. | | `central_angle(lat1, lon1, lat2, lon2)` | The angle between two points seen from the sphere's centre, in radians, by the haversine formula, each coordinate taken modulo 360 degrees by `math.fmod` first. Where the haversine falls below the smallest normal real, its root is the `math.hypot` of the roots of its two terms. | | `haversine(lat1, lon1, lat2, lon2)` | The great-circle distance between two points on the sphere of `mean_radius()`, in metres. | | `bearing(lat1, lon1, lat2, lon2)` | The initial bearing of the great circle from the first point to the second, clockwise from north, from 0 to 360, each coordinate taken modulo 360 degrees by `math.fmod` first. 0.0 for two points that coincide. | | `destination(lat, lon, heading, distance)` | The point reached by setting out from a point on a bearing `heading` and keeping to the great circle for `distance` metres on the sphere: a list `[lat, lon]`, `lon` from -180 to 180. Each angle is taken modulo 360 degrees by `math.fmod` first. | | `spherical_excess(lat1, lon1, lat2, lon2, lat3, lon3)` | The spherical excess of the triangle with the three points as corners, in radians, by L'Huilier's theorem from its sides: the amount by which its angles sum past π. 0.0 when the three points lie on one great circle or coincide. Where the product of the four tangents L'Huilier multiplies is not a normal real, its root is taken on the mantissas and exponents `math.frexp` gives. | | `triangle_area(lat1, lon1, lat2, lon2, lat3, lon3)` | The area of that triangle on the sphere of `mean_radius()`, in square metres: the excess times the radius squared. | | `mercator(lat)` | The Mercator projection's northing for a latitude, in units of the sphere's radius: `ln(tan(45° + φ/2))`. Defined strictly between -90 and 90. | | `mercator_inverse(y)` | The latitude, in degrees, that a Mercator northing `y` comes from. | | `mercator_scale(lat)` | How much the projection enlarges a short distance at a latitude, `1 / cos φ`. | | `dms(x)` | An angle as a list `[degrees, minutes, seconds]`, whole degrees and whole minutes and the remainder as seconds, each carrying the angle's sign. | | `vincenty_inverse(lat1, lon1, lat2, lon2)` | The distance between two points on the WGS84 ellipsoid, by Vincenty's iteration of 1975: a list `[metres, the azimuth from the first point to the second, the azimuth from the second point back to the first, rounds]`, azimuths in degrees from 0 to 360. Two points that coincide answer `[0.0, 0.0, 0.0, 1.0]`. Near antipodal points the iteration need not converge: after 200 rounds it stops and answers `[0.0, 0.0, 0.0, -1.0]`. Each coordinate is taken modulo 360 degrees by `math.fmod` first, and where the square of the sine of the arc falls below the smallest normal real, the sine is a `math.hypot`. | | `vincenty_direct(lat1, lon1, az1, s)` | The point a distance `s` metres along the geodesic from a point at azimuth `az1` degrees, on the WGS84 ellipsoid, by Vincenty's direct method: a list `[lat, lon, the azimuth from there back to the start]`, `lon` from -180 to 180. The latitude and the azimuth are taken modulo 360 degrees by `math.fmod` first. | The ellipsoid's constants are those of WGS84: semi-major axis 6378137.0 metres and flattening `1 / 298.257223563`. ### 3.45 `mathematics` — declared fields The writing scripts of §3.48 write `Number` and `Candidate` under the source `"numbers"`, `Operation`, `Element`, `Cell` and `Triple` under the source `"table"`, and `Triangle` under the source `"figures"`, and you may write the same fields yourself. A **number** is a whole number from 1 up, named `n` followed by its value, so the number 28 is `n28`. A **candidate** is one number tried as a divisor of another, from 1 to half of it, since no proper divisor is larger. An **operation** is a binary operation on a finite set, given as its table: its **elements** are named by labels you choose, and its **cells** are the products of the table, `a · b = c`. A **triple** is three elements taken in order, `x`, `y` and `z`, the case that associativity quantifies over. A **triangle** is three sides in whole units. An element is named `__` and a triple `___`, and a label that holds an underscore makes those names ambiguous to the readers of §3.48. **`Number`** | Field | Class | Notes | |---|---|---| | `n` | `int` | The value, at least 1. | | `divisor_count` | `int` | Concluded by a rule (§3.47): how many of its candidates divide it. Never written. | | `claims` | `int` | Concluded by a rule (§3.47): how many claims of `k` those candidates hold. Never written. | | `disputed` | `bool` | Concluded by a rule (§3.47): `claims` is greater than `divisor_count`. Never written. | | `divisor_sum` | `int` | Concluded by a rule (§3.47). The sum of its proper divisors, each divisor but itself. Never written; absent for 1, which has none. | | `prime` | `bool` | Concluded by a rule (§3.47). Never written. | | `composite` | `bool` | Concluded by a rule (§3.47). Never written. | | `perfect` | `bool` | Concluded by a rule (§3.47). Never written. | | `abundant` | `bool` | Concluded by a rule (§3.47). Never written. | | `deficient` | `bool` | Concluded by a rule (§3.47). Never written. | **`Candidate`** | Field | Class | Notes | |---|---|---| | `of` | `string` | The `Number` the candidate is tried against. | | `n` | `int` | That number's value. | | `k` | `int` | The candidate divisor, from 1 to half of `n`. | | `divides` | `bool` | Concluded by a rule (§3.47). Never written. | **`Operation`** | Field | Class | Notes | |---|---|---| | `order` | `int` | How many elements the set has. | | `identity` | `string` | Concluded by a rule (§3.47). The label of the element that leaves every element as it is from either side. Never written; absent where there is none. | | `closed` | `bool` | Concluded by a rule (§3.47). Never written. | | `commutative` | `bool` | Concluded by a rule (§3.47). Never written. | | `associative` | `bool` | Concluded by a rule (§3.47). Never written. | | `group` | `bool` | Concluded by a rule (§3.47). Never written. | | `abelian` | `bool` | Concluded by a rule (§3.47). Never written. | **`Element`** | Field | Class | Notes | |---|---|---| | `op` | `string` | The `Operation` whose set the element belongs to. | | `el` | `string` | The element's label. | | `identity` | `bool` | Concluded by a rule (§3.47). Never written. | | `invertible` | `bool` | Concluded by a rule (§3.47). Never written. | | `noninvertible` | `bool` | Concluded by a rule (§3.47). Never written. | **`Cell`** | Field | Class | Notes | |---|---|---| | `op` | `string` | The `Operation` the cell belongs to. | | `a` | `string` | The label of the left factor. | | `b` | `string` | The label of the right factor. | | `c` | `string` | The label of the product `a · b`, as the table gives it. A label that is not an element's is an error of the table, which `outside` marks. | | `left` | `string` | The name of the `Element` that is the left factor. | | `right` | `string` | The name of the `Element` that is the right factor. | | `outside` | `bool` | Concluded by a rule (§3.47). Never written. | | `noncommuting` | `bool` | Concluded by a rule (§3.47). Never written. | | `to_identity` | `bool` | Concluded by a rule (§3.47). Never written. | | `twosided` | `bool` | Concluded by a rule (§3.47). Never written. | **`Triple`** | Field | Class | Notes | |---|---|---| | `op` | `string` | The `Operation` the triple belongs to. | | `x` | `string` | The label of the first element. | | `z` | `string` | The label of the third element. The second is named by `xy` and `yz`. | | `xy` | `string` | The name of the `Cell` `x · y`. | | `yz` | `string` | The name of the `Cell` `y · z`. | | `left` | `string` | Concluded by a rule (§3.47). The label of `(x · y) · z`. Never written. | | `right` | `string` | Concluded by a rule (§3.47). The label of `x · (y · z)`. Never written. | | `breaks` | `bool` | Concluded by a rule (§3.47). Never written. | **`Triangle`** | Field | Class | Notes | |---|---|---| | `a` | `int` | The shortest side, in whole units. | | `b` | `int` | The middle side. | | `c` | `int` | The longest side. The rules read `c` as the longest, so write the three in order. | | `acute` | `bool` | Concluded by a rule (§3.47). Never written. | | `right` | `bool` | Concluded by a rule (§3.47). Never written. | | `obtuse` | `bool` | Concluded by a rule (§3.47). Never written. | | `equilateral` | `bool` | Concluded by a rule (§3.47). Never written. | | `isosceles` | `bool` | Concluded by a rule (§3.47). Never written. | | `scalene` | `bool` | Concluded by a rule (§3.47). Never written. | A triangle has six further fields that are computed rather than written or concluded, and `Candidate` one: §3.46 defines them. ### 3.46 `mathematics` — derived fields | Field | Definition | |---|---| | `Candidate.remainder` | `n % k` | | `Triangle.perimeter` | `a + b + c` | | `Triangle.gap` | `a * a + b * b - c * c` | | `Triangle.slack` | `a + b - c` | | `Triangle.heron` | `(a + b + c) * (b + c - a) * (a + c - b) * (a + b - c)` | | `Triangle.valid` | `slack > 0` | `remainder` is what is left when the candidate `k` divides `n`. `perimeter` is the sum of the three sides. `gap` is a² + b² − c², whose sign is the sign of the cosine of the angle facing the longest side: positive for an acute angle, 0 for a right one and negative for an obtuse one. `slack` is a + b − c, which is positive exactly when three lengths close up into a triangle, and `valid` says so; a degenerate triangle, whose slack is 0, is not valid. `heron` is sixteen times the square of the triangle's area, a whole number for whole sides. Each is absent until the fields it reads are present, and `heron` is also absent when the product passes 9,223,372,036,854,775,807, as for three equal sides of 42,000 units. All six are integers, except `valid`, which is a `bool`. ### 3.47 `mathematics` — standing rules Each holds continuously, as in §3.17. A rule over a `Number` binds it as `x` and a `Candidate` as `d`; over an `Operation` as `t` or `o`, an `Element` as `e` or `u`, a `Cell` as `c`, `p` or `q`, a `Triple` as `t` and a `Triangle` as `t`. | Rule | Over | Concludes | While | |---|---|---|---| | `divides` | `Candidate` | `divides` | the candidate's `remainder` is 0; concludes `True` | | `number_claims` | `Number`, `Candidate` | `claims` | the candidate's `of` names the number, it `divides` and its `k > -1000000000000000000`; the number takes the number of claims of `k` those candidates hold | | `number_divisors` | `Number`, `Candidate` | `divisor_count` | the candidate's `of` names the number, it `divides` and its `k > -1000000000000000000`; the number takes the number of distinct such candidates | | `number_disputed` | `Number` | `disputed` | the number's `claims` is greater than its `divisor_count`; concludes `True` | | `divisor_sum` | `Number`, `Candidate` | `divisor_sum` | the candidate's `of` names the number, it `divides` and the number has no `disputed`; the number takes the sum of those candidates' `k` | | `composite` | `Number`, `Candidate` | `composite` | the candidate's `of` names the number, its `k > 1` and it `divides`; concludes `True` | | `prime` | `Number` | `prime` | the number's `n > 1` and no candidate of it with `k > 1` `divides`; concludes `True` | | `perfect` | `Number` | `perfect` | the number's `divisor_sum` equals its `n`; concludes `True` | | `abundant` | `Number` | `abundant` | the number's `divisor_sum` exceeds its `n`; concludes `True` | | `deficient` | `Number` | `deficient` | the number's `divisor_sum` falls short of its `n`; concludes `True` | | `one_is_deficient` | `Number` | `deficient` | the number's `n` is 1, which has no `divisor_sum`; concludes `True` | | `identity` | `Element` | `identity` | no cell whose `left` names the element has a `c` other than its `b`, and no cell whose `right` names it has a `c` other than its `a`; concludes `True` | | `operation_identity` | `Operation`, `Element` | `identity` | the element's `op` names the operation and it is `identity`; the operation takes the element's `el` | | `outside` | `Cell` | `outside` | no element of the cell's operation has an `el` equal to the cell's `c`; concludes `True` | | `closed` | `Operation` | `closed` | no cell of the operation is `outside`; concludes `True` | | `noncommuting` | `Cell` | `noncommuting` | a cell of the same operation has its `a` equal to this cell's `b`, its `b` equal to this cell's `a` and a different `c`; concludes `True` | | `commutative` | `Operation` | `commutative` | no cell of the operation is `noncommuting`; concludes `True` | | `bracket_left` | `Triple`, `Cell` | `left` | the triple's `xy` names a cell `p`, and a cell `q` of the same operation has its `a` equal to the `c` of `p` and its `b` equal to the triple's `z`; the triple takes the `c` of `q` | | `bracket_right` | `Triple`, `Cell` | `right` | the triple's `yz` names a cell `r`, and a cell `s` of the same operation has its `a` equal to the triple's `x` and its `b` equal to the `c` of `r`; the triple takes the `c` of `s` | | `breaks` | `Triple` | `breaks` | the triple's `left` differs from its `right`; concludes `True` | | `associative` | `Operation` | `associative` | no triple of the operation `breaks`; concludes `True` | | `to_identity` | `Cell`, `Operation` | `to_identity` | the cell's `op` names the operation and its `c` equals the operation's `identity`; concludes `True` | | `twosided` | `Cell` | `twosided` | a cell of the same operation has its `a` equal to this cell's `b` and its `b` equal to this cell's `a`, and both cells are `to_identity`; concludes `True` | | `invertible` | `Element`, `Cell` | `invertible` | a cell whose `left` names the element is `twosided`; concludes `True` | | `noninvertible` | `Element` | `noninvertible` | another element `u` of the same operation is the `identity`, and no cell whose `left` names the element is `twosided`; concludes `True` | | `group` | `Operation`, `Element` | `group` | an element of the operation is the `identity`, the operation is `closed` and `associative`, and no element of it is `noninvertible`; concludes `True` | | `abelian` | `Operation` | `abelian` | the operation is a `group` and `commutative`; concludes `True` | | `acute` | `Triangle` | `acute` | the triangle is `valid` and its `gap > 0`; concludes `True` | | `right` | `Triangle` | `right` | the triangle is `valid` and its `gap` is 0; concludes `True` | | `obtuse` | `Triangle` | `obtuse` | the triangle is `valid` and its `gap < 0`; concludes `True` | | `equilateral` | `Triangle` | `equilateral` | the triangle is `valid` and `a`, `b` and `c` are equal; concludes `True` | | `isosceles_base` | `Triangle` | `isosceles` | the triangle is `valid` and its `a` equals its `b`; concludes `True` | | `isosceles_top` | `Triangle` | `isosceles` | the triangle is `valid` and its `b` equals its `c`; concludes `True` | | `scalene` | `Triangle` | `scalene` | the triangle is `valid`, its `a` is less than its `b` and its `b` is less than its `c`; concludes `True` | `mathematics` declares no standing constraint. Seven notes that are contract rather than commentary: - **A number is judged by the candidates written for it.** `prime` asks that no candidate above 1 divide the number, and the candidates are the facts you or `number()` wrote, from 1 to half of it. A number written with no candidate and above 1 is concluded `prime`, and has no `divisor_sum`. The number 1 is neither `prime` nor `composite`, has no `divisor_sum` and is `deficient`. Every number above 1 has a `divisor_sum`, which counts the divisor 1. - **A property is judged over the table given.** `closed`, `commutative` and `associative` hold when no cell or triple of the table breaks them, and each withdraws when a cell it rests on is rewritten. A triple whose bracket leaves the set has no result to compare and is not judged, so a table that is not `closed` can still be reported `associative`; `group` requires both. - **An inverse is two-sided and needs an identity.** `invertible` asks that some product of the element with another give the identity from both sides. `noninvertible` is concluded only where the operation has an `identity`: an operation with none has no element marked either way, and is not a `group`. - **A triangle is judged only when its sides close up.** `acute`, `right`, `obtuse` and the three by sides are concluded only for a `valid` triangle, one whose `slack` is positive. Three lengths that do not close up, or that lie flat, have no kind. `isosceles` includes the equilateral. - **The sides are read in order.** `gap` and `slack` take `c` as the longest side. `triangle()` writes the three sorted; sides you write yourself must already be. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. A cell given two products breaks commutativity or associativity if either one does, and a number given two values is classified by both. A divisor sum reads every value of a `k`, so a candidate whose `k` a second source writes, even the same `k`, would be added twice; `divisor_count` and `claims` count the divisors and their claims over the one binding the sum reads, and while the claims are more the number is `disputed` and has no `divisor_sum`, `perfect`, `abundant` or `deficient`. A candidate whose `of` holds two values is added to each number it names, each divisor sum being one source's. - **No rule reads the mathematics.** Every rule compares or adds whole numbers, or compares labels. That a table is the operation it was meant to be, or that a set of labels is the set the operation acts on, is not asked. ### 3.48 `mathematics` — queries Called by name after `import mathematics`. No query refuses because sources disagree: a reader answers every value in force, and `unsettled()` names what is in disagreement. The writers and readers of the first two groups are the interface to the facts; the rest compute values from their arguments and write nothing. An `int` is 64 bits, and a result past 9,223,372,036,854,775,807 refuses as an overflow rather than wrapping. | Query | Answers | |---|---| | `number(v)` | Nothing. Writes the number named `n` followed by `v`, with its value, and a candidate for each `k` from 1 to `v // 2`, each named for the number, `_` and `k`, with its `of`, `n` and `k`, under the source `"numbers"`. | | `numbers(lo, hi)` | Nothing. Writes `number(v)` for every `v` from `lo` to `hi`. The candidates grow as the square of `hi`, so it is for numbers in the hundreds. | | `operation(name, elements, table)` | Nothing. Writes the operation `name` with its `order`, an element for each label of `elements`, a cell for each pair, `table[i][j]` being `elements[i] · elements[j]`, and a triple for each three elements in order, under the source `"table"`. It writes n² cells and n³ triples for n elements, so it is for tables of a few elements. | | `cell(name, a, b, c)` | Nothing. Writes the product of the cell `a · b` of operation `name` as `c`, under the source `"table"`. Writing it again corrects it. | | `triangle(name, x, y, z)` | Nothing. Writes the triangle `name` with its three sides sorted into `a`, `b` and `c`, under the source `"figures"`. | | `numbers_that_are(property)` | The values of every number that is `"prime"`, `"composite"`, `"perfect"`, `"abundant"`, `"deficient"` or `"disputed"`, each once, sorted. Any other `property` reads as `"deficient"`. | | `divisors(v)` | The proper divisors of the number `v`, sorted: the candidates the rules found to divide it. Empty for a number not written. | | `properties(name)` | The properties that hold of operation `name`, from `"closed"`, `"commutative"`, `"associative"`, `"group"` and `"abelian"`, in that order. | | `identity_of(name)` | The label of the identity of operation `name`, `""` where it has none. | | `noncommuting_pairs(name)` | Every pair `"a b"` of operation `name` whose products `a · b` and `b · a` differ, sorted. | | `nonassociative_triples(name)` | Every three elements `"x y z"` of operation `name` for which `(x · y) · z` and `x · (y · z)` differ, sorted. | | `without_inverse(name)` | Every element of operation `name`, which must have an identity, that has no two-sided inverse, sorted. | | `kinds(name)` | What triangle `name` is, from `"acute"`, `"right"`, `"obtuse"`, `"equilateral"`, `"isosceles"` and `"scalene"`, in that order; empty where its sides make no triangle. | | `area(name)` | The area of triangle `name` by Heron's formula, `math.sqrt(heron) / 4`; 0.0 where its sides make no triangle. It refuses for a triangle not written, and for one whose `heron` is absent (§3.46). | | `unsettled()` | Each number, candidate, cell and triangle side that holds two different values in force for a field you write: a number's `n`, a candidate's `k`, a cell's `c`, or a triangle's `a`, `b` or `c`. Given as `number x n`, `candidate x k`, `cell x c`, or `triangle x a`, `triangle x b` or `triangle x c`, sorted. | | `gcd(a, b)` | The greatest common divisor of `a` and `b` by Euclid's algorithm, taking their absolute values; no pair of 64-bit numbers needs more than 93 steps. | | `lcm(a, b)` | The least common multiple, `abs(a) // gcd(a, b) * abs(b)`; 0 when either is 0. | | `extended_gcd(a, b)` | A list `[g, x, y]` with `a * x + b * y = g`, the greatest common divisor, by the extended Euclidean algorithm, for `a` and `b` at least 0. | | `modinv(a, m)` | The inverse of `a` modulo `m`, from 1 to `m - 1`, or 0 where `a` and `m` share a factor and there is none. `m` is at least 2. | | `modpow(b, e, m)` | `b` to the power `e` modulo `m` by repeated squaring, for `e` at least 0 and `m` from 1 to 3,037,000,499, so that the product of two remainders fits in an `int`. | | `isqrt(n)` | The largest whole number whose square is at most `n`, for `n` at least 0, by Newton's method in whole numbers. | | `is_prime(n)` | Whether `n` is prime, by the Miller–Rabin test to the bases 2, 3, 5 and 7, which decide every `n` below 3,215,031,751. `n` is at most 3,037,000,499, the bound of `modpow`. | | `factorize(n)` | The prime factors of `n`, at least 2, smallest first and each as often as it divides `n`, by trial division. Its steps grow as the square root of `n`'s second largest prime factor. | | `totient(n)` | Euler's totient: how many of 1 to `n` share no factor with `n`. | | `primes(n)` | Every prime up to `n`, by the sieve of Eratosthenes. The sieve holds `n` values, so `n` is for the thousands. | | `factorial(n)` | `n!`, for `n` from 0 to 20; 21! refuses. | | `binomial(n, k)` | `n` choose `k`, exactly, 0 for `k` below 0 or above `n`. Only a coefficient past 2⁶³ − 1 refuses. | | `fibonacci(n)` | The `n`-th Fibonacci number, F(0) = 0 and F(1) = 1, for `n` from 0 to 92; F(93) refuses. | | `collatz(n)` | How many steps `n` takes to reach 1, halving an even number and taking 3n + 1 for an odd one; -1 if it has not reached 1 in 1,024 steps. | | `continued_fraction(p, q)` | The terms `[a0; a1, a2, …]` of the fraction `p / q`, as a list, for `q` at least 1, by Euclid's algorithm. | | `convergents(terms)` | The convergents `[p, q]` of a continued fraction, one for each term, as a list of pairs. `terms` has at least one term. | | `sqrt_period(n)` | The continued fraction of the square root of `n`: `[a0, a1, …, ar]`, where `a1` to `ar` repeat forever and `ar` is `2 * a0`. `[a0]` alone for a square. | | `pell(n)` | The smallest `x` and `y` at least 1 with `x * x - n * y * y = 1`, as `[x, y]`, for `n` not a square. It refuses only where `x` itself passes 2⁶³ − 1. | | `root(x, k)` | The `k`-th root of `x` by Newton's method from above, stopped when a step no longer brings it down, for `x` above 0 and `k` at least 1. | | `trapezoid(ys, h)` | The integral of a function sampled at equal steps `h` by the trapezoidal rule. Where the sum, or the sum times `h`, passes the largest real while every sample and `h` are reals, it is summed again with each sample scaled by a power of two and the integral scaled back. | | `simpson(ys, h)` | The integral of a function sampled at equal steps `h` by Simpson's rule, over an odd number of samples. Where the sum, or the sum times `h`, passes the largest real, it is taken again as `trapezoid` does. | | `machin()` | π by Machin's formula of 1706, `4 * (4 * math.atan(1 / 5) - math.atan(1 / 239))`. | | `determinant(m)` | The determinant of a square matrix by Gaussian elimination with partial pivoting: at each column, the row with the largest entry. 0.0 where a pivot is 0. The product of the pivots is kept as a mantissa and a power of two, as `math.frexp` gives them. Where an entry passes the largest real on the way, or a multiplier falls below the smallest normal real and loses the row it scales, while every entry is a real, it is taken again with each row scaled by a power of two that brings its largest entry near 1, and the powers added back. | | `solve(m, b)` | The `x` with `m · x = b`, by Gaussian elimination with partial pivoting and back substitution, as a list; `[]` where a pivot is 0, that is where `m` is singular. Where `x` passes the range of a real, or a pivot or a multiplier falls below the smallest normal real, while `m` and `b` are reals, it is solved again with each row of `m` scaled by a power of two that brings its largest entry near 1, and `b` by another, and `x` scaled back. | | `hilbert(n)` | The `n` by `n` Hilbert matrix, `1 / (i + j + 1)` for row `i` and column `j` from 0, whose determinant falls toward zero faster than elimination can follow. | ### 3.49 `statistics` — declared fields The writing scripts of §3.52 write `Stratum` under the source `"strata"`, `Screen` under `"screens"` and `Significance` under `"tests"`, and you may write the same fields yourself. A **study** is named by you. A **stratum** is one part of a study in which two arms, A and B, were each tried, and is named `_`, the study's name, an underscore and a name of its own. A **screen** is a screening test and a **significance** a test result, each named by you. `stratum()` also writes the `Study` it belongs to, giving its `label` the study's name, under the source `"strata"`. Rates and probabilities are numbers from 0 to 1. **`Stratum`** | Field | Class | Notes | |---|---|---| | `study` | `string` | The name of the `Study` the stratum is part of. | | `a_yes` | `int` | Successes among arm A's trials in the stratum. | | `a_n` | `int` | Arm A's trials in the stratum. | | `b_yes` | `int` | Successes among arm B's trials in the stratum. | | `b_n` | `int` | Arm B's trials in the stratum. | | `a_rate` | `real` | Computed from `a_yes` and `a_n` (§3.50). Never written. | | `b_rate` | `real` | Computed from `b_yes` and `b_n` (§3.50). Never written. | | `a_wins` | `bool` | Computed from the two rates (§3.50). Never written. | | `b_wins` | `bool` | Computed from the two rates (§3.50). Never written. | **`Study`** | Field | Class | Notes | |---|---|---| | `label` | `string` | The study's name. Written by `stratum()`. | | `a_yes_strata` | `int` | Concluded by a rule (§3.51): how many of its strata hold a `a_yes`. Never written. | | `a_n_strata` | `int` | Concluded by a rule (§3.51): how many of its strata hold a `a_n`. Never written. | | `b_yes_strata` | `int` | Concluded by a rule (§3.51): how many of its strata hold a `b_yes`. Never written. | | `b_n_strata` | `int` | Concluded by a rule (§3.51): how many of its strata hold a `b_n`. Never written. | | `a_yes_claims` | `int` | Concluded by a rule (§3.51): how many claims of `a_yes` those strata hold. Never written. | | `a_n_claims` | `int` | Concluded by a rule (§3.51): how many claims of `a_n` those strata hold. Never written. | | `b_yes_claims` | `int` | Concluded by a rule (§3.51): how many claims of `b_yes` those strata hold. Never written. | | `b_n_claims` | `int` | Concluded by a rule (§3.51): how many claims of `b_n` those strata hold. Never written. | | `a_yes_disputed` | `bool` | Concluded by a rule (§3.51): `a_yes_claims` is greater than `a_yes_strata`. Never written. | | `a_n_disputed` | `bool` | Concluded by a rule (§3.51): `a_n_claims` is greater than `a_n_strata`. Never written. | | `b_yes_disputed` | `bool` | Concluded by a rule (§3.51): `b_yes_claims` is greater than `b_yes_strata`. Never written. | | `b_n_disputed` | `bool` | Concluded by a rule (§3.51): `b_n_claims` is greater than `b_n_strata`. Never written. | | `a_yes` | `int` | Concluded by a rule (§3.51): the sum of its strata's `a_yes`. Never written. | | `a_n` | `int` | Concluded by a rule (§3.51): the sum of its strata's `a_n`. Never written. | | `b_yes` | `int` | Concluded by a rule (§3.51): the sum of its strata's `b_yes`. Never written. | | `b_n` | `int` | Concluded by a rule (§3.51): the sum of its strata's `b_n`. Never written. | | `a_rate` | `real` | Computed from the pooled counts (§3.50). Never written. | | `b_rate` | `real` | Computed from the pooled counts (§3.50). Never written. | | `pooled_a_ahead` | `bool` | Computed from the pooled rates (§3.50). Never written. | | `pooled_b_ahead` | `bool` | Computed from the pooled rates (§3.50). Never written. | | `paradox` | `bool` | Concluded by a rule (§3.51). Never written. | **`Screen`** | Field | Class | Notes | |---|---|---| | `prevalence` | `real` | How common the condition is among those screened. | | `sensitivity` | `real` | The chance a positive result is given to someone who has the condition. | | `specificity` | `real` | The chance a negative result is given to someone who does not. | | `ppv` | `real` | Computed (§3.50). The chance that a positive result is right. Never written. | | `npv` | `real` | Computed (§3.50). The chance that a negative result is right. Never written. | | `mostly_false` | `bool` | Computed (§3.50). Never written. | **`Significance`** | Field | Class | Notes | |---|---|---| | `p` | `real` | The test's p-value. | | `alpha` | `real` | The level the result is held to. | | `significant` | `bool` | Computed from the two (§3.50). Never written. | ### 3.50 `statistics` — derived fields | Field | Definition | |---|---| | `Stratum.a_rate` | `a_yes / a_n` | | `Stratum.b_rate` | `b_yes / b_n` | | `Stratum.a_wins` | `a_rate > b_rate` | | `Stratum.b_wins` | `b_rate > a_rate` | | `Study.a_rate` | `a_yes / a_n` | | `Study.b_rate` | `b_yes / b_n` | | `Study.pooled_a_ahead` | `a_rate > b_rate` | | `Study.pooled_b_ahead` | `b_rate > a_rate` | | `Screen.ppv` | `prevalence * sensitivity / (prevalence * sensitivity + (1.0 - prevalence) * (1.0 - specificity))` | | `Screen.npv` | `(1.0 - prevalence) * specificity / ((1.0 - prevalence) * specificity + prevalence * (1.0 - sensitivity))` | | `Screen.mostly_false` | `ppv < 0.5` | | `Significance.significant` | `p < alpha` | A stratum's `a_rate` is the share of arm A's trials that succeeded, and `a_wins` says that arm A's rate is strictly higher than arm B's; two equal rates make neither arm win. The `Study` fields of the same names are the same quantities over the pooled counts. `ppv` and `npv` are Bayes' rule: `ppv` is the share of positive results that are right, `prevalence * sensitivity` over all the positive results there would be, and `npv` the share of negative results that are right. `mostly_false` is True where `ppv` is below one half, a positive result more likely wrong than right. `significant` is True where `p` is strictly below `alpha`; a `p` equal to `alpha` is not significant. Each is absent until the fields it reads are present. A rate whose trials are 0 is absent, and so are the `wins` of its stratum; `ppv` is absent where the prevalence is 0 and the specificity 1, since there are no positive results to value, and `npv` where the prevalence is 1 and the sensitivity 1. `a_yes`, `a_n`, `b_yes` and `b_n` are whole numbers, `significant`, `mostly_false` and the four `wins` and `ahead` fields are `bool`, and the rest are `real`. ### 3.51 `statistics` — standing rules Each holds continuously, as in §3.17. A rule over a study and a stratum binds them as `t` and `s`. | Rule | Over | Concludes | While | |---|---|---|---| | `study_a_yes_strata` | `Study`, `Stratum` | `a_yes_strata` | the stratum's `study` names the study and its `a_yes > -1000000000000000000`; the study takes the number of distinct such strata | | `study_a_n_strata` | `Study`, `Stratum` | `a_n_strata` | the stratum's `study` names the study and its `a_n > -1000000000000000000`; the study takes the number of distinct such strata | | `study_b_yes_strata` | `Study`, `Stratum` | `b_yes_strata` | the stratum's `study` names the study and its `b_yes > -1000000000000000000`; the study takes the number of distinct such strata | | `study_b_n_strata` | `Study`, `Stratum` | `b_n_strata` | the stratum's `study` names the study and its `b_n > -1000000000000000000`; the study takes the number of distinct such strata | | `study_a_yes_claims` | `Study`, `Stratum` | `a_yes_claims` | the stratum's `study` names the study and its `a_yes > -1000000000000000000`; the study takes the number of claims of `a_yes` those strata hold | | `study_a_n_claims` | `Study`, `Stratum` | `a_n_claims` | the stratum's `study` names the study and its `a_n > -1000000000000000000`; the study takes the number of claims of `a_n` those strata hold | | `study_b_yes_claims` | `Study`, `Stratum` | `b_yes_claims` | the stratum's `study` names the study and its `b_yes > -1000000000000000000`; the study takes the number of claims of `b_yes` those strata hold | | `study_b_n_claims` | `Study`, `Stratum` | `b_n_claims` | the stratum's `study` names the study and its `b_n > -1000000000000000000`; the study takes the number of claims of `b_n` those strata hold | | `study_a_yes_disputed` | `Study` | `a_yes_disputed` | the study's `a_yes_claims` is greater than its `a_yes_strata`; concludes `True` | | `study_a_n_disputed` | `Study` | `a_n_disputed` | the study's `a_n_claims` is greater than its `a_n_strata`; concludes `True` | | `study_b_yes_disputed` | `Study` | `b_yes_disputed` | the study's `b_yes_claims` is greater than its `b_yes_strata`; concludes `True` | | `study_b_n_disputed` | `Study` | `b_n_disputed` | the study's `b_n_claims` is greater than its `b_n_strata`; concludes `True` | | `fold_a_yes` | `Study`, `Stratum` | `a_yes` | the stratum's `study` names the study and the study has no `a_yes_disputed`; the study takes the sum of those strata's `a_yes` | | `fold_a_n` | `Study`, `Stratum` | `a_n` | the stratum's `study` names the study and the study has no `a_n_disputed`; the study takes the sum of those strata's `a_n` | | `fold_b_yes` | `Study`, `Stratum` | `b_yes` | the stratum's `study` names the study and the study has no `b_yes_disputed`; the study takes the sum of those strata's `b_yes` | | `fold_b_n` | `Study`, `Stratum` | `b_n` | the stratum's `study` names the study and the study has no `b_n_disputed`; the study takes the sum of those strata's `b_n` | | `paradox_b_ahead_in_the_pool` | `Study` | `paradox` | the study's `pooled_b_ahead` is True and no stratum of it has an `a_wins` other than True; concludes `True` | | `paradox_a_ahead_in_the_pool` | `Study` | `paradox` | the study's `pooled_a_ahead` is True and no stratum of it has a `b_wins` other than True; concludes `True` | `statistics` declares no standing constraint. Seven notes that are contract rather than commentary: - **A study is the sum of its strata.** The four folds add every stratum whose `study` names the study, so a stratum written again with other counts changes the pooled rates and withdraws every conclusion that rested on the old ones, a `paradox` among them. A study with no stratum written has no pooled counts. - **A pooled count is not drawn from a stratum bound to it twice.** A fold reads every value of the count it sums, so a stratum whose count a second source writes, even the same number, would be added twice. The `_strata` and `_claims` fields count the strata and their claims of each count over the one binding its fold reads, and while the claims are more, that count is disputed and not pooled, nor are the rate and the paradox that rest on it; a count both sources agree on is pooled. A stratum with no value of a count is in neither of its counts, so it hides no dispute. A stratum whose `study` holds two values counts in each it names, and each of those pools is one source's. - **A paradox is a reversal, and only that.** `paradox` is concluded for a study when one arm is strictly ahead in the pool and the other arm is strictly ahead in every stratum that has rates. It is not concluded for a study in which the two arms are level in some stratum, or in which the arm ahead in the pool is ahead in a stratum too, however far the pooled rate differs from the strata's. A stratum with no trials has no `wins` and does not stand in its way. - **The two figures a screen is judged by are not the test's.** `ppv` and `npv` depend on the `prevalence` as much as on the sensitivity and specificity, and the rules assume the people screened are drawn from the population the prevalence describes. A test of the same sensitivity and specificity can have a `ppv` of 0.08 at a prevalence of 0.01 and 0.69 at 0.2. - **A test result is a comparison.** `significant` compares the `p` you wrote with the `alpha` you wrote. Nothing computes the `p`, adjusts it for how many tests were run, or says whether the effect it measures matters. - **Probabilities are not checked.** A figure outside 0 to 1, or a count larger than its trials, is a fact like any other, and the conclusions that follow from it are as meaningful as the figure. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. A screen whose prevalence has two values can be `mostly_false` by one and not by the other. `unsettled()` names the fact. `pooled()` and `predictive_values()` are not readers of that kind: they read one value of each rate, and refuse where it is absent. ### 3.52 `statistics` — queries Called by name after `import statistics`. The first three write facts and answer nothing. The next six read what the rules concluded or what was written; none refuses because sources disagree, except `pooled()` and `predictive_values()` as §3.51 says, and `unsettled()` names what is in disagreement. The rest are value scripts that return a value and write nothing. Floats are IEEE doubles. A sample variance needs two values, a mean needs one, and a list that is too short is the caller's to avoid: the script refuses with a division by zero. Where a sum, square or product in a script's work would pass the largest real, or fall below the smallest normal one, while the value it serves would not, the work is done so that it stays in range, as each row says, and the value is had; the scaling by a power of two that most rows use changes no digit of a value whose work stays in range. | Query | Answers | |---|---| | `stratum(study, name, a_yes, a_n, b_yes, b_n)` | Nothing. Writes the `Stratum` named `_`'s `study` and four counts, and the `Study` named `study`'s `label`, under the source `"strata"`. | | `screen(name, prevalence, sensitivity, specificity)` | Nothing. Writes the `Screen` named `name`'s three figures under the source `"screens"`. | | `significance(name, p, alpha)` | Nothing. Writes the `Significance` named `name`'s `p` and `alpha` under the source `"tests"`. | | `paradoxes()` | The studies whose `paradox` holds, sorted. | | `pooled(study)` | `[A's pooled rate, B's pooled rate]` for the study `study`. It refuses a study with any of the four `_disputed` fields, and where either rate is absent, a study with no stratum or none with trials. | | `disputed_studies()` | The studies with any of the four `_disputed` fields, sorted. | | `predictive_values(name)` | `[ppv, npv]` for the screen `name`. It refuses where either is absent. | | `significant_tests()` | The tests whose `significant` is True, sorted. | | `unsettled()` | Each stratum count, screen figure and test figure that holds two different values in force for a fact you write, given as `stratum` and its name and the field, `screen` and `test` likewise, `stratum stones_small a_yes`, sorted. | | `scale_of(xs)` | The exponent `e` of `math.frexp` of the largest finite value of `xs` in size, which brings that value to between 1/2 and 1 when scaled by `2^-e`, where that value is at least `2^400` or under `2^-400` in size; 0 otherwise, and for a list with no finite value other than 0. | | `mean(xs)` | The arithmetic mean, summed from the first value to the last. Where that sum passes the largest real while every value is finite, the values are summed again each scaled by `2^-k`, `k` the exponent of `math.frexp` of their count, and the mean of those is scaled back. `xs` is not empty. | | `variance(xs)` | The sample variance, dividing by `n - 1`, by Welford's single pass over the values scaled by `2^-e`, `e` being `scale_of(xs)`, scaled back by `2^(2e)`. `xs` has at least two values. | | `std_dev(xs)` | The sample standard deviation: the square root of the variance of the values scaled by `2^-e`, `e` being `scale_of(xs)`, scaled back by `2^e`, so it is had wherever it is a real, even where the variance is not. | | `median(xs)` | The middle value of the sorted list, or the mean of the two middle ones, taken as the sum of their halves where their sum passes the largest real. | | `regression(xs, ys)` | `[intercept, slope, r]`: the least-squares line `y = intercept + slope * x` through the points and Pearson's correlation, computed over `xs` and `ys` each scaled by `2^-e` for its own `scale_of`, which does not change `r`, the intercept scaled back by the `ys`' power and the slope by the difference of the two. `xs` has at least two different values and `ys` as many values as `xs`. | | `welch_t(xs, ys)` | Welch's t statistic for two samples of unequal variance, computed over both samples scaled by `2^-e`, `e` being `scale_of(xs + ys)`, which does not change t. | | `z_score(x, mu, sigma)` | `(x - mu) / sigma`, taken as `(x/2 - mu/2) / sigma * 2` where `x - mu` passes the largest real. | | `normal_pdf(x, mu, sigma)` | The normal density at `x`. | | `normal_cdf(z)` | The standard normal distribution function, `0.5 * math.erfc(-z / sqrt(2))`, so the tails keep their digits: `z = -5` gives `2.8665157187919455e-07`. | | `normal_quantile(p)` | The `z` whose standard normal distribution function is `p`, for `p` strictly between 0 and 1, by 200 halvings of -40 to 40: exact to the last digit of `normal_cdf`. | | `stirling_error(n)` | `ln(n!) - ln(sqrt(2 pi n) (n/e)^n)`, the error of Stirling's formula, for `n` from 0: a table of its values to 15, and above it the series `(1/12 - (1/360 - (1/1260 - (1/1680 - 1/(1188 n^2)) / n^2) / n^2) / n^2) / n`, so no two large logarithms are subtracted. 0 at `n = 0`. It refuses a negative `n` with `ValueError`. | | `deviance(x, mean)` | `x ln(x / mean) + mean - x`, for a finite `x` from 0 and a finite `mean` above 0; `mean` at `x = 0`. Where `x` is within a factor of 3 of `mean`, where the plain form cancels, it is the series `d v + 2 x (v^3/3 + v^5/5 + ...)`, `d = x - mean` and `v = d / (x + mean)`, summed until a term changes nothing. It refuses other inputs with `ValueError`. | | `exact_product(a, b)` | `[a * b, the part of a * b its rounding lost]`, which add to `a * b` exactly, by Dekker's splitting, for factors and a product under `1e300` in size. It refuses others with `ValueError`. | | `binom_pmf(n, k, p)` | The probability of exactly `k` successes in `n` trials at chance `p`, for `n` from 0 and `p` from 0 to 1; 0 for a `k` outside 0 to `n`. It is `C(n, k) p^k q^(n - k) (1 + r/q)^(n - k)`, `q` being `1 - p` rounded and `r` the exact `(1 - q) - p` the rounding lost, the coefficient a running product over the smaller of `k` and `n - k`, wherever both powers, the coefficient and the probability are normal reals and the run is under 515 steps, `C(1030, 515)` being the first coefficient past the largest real. Elsewhere it is Loader's saddle-point form, `e^(stirling_error(n) - stirling_error(k) - stirling_error(n - k) - deviance(k, n p) - deviance(n - k, n q)) / sqrt(2 pi k (n - k) / n)`, its means `n p` and `n q` carried with what their rounding lost by `exact_product`, and `e^(n ln(1 - p))` or `e^(n ln p)` for a `k` of 0 or `n`. The product is within 17 units in its last digit to `n = 5000`, and Loader's form within `6 (25 + |ln P|)` of them. It refuses an `n` below 0 and a `p` outside 0 to 1 with `ValueError`. | | `binom_cdf(n, k, p)` | The probability of at most `k` successes in `n` trials, the sum of `binom_pmf` from no successes. It refuses as `binom_pmf` does. | | `poisson_pmf(k, lam)` | The probability of `k` events at a mean rate `lam`, a finite real from 0; 0 for a `k` below 0. It is the running product `e^-lam * lam/1 * ... * lam/k` wherever `e^-lam` and the probability are normal reals, which is for a rate to about 708, stopping where a step falls below the smallest normal real, which happens only past the most likely count. Elsewhere it is Loader's form, `e^(-stirling_error(k) - deviance(k, lam)) / sqrt(2 pi k)`. The product is within 50 units in its last digit, and Loader's form within `6 (25 + |ln P|)` of them. It refuses a rate below 0 or infinite with `ValueError`. | | `birthday(n)` | The chance that two of `n` people share a birthday, with 365 equally likely days: 23 people give `0.5072972343239855`. | | `bayes(prior, likelihood, false_likelihood)` | The posterior chance of a hypothesis with the given prior, after evidence that has `likelihood` under it and `false_likelihood` under its negation: `prior * likelihood / (prior * likelihood + (1 - prior) * false_likelihood)`, each factor taken as the mantissa and the exponent `math.frexp` gives, so a product too small or too large for a real still gives the posterior, and the posterior is the same to the last digit wherever the plain products are normal reals. It refuses a prior outside 0 to 1, and a likelihood below 0, with `ValueError`. | | `chi_square(obs, exp)` | Pearson's statistic, the sum of `(observed - expected)^2 / expected`, a term whose square passes the largest real or falls below the smallest normal one being taken as `d * (d / expected)`, `d` the difference. It refuses an observed count below 0, and an expected count of 0 or below, with `ValueError`. | | `chi_square_p_df1(x)` | The chance of a chi-square statistic of at least `x` with one degree of freedom, `math.erfc(sqrt(x / 2))`: 0.05 at `3.841458820694124`. | | `chi_square_p_df2(x)` | The same with two degrees of freedom, `exp(-x / 2)`. | | `lehmer_next(seed)` | The next state of the Lehmer generator, `48271 * x mod (2^31 - 1)`, for a seed from 1 to 2^31 - 2. A seed of 0 stays 0. DKE Python has no random module, and a run from the same seed repeats exactly. | | `lehmer_uniform(seed)` | A state as a number between 0 and 1, the state over `2^31 - 1`. | | `monte_carlo_pi(n, seed)` | Four times the share of `n` points, drawn uniformly in the unit square from the seed, that fall inside the quarter circle. It repeats for the same `n` and seed: 10,000 points from seed 1 give `3.1344`. The points count against the memory one run may hold, so `n` is for the thousands: a run on the service refuses at 20,000. | ### 3.53 `earthscience` — declared fields The writing scripts of §3.56 write `Station` under the source `"stations"`, `Storm` under `"storms"` and `Mineral` and `Pair` under `"minerals"`, and you may write the same fields yourself. A **station**, a **storm** and a **mineral** are each named by you. A **pair** is two minerals in order, named `__` with two underscores between the names, so a mineral's name holds no two underscores in a row. Temperatures are in degrees Celsius, rainfall in millimetres, wind in miles per hour and a hardness is a number on a scale on which a harder mineral scratches a softer one, the Mohs scale or a finer one. **`Station`** | Field | Class | Notes | |---|---|---| | `coldest` | `real` | The mean temperature of the coldest month. | | `warmest` | `real` | The mean temperature of the warmest month. | | `annual_temp` | `real` | The annual mean temperature. | | `rain` | `real` | The annual rainfall. | | `summer_share` | `real` | The fraction, from 0 to 1, of the rain that falls in the half of the year when the sun is high. | | `boundary` | `real` | The coldest-month temperature that divides the temperate group from the continental, 0.0 or -3.0 as the version of the system you follow has it. | | `addition` | `real` | Concluded by a rule (§3.55): 280, 140 or 0 by `summer_share`. Never written. | | `threshold` | `real` | Computed (§3.54). The rainfall under which the station is dry. Never written. | | `half` | `real` | Computed (§3.54). Half the threshold. Never written. | | `dry` | `bool` | Computed (§3.54). Never written. | | `polar` | `bool` | Computed (§3.54): group E. Never written. | | `tundra` | `bool` | Concluded by a rule (§3.55). Never written. | | `icecap` | `bool` | Concluded by a rule (§3.55). Never written. | | `arid` | `bool` | Concluded by a rule (§3.55): group B. Never written. | | `desert` | `bool` | Concluded by a rule (§3.55). Never written. | | `steppe` | `bool` | Concluded by a rule (§3.55). Never written. | | `tropical` | `bool` | Concluded by a rule (§3.55): group A. Never written. | | `temperate` | `bool` | Concluded by a rule (§3.55): group C. Never written. | | `continental` | `bool` | Concluded by a rule (§3.55): group D. Never written. | **`Storm`** | Field | Class | Notes | |---|---|---| | `wind_mph` | `int` | The sustained wind, in whole miles per hour. | | `hurricane` | `bool` | Concluded by a rule (§3.55). Never written. | | `category` | `int` | Concluded by a rule (§3.55): the Saffir-Simpson category, 1 to 5. Never written. | | `major` | `bool` | Concluded by a rule (§3.55). Never written. | **`Mineral`** | Field | Class | Notes | |---|---|---| | `hardness` | `real` | The mineral's hardness. | **`Pair`** | Field | Class | Notes | |---|---|---| | `first` | `string` | The name of the first mineral. | | `second` | `string` | The name of the second. | | `h_first` | `real` | The first mineral's hardness. | | `h_second` | `real` | The second mineral's hardness. | | `scratches` | `bool` | Computed from the two hardnesses (§3.54). Never written. | ### 3.54 `earthscience` — derived fields | Field | Definition | |---|---| | `Station.threshold` | `20.0 * annual_temp + addition` | | `Station.half` | `threshold / 2.0` | | `Station.dry` | `rain < threshold` | | `Station.polar` | `warmest < 10.0` | | `Pair.scratches` | `h_first > h_second` | `threshold` is the rainfall in millimetres under which a station is dry: twenty times the annual mean temperature plus `addition`, which is 280 where 70% or more of the rain falls in the high-sun half of the year, 140 where 30% to 70% does and 0 where under 30% does. `half` is half of it, the line between desert and steppe. `dry` is True where the station's `rain` is strictly below it, and `polar` where the warmest month is strictly under 10 degrees. `scratches` is True where the first mineral is strictly harder than the second; two minerals of equal hardness scratch neither. Each is absent until the fields it reads are present, and `threshold`, `half` and `dry` until the rule that concludes `addition` has. All are `real` except `dry`, `polar` and `scratches`, which are `bool`. ### 3.55 `earthscience` — standing rules Each holds continuously, as in §3.17. A rule over a station binds it as `c` and a rule over a storm as `s`. | Rule | Over | Concludes | While | |---|---|---|---| | `threshold_summer_rain` | `Station` | `addition` | the station's `summer_share >= 0.7`; the station takes 280.0 | | `threshold_even_rain` | `Station` | `addition` | the station's `summer_share >= 0.3` and its `summer_share < 0.7`; the station takes 140.0 | | `threshold_winter_rain` | `Station` | `addition` | the station's `summer_share < 0.3`; the station takes 0.0 | | `tundra` | `Station` | `tundra` | the station is `polar` and its `warmest >= 0.0`; concludes `True` | | `icecap` | `Station` | `icecap` | the station is `polar` and its `warmest < 0.0`; concludes `True` | | `arid` | `Station` | `arid` | the station is not `polar` and is `dry`; concludes `True` | | `desert` | `Station` | `desert` | the station is `arid` and its `rain` is under its `half`; concludes `True` | | `steppe` | `Station` | `steppe` | the station is `arid` and its `rain` is no less than its `half`; concludes `True` | | `tropical` | `Station` | `tropical` | the station is not `polar` and not `dry`, and its `coldest >= 18.0`; concludes `True` | | `temperate` | `Station` | `temperate` | the station is not `polar` and not `dry`, its `coldest < 18.0` and its `coldest` is above its `boundary`; concludes `True` | | `continental` | `Station` | `continental` | the station is not `polar` and not `dry`, and its `coldest` is no higher than its `boundary`; concludes `True` | | `hurricane` | `Storm` | `hurricane` | the storm's `wind_mph >= 74`; concludes `True` | | `category_one` | `Storm` | `category` | the storm's `wind_mph >= 74` and its `wind_mph <= 95`; the storm takes 1 | | `category_two` | `Storm` | `category` | the storm's `wind_mph >= 96` and its `wind_mph <= 110`; the storm takes 2 | | `category_three` | `Storm` | `category` | the storm's `wind_mph >= 111` and its `wind_mph <= 129`; the storm takes 3 | | `category_four` | `Storm` | `category` | the storm's `wind_mph >= 130` and its `wind_mph <= 156`; the storm takes 4 | | `category_five` | `Storm` | `category` | the storm's `wind_mph >= 157`; the storm takes 5 | | `major` | `Storm` | `major` | the storm's `wind_mph >= 111`; concludes `True` | `earthscience` declares no standing constraint. Seven notes that are contract rather than commentary: - **Every station is in exactly one of five groups.** The rules test the polar group first, then the arid, and only a station that is neither can be tropical, temperate or continental, so the five are `polar` (E), `arid` (B), `tropical` (A), `temperate` (C) and `continental` (D), once all the facts of the station are written. A station is polar when its warmest month is under 10 degrees, `tundra` where that month is 0 or more and `icecap` where it is under 0. It is arid when it is not polar and its `rain` is strictly below its `threshold`, `desert` under half of it and `steppe` from half of it up. - **The limits fall to one side.** A station whose warmest month is exactly 10 is not polar. One whose `rain` is exactly its `threshold` is not dry, and one whose `rain` is exactly its `half` is `steppe`. A station whose coldest month is exactly 18 is `tropical`; one whose coldest month is exactly the `boundary` is `continental`. - **The group is the first letter of a climate and no more.** The rules stop at the five groups and the two kinds of arid and polar climate; the finer climates within A, C and D, that depend on which season is dry or how warm the summer is, are not concluded. - **The version of the system is a fact you write.** `boundary` is 0.0 for the version of Köppen's system that puts the temperate group above 0 degrees and -3.0 for the one that puts it above -3. A station whose coldest month falls between the two is `continental` under the first and `temperate` under the second; the rules do not choose. - **The high-sun half of the year is yours to say.** `summer_share` is the fraction of the year's rain falling in the half of the year when the sun is high, the summer half of whichever hemisphere the station lies in. The rules do not read the hemisphere, and a station whose fraction is written for the wrong half is classified by it. - **A storm is judged by its wind alone.** `hurricane` is concluded at 74 miles per hour and the category by the five bands of the Saffir-Simpson scale, which cover every wind from 74 up and do not overlap. A wind under 74 has no `category`, and `category()` answers 0. `major` is a category of 3 or more. The rules read no pressure, surge, size or rainfall. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. A station whose `rain` has two values can be in two groups at once, `groups()` names both, and `climate()` reads the first of them in the order A, B, C, D, E. `unsettled()` names the fact. `dryness_threshold()` and `category()` read one value and refuse while two are in force, as a station with two annual means or a storm with two winds in two categories gives them. ### 3.56 `earthscience` — queries Called by name after `import earthscience`. The first three write facts and answer nothing. The next seven read what the rules concluded or what was written; none refuses because sources disagree, except `dryness_threshold()` and `category()` as §3.55 says: each answers by the rule its cell states, and `unsettled()` names what is in disagreement. The last thirteen are value scripts that return a value and write nothing. Temperatures are as each cell says, and each formula holds over a range it does not check. | Query | Answers | |---|---| | `station(name, coldest, warmest, annual_temp, rain, summer_share, boundary)` | Nothing. Writes the `Station` named `name`'s six figures under the source `"stations"`. | | `storm(name, wind_mph)` | Nothing. Writes the `Storm` named `name`'s `wind_mph` under the source `"storms"`. | | `minerals(names, hardness)` | Nothing. Writes each mineral of `names` with the hardness at the same position of `hardness`, and a `Pair` for each ordered two different minerals, under the source `"minerals"`. The pairs grow as the square of the number of minerals. | | `groups(name)` | The Köppen groups the station is in, from `"A"`, `"B"`, `"C"`, `"D"` and `"E"`, in that order; exactly one for a station whose facts are all written, and `[]` before they are. | | `climate(name)` | The station's group with its kind where it has one: `"A"`, `"BW"` (desert), `"BS"` (steppe), `"C"`, `"D"`, `"ET"` (tundra) or `"EF"` (ice cap), and `""` before the facts are written. | | `dryness_threshold(name)` | The rainfall in millimetres under which the station is dry, 0.0 before its facts are written. | | `category(name)` | The storm's Saffir-Simpson category, 0 below hurricane force. | | `scratches(first, second)` | Whether the first mineral is strictly harder than the second. | | `scratched_by(name)` | The minerals the named one scratches, sorted. | | `unsettled()` | Each station, storm and mineral figure that holds two different values in force for a field you write, given as `station`, `storm` or `mineral`, its name and the field, `station cairo rain`, sorted. | | `dew_point(t, rh)` | The dew point in degrees Celsius of air at `t` degrees and `rh` percent humidity, above 0 and up to 100, by the Magnus formula with `b = 17.625` and `c = 243.04`, fitted for -40 to 50 degrees. At 100% it gives the temperature, to within a rounding. Another humidity is refused with `ValueError`. Where `b t` passes the largest real, `b t / (c + t)` is taken as `b (t / (c + t))`. | | `heat_index(t, rh)` | The heat index in degrees Fahrenheit of air at `t` degrees and `rh` percent, by the Rothfusz regression, fitted for 80 degrees and 40% or more and within 1.3 degrees there; below that it gives a value that means little. | | `wind_chill(t, v)` | The wind chill in degrees Fahrenheit of air at `t` degrees and a wind of `v` miles per hour, defined for air at 50 degrees or colder and a wind above 3. | | `temperature_at(h)` | The temperature in kelvin at `h` metres in the standard atmosphere's troposphere: 288.15 at sea level and 6.5 cooler for each kilometre, to 11,000 metres. | | `pressure_at(h)` | The pressure in hectopascals at `h` metres in the standard atmosphere, `1013.25 * (1 - h / 44307.694) ** 5.2553`, holding in the troposphere, to about 11,000 metres, and for `h` under 44,307. | | `potential_temperature(t_kelvin, p_hpa)` | The temperature in kelvin the air would have if brought to 1000 hectopascals without exchanging heat, `t * (1000 / p) ** 0.286`; 0 for a temperature of 0. Where that is not a normal real while `t` and `p` are, it is `t e^(0.286 (ln 1000 - ln p))`. | | `coriolis(lat_deg)` | The Coriolis parameter in 1/s at a latitude in degrees, `2 * 7.2921e-5 * sin(latitude)`. | | `lcl_height(t, td)` | The height in metres at which rising air reaches saturation, `125 * (t - td)` for a temperature and a dew point in the same unit, accurate to about 1% in ordinary air. | | `radiometric_age(daughter_per_parent, half_life)` | The age of a sample, in the unit of the half-life, from the ratio of daughter atoms to parent atoms now: `half_life * math.log2(1 + ratio)`. It assumes no daughter at the start and none gained or lost since. | | `quake_energy_joules(m)` | The energy in joules radiated by an earthquake of surface-wave magnitude `m`, `10 ** (1.5 * m + 4.8)`. | | `magnitude_from_energy(joules)` | The magnitude whose energy is the given joules, `(math.log10(joules) - 4.8) / 1.5`; it inverts `quake_energy_joules` to within a rounding. | | `quake_ratio(m1, m2)` | How many times more energy a magnitude `m2` releases than `m1`, `10 ** (1.5 * (m2 - m1))`: one step is 31.6 times and two are 1000. | | `sp_distance_km(sp_seconds, vp, vs)` | The distance in kilometres to an earthquake from the interval in seconds between the arrival of its P wave and its S wave, for wave speeds `vp` and `vs` in kilometres per second: `sp_seconds * vp * vs / (vp - vs)`, the difference taken of halves where it passes the largest real, and where the distance is then not a normal real, worked on the mantissas and exponents `math.frexp` gives. | ### 3.57 `computing` — declared fields The writing script of §3.60 writes `Code`, `Word` and `Pair` under the source `"code"`, and you may write the same fields yourself. A **code** is a set of binary words, each a string of the characters 0 and 1, and is named by you; a code's name holds no underscore. A **word** is one of them, named `_`, the code's name, an underscore and the word. A **pair** is two words of a code in order, named `__`. **`Code`** | Field | Class | Notes | |---|---|---| | `label` | `string` | The code's name. Written by `code()`. | | `words` | `int` | Concluded by a rule (§3.59): how many of its words have a `weight`. Never written. | | `claims` | `int` | Concluded by a rule (§3.59): how many claims of `weight` they hold. Never written. | | `disputed` | `bool` | Concluded by a rule (§3.59): `claims` is greater than `words`. Never written. | | `kraft` | `real` | Concluded by a rule (§3.59): the sum of its words' `weight`, the Kraft sum. Never written. | | `complete` | `bool` | Concluded by a rule (§3.59). Never written. | | `oversubscribed` | `bool` | Computed from `kraft` (§3.58). Never written. | | `prefix_free` | `bool` | Concluded by a rule (§3.59). Never written. | **`Word`** | Field | Class | Notes | |---|---|---| | `code` | `string` | The name of the `Code` the word belongs to. | | `bits` | `string` | The word, a string of 0 and 1. | | `weight` | `real` | 2 to the minus the length of `bits`. Written by `code()`. | **`Pair`** | Field | Class | Notes | |---|---|---| | `code` | `string` | The name of the `Code` the pair belongs to. | | `first` | `string` | The first word. | | `second` | `string` | The second word. | | `prefix` | `bool` | True where the first word is the beginning of the second, or the same word. Written by `code()`. | ### 3.58 `computing` — derived fields | Field | Definition | |---|---| | `Code.oversubscribed` | `kraft > 1.0` | `oversubscribed` is True where the Kraft sum is over 1, and then no uniquely decodable code has words of those lengths. It is absent until the rule that concludes `kraft` has. It is a `bool`. ### 3.59 `computing` — standing rules Each holds continuously, as in §3.17. A rule over a code and a word binds them as `c` and `w`; a rule over a code and a pair binds the pair as `p`. | Rule | Over | Concludes | While | |---|---|---|---| | `code_claims` | `Code`, `Word` | `claims` | the word's `code` names the code and its `weight > -1.0e300`; the code takes the number of claims of `weight` those words hold | | `code_words` | `Code`, `Word` | `words` | the word's `code` names the code and its `weight > -1.0e300`; the code takes the number of distinct such words | | `code_disputed` | `Code` | `disputed` | the code's `claims` is greater than its `words`; concludes `True` | | `kraft_of_words` | `Code`, `Word` | `kraft` | the word's `code` names the code and the code has no `disputed`; the code takes the sum of those words' `weight` | | `complete` | `Code` | `complete` | the code's `kraft` is 1.0; concludes `True` | | `prefix_free` | `Code` | `prefix_free` | no pair of the code has `prefix` True; concludes `True` | `computing` declares no standing constraint. Five notes that are contract rather than commentary: - **A Kraft sum of 1 does not make a code prefix-free.** The Kraft sum is a property of the lengths of the words alone, and `prefix_free` is a property of the words. A code with a Kraft sum of 1 can still have a word that begins another, and one with a Kraft sum of less than 1 can have one too. The sum says whether a code with those lengths could exist: over 1, none could. - **`complete` is concluded, never denied.** A code whose Kraft sum is 1 is `complete`. A code whose sum is anything else has no `complete` at all rather than a False one, and the same holds of `prefix_free`: it is concluded where no pair breaks it, and absent where one does. - **A word that begins another is a pair.** `code()` writes a pair for every two different positions of the list, so a word given twice is a pair with itself and the code is not prefix-free. The two positions are one `Word`, and its `weight` counts once in the sum. - **A code of no words is prefix-free.** Its Kraft sum is 0, and it has no pair to break the rule. A word written again with another string is a different word: nothing withdraws the first, so a corrected code is written under a new name. - **Disagreement is reasoned about, not resolved.** When two sources give a field two values, every value is reasoned about, and a conclusion stands if any value on record supports it. `unsettled()` names the fact. The Kraft sum reads every value of a `weight`, so a word whose weight a second source writes, even the same weight, would be added twice; `words` and `claims` count the words and their claims over the one binding the sum reads, and while the claims are more the code is `disputed` and has no `kraft`, `complete` or `oversubscribed`. A word with no `weight` is in neither count, and one whose `code` holds two values counts in each code it names, each Kraft sum being one source's. ### 3.60 `computing` — queries Called by name after `import computing`. The first writes facts and answers nothing. The next four read what the rules concluded, and `unsettled()` names what is in disagreement; `kraft_sum` refuses a disputed code. The last fourteen are value scripts that return a value and write nothing. An `int` is 64 bits: the checksums fit, and a 64-bit hash that wraps would not. Every loop is bounded, and the bound is stated where it limits an answer. | Query | Answers | |---|---| | `code(name, words)` | Nothing. Writes the `Code` named `name`'s `label`, a `Word` for each word of `words` with its `code`, `bits` and `weight`, and a `Pair` for each two different positions of the list, with their `code`, `first`, `second` and `prefix`, under the source `"code"`. The pairs grow as the square of the number of words. | | `prefix_free_codes()` | The codes in which no word begins another, sorted. | | `kraft_sum(name)` | The Kraft sum of the code `name`, 0.0 before its words are written. A code with `disputed` is refused. | | `disputed_codes()` | The codes with `disputed`, sorted. | | `breaking_pairs(name)` | Every pair `"first second"` of the code in which the first word begins the second, sorted; empty for a prefix-free code. | | `unsettled()` | Each word and pair that holds two different values in force for a fact you write, given as `word` or `pair`, its name and the field, `word good_0 bits`, sorted. | | `crc32(data)` | CRC-32/ISO-HDLC, bit by bit, of a string whose characters have codes from 0 to 255, each taken as a byte: `"123456789"` gives 3421780262, which is 0xcbf43926. | | `adler32(data)` | Adler-32 of a string whose characters have codes from 0 to 255: `"Wikipedia"` gives 300286872, which is 0x11e60398. | | `luhn_valid(digits)` | Whether a string of digits passes Luhn's check: every second digit from the right doubled, 9 taken from any above 9, and the sum a multiple of 10. | | `isbn13_valid(digits)` | Whether a string of exactly 13 digits, hyphens removed, passes the ISBN-13 check: weights 1 and 3 alternately, and the sum a multiple of 10. | | `to_base(n, base)` | `n`, at least 0, written in a base from 2 to 36 with the digits 0 to 9 and a to z. An `int` has at most 63 binary digits, so the loop is bounded by 64. | | `from_base(text, base)` | A number written in a base from 2 to 36 in lower-case digits, no longer than the 63 binary digits an `int` holds. | | `hamming_distance(a, b)` | How many bits differ between `a` and `b`, both at least 0. | | `hamming_encode(d)` | Hamming(7,4): four data bits, `d` from 0 to 15, as a seven-bit word whose bits from the left are `p1 p2 d1 p3 d2 d3 d4`. Eleven encodes as 51. | | `hamming_decode(w)` | The four data bits of a Hamming(7,4) word, `w` from 0 to 127, after correcting any single flipped bit. Two flipped bits are decoded wrongly; the code cannot tell. | | `entropy(counts)` | Shannon's entropy in bits of a source whose symbols occurred `counts[i]` times, `-sum(p * math.log2(p))`. Two equal counts give 1.0 and four give 2.0. | | `huffman_lengths(freqs)` | The length of each symbol's codeword in a Huffman code for symbols that occurred `freqs[i]` times, merging the two lightest groups at each step, the lower index first on a tie. Frequencies 45, 13, 12, 16, 9 and 5 give 1, 3, 3, 3, 4 and 4. There are at most `len(freqs) - 1` merges. | | `binary_search(items, target)` | The index of `target` in a list sorted ascending, or -1. At most 64 halvings, which any list of an `int`'s length needs. | | `binary_search_steps(n, target)` | How many probes a binary search of the indexes 0 to `n - 1` makes to find the index `target`: 9 for the first of 1,000 and 20 for the last of 1,000,000. When the target is outside, how many it makes before it gives up. | | `dijkstra(n, edges, src)` | The shortest distance from node `src` to each of the nodes 0 to `n - 1`, over directed edges `[from, to, weight]` with weights from 0 up. A node not reached keeps 1000000, so a path is shorter than that. It makes `n` rounds of settling the nearest node. | ### 3.61 `calendars` — declared fields The writing scripts of §3.64 write `Year` under the source `"years"`, `Day` under `"days"` and `Reform` under the source you pass, and you may write the same fields yourself. A **year** is named `y`, the letter y and its number, as `years()` and `year()` name it. A **reform** and a **day** are named by you; a reform is named for the place that adopted it. A date is one whole number, `year * 10000 + month * 100 + day`, so 4 October 1582 is 15821004, and two dates compare in order whichever months they fall in. The **gap** is a relation, `Gap..`, concluded by a rule and never written. **`Year`** | Field | Class | Notes | |---|---|---| | `number` | `int` | The year's number. Written by `years()` and `year()`. | | `r4` | `int` | Computed from `number` (§3.62). Never written. | | `r100` | `int` | Computed from `number` (§3.62). Never written. | | `r400` | `int` | Computed from `number` (§3.62). Never written. | | `julian_leap` | `bool` | Concluded by a rule (§3.63): the year is a leap year under the Julian rule. Never written. | | `gregorian_leap` | `bool` | Concluded by a rule (§3.63): the year is a leap year under the Gregorian rule. Never written. | | `differ` | `bool` | Concluded by a rule (§3.63): the Julian rule makes the year a leap year and the Gregorian rule does not. Never written. | **`Reform`** | Field | Class | Notes | |---|---|---| | `last` | `int` | The last day of the old calendar, as a date. Written by `reform()`. | | `first` | `int` | The first day of the new calendar, as a date. Written by `reform()`. | | `last_count` | `int` | The day number of `last` on the Julian calendar, as `julian_day_number` returns it. Written by `reform()`. | | `first_count` | `int` | The day number of `first` on the Julian calendar. Written by `reform()`. | | `skipped` | `int` | Computed from the two counts (§3.62). Never written. | **`Day`** | Field | Class | Notes | |---|---|---| | `ymd` | `int` | The day, as a date. Written by `day()`. | **`Gap`** declares no field. It is the relation of §3.63: `Gap..` is `True` for a day that falls after a reform's last day of the old calendar and before its first day of the new one. ### 3.62 `calendars` — derived fields | Field | Definition | |---|---| | `Year.r4` | `number % 4` | | `Year.r100` | `number % 100` | | `Year.r400` | `number % 400` | | `Reform.skipped` | `first_count - last_count - 1` | The three remainders are those of the year's number on division by 4, 100 and 400. `skipped` is the number of days between the reform's two counts, which are day numbers of one calendar, so it holds across the end of a month: 10 for Rome's reform of 1582, from Thursday 4 October to Friday 15 October, and 11 for Britain's of 1752, from 2 September to 14 September. Each is absent until the fields it reads are present, and all are `int`. ### 3.63 `calendars` — standing rules Each holds continuously, as in §3.17. A rule over a year binds it as `y`, and the rule over a day and a reform binds them as `d` and `r`. | Rule | Over | Concludes | While | |---|---|---|---| | `julian_leap_year` | `Year` | `julian_leap` | the year's `r4` is 0; concludes `True` | | `gregorian_leap_ordinary` | `Year` | `gregorian_leap` | the year's `r4` is 0 and its `r100` is not 0; concludes `True` | | `gregorian_leap_fourth_century` | `Year` | `gregorian_leap` | the year's `r400` is 0; concludes `True` | | `years_differ` | `Year` | `differ` | the year's `julian_leap` is `True` and it has no `gregorian_leap`; concludes `True` | | `day_in_the_gap` | `Day`, `Reform` | `Gap` | the day's `ymd` is above the reform's `last` and below its `first`; concludes `Gap..` is `True` | `calendars` declares no standing constraint. Six notes that are contract rather than commentary: - **A year that is not a leap year has no value, not a false one.** `gregorian_leap` and `julian_leap` are concluded where they hold and absent where they do not, so `why_not` of one names the remainder that failed. The two Gregorian rules are alternatives: a year divisible by 4 and not by 100 qualifies by the first, and a year divisible by 400 by the second. - **`differ` is a Julian leap year the Gregorian rule refuses.** Those are the centuries not divisible by 400: 1700, 1800, 1900 and 2100, and not 1600 or 2000. - **A year the store does not hold is no year.** The rules reach only the years you wrote, so `gregorian_leap(2000)` is `False` before 2000 is written, which says nothing about the year. The calculations of §3.64 answer for any year. - **A day in the gap is marked and kept.** The rule reads the day's `ymd` and the reform's `last` and `first` as numbers, strictly between them. The day is a valid fact; the relation is the only consequence, and a reform's `first` rewritten moves the gap and withdraws the marks that rested on it. - **A reform rewritten replaces what the same source wrote.** Written again under another source it is held beside the first, every value is reasoned about, and a day is in the gap if it is in the gap under any value in force. `unsettled()` names the fact two sources disagree about. - **The gap is per reform, and the reform is named for the place.** A day that is in one place's gap is not in another's, and `missing(day, place)` asks about the reform written under that name. ### 3.64 `calendars` — queries Called by name after `import calendars`. The first four write facts and answer nothing. The next eight read what the rules concluded or what was written, and `unsettled()` names what is in disagreement. The last eleven are value scripts that return a value and write nothing. The calculations count in the proleptic Gregorian calendar, years 1 to 9999, with a day of 86,400 seconds and no leap second. A `datetime` is a UTC instant written with a trailing Z, and a `duration` has days, hours, minutes and seconds and no months or years. | Query | Answers | |---|---| | `years(first_year, last_year)` | Nothing. Writes a `Year` named `y` for each year from `first_year` to `last_year` inclusive, with its `number`, under the source `"years"`. | | `year(n)` | Nothing. Writes the one `Year` `y`. | | `reform(name, last_year, last_month, last_day, first_year, first_month, first_day, source)` | Nothing. Writes the `Reform` named `name`'s `last` and `first` as dates and its `last_count` and `first_count` as Julian day numbers, under `source`. | | `day(name, y, m, d)` | Nothing. Writes the `Day` named `name`'s `ymd`, under the source `"days"`. | | `true_for(values, name)` | Whether any claim in `values`, a list as `list_values` returns, is `True` for the subject `name`. The reading below it is built on it. | | `julian_leap(n)` | Whether the year `n` is a Julian leap year, as the rules concluded; `False` for a year not written. | | `gregorian_leap(n)` | Whether the year `n` is a Gregorian leap year, as the rules concluded; `False` for a year not written. | | `differ(n)` | Whether the year `n` is one the two rules disagree about. | | `years_that_differ()` | The written years the two rules disagree about, sorted. | | `skipped(name)` | The days the reform `name` skipped, one value, or one for each source when the sources disagree, sorted; empty before the reform is written. | | `missing(day_name, place)` | Whether the day falls in the gap of the reform written as `place`, under any value in force for the reform. | | `unsettled()` | Each reform or day that holds two different values in force for a fact you write, given as `reform` or `day`, its name and the field, `reform rome first`, sorted. | | `is_gregorian_leap(y)` | Whether `y` is a leap year under the Gregorian rule, for any integer. | | `is_julian_leap(y)` | Whether `y` is a leap year under the Julian rule, every fourth year. | | `month_length(y, m)` | The days in month `m`, 1 to 12, of year `y` under the Gregorian rule: 28 or 29 for February, 30 or 31 otherwise. The month is not checked. | | `julian_month_length(y, m)` | The days in month `m` of year `y` under the Julian rule. | | `date_exists(y, m, d)` | Whether the Gregorian calendar has this day, in years 1 to 9999; `False` for 29 February of 2026. | | `weekday(y, m, d)` | The weekday of a Gregorian date, 0 for Sunday to 6 for Saturday, by Sakamoto's method, proleptic. The date is not checked. | | `easter(y)` | Easter Sunday of the year `y` as `[month, day]` in the Western calendar: `[4, 5]` for 2026. Defined for years from 1583. | | `day_number(y, m, d)` | The Gregorian day number, 1 for 1 January of year 1; the difference of two is the days between them. | | `julian_day_number(y, m, d)` | A day number on the Julian calendar, in the same unit; its zero is not `day_number`'s. | | `span(a, b)` | The time from the `datetime` `a` to `b` as a `duration`, negative when `b` is earlier. A span of more than about 292 years is refused. | | `after(t, days)` | The instant `days` whole days after `t`, negative days going back. The result must lie in years 1 to 9999, or it is refused. | ### 3.65 `colour` — declared fields The writing scripts of §3.68 write `Pair` under the source `"pairs"` and `Ray` under `"rays"`, and you may write the same fields yourself. A **pair** is a colour of text on a colour of background and a **ray** is a ray meeting a boundary; each is named by you. A luminance is the **relative luminance** of an sRGB colour, from 0.0 for black to 1.0 for white. **`Pair`** | Field | Class | Notes | |---|---|---| | `fg` | `real` | The relative luminance of the text. | | `bg` | `real` | The relative luminance of the background. | | `ratio` | `real` | Computed from the two (§3.66): the contrast ratio when the text is the lighter. Never written. | | `inverse` | `real` | Computed from the two (§3.66): the contrast ratio when the background is the lighter. Never written. | | `aa` | `bool` | Concluded by a rule (§3.67): the pair clears WCAG AA, 4.5 to 1. Never written. | | `aaa` | `bool` | Concluded by a rule (§3.67): the pair clears WCAG AAA, 7 to 1. Never written. | | `large_aa` | `bool` | Concluded by a rule (§3.67): the pair clears AA for large text, 3 to 1. Never written. | | `large_aaa` | `bool` | Concluded by a rule (§3.67): the pair clears AAA for large text, 4.5 to 1. Never written. | **`Ray`** | Field | Class | Notes | |---|---|---| | `n1` | `real` | The refractive index of the medium the ray leaves, 1 or more, as every medium's is for visible light. | | `n2` | `real` | The refractive index of the medium the ray meets, 1 or more. | | `sin_i` | `real` | The sine of the ray's angle of incidence, 0.0 to 1.0. | | `sin_t` | `real` | Computed from the three (§3.66): the sine of the refracted angle that Snell's law asks for. Never written. | | `total` | `bool` | Concluded by a rule (§3.67): the ray is totally reflected. Never written. | ### 3.66 `colour` — derived fields | Field | Definition | |---|---| | `Pair.ratio` | `(fg + 0.05) / (bg + 0.05)` | | `Pair.inverse` | `(bg + 0.05) / (fg + 0.05)` | | `Ray.sin_t` | `n1 * sin_i / n2` | `ratio` is the contrast ratio of a pair whose text is the lighter, and `inverse` that of a pair whose background is the lighter; the one that applies is at least 1.0, and a pair of equal luminance has 1.0 in both. `sin_t` is the sine of the angle of the refracted ray, and exceeds 1.0 where no such angle exists. Each is absent until the fields it reads are present, and all are `real`. ### 3.67 `colour` — standing rules Each holds continuously, as in §3.17. A rule over a pair binds it as `p` and a rule over a ray as `r`. | Rule | Over | Concludes | While | |---|---|---|---| | `aa_light_text` | `Pair` | `aa` | the pair's `fg` is above its `bg` and its `ratio >= 4.5`; concludes `True` | | `aa_dark_text` | `Pair` | `aa` | the pair's `bg` is no less than its `fg` and its `inverse >= 4.5`; concludes `True` | | `aaa_light_text` | `Pair` | `aaa` | the pair's `fg` is above its `bg` and its `ratio >= 7.0`; concludes `True` | | `aaa_dark_text` | `Pair` | `aaa` | the pair's `bg` is no less than its `fg` and its `inverse >= 7.0`; concludes `True` | | `large_aa_light_text` | `Pair` | `large_aa` | the pair's `fg` is above its `bg` and its `ratio >= 3.0`; concludes `True` | | `large_aa_dark_text` | `Pair` | `large_aa` | the pair's `bg` is no less than its `fg` and its `inverse >= 3.0`; concludes `True` | | `large_aaa_light_text` | `Pair` | `large_aaa` | the pair's `fg` is above its `bg` and its `ratio >= 4.5`; concludes `True` | | `large_aaa_dark_text` | `Pair` | `large_aaa` | the pair's `bg` is no less than its `fg` and its `inverse >= 4.5`; concludes `True` | | `total_internal_reflection` | `Ray` | `total` | the ray's `n1` is above its `n2`, its `sin_i <= 1.0` and its `sin_t > 1.0`; concludes `True` | `colour` declares no standing constraint. Five notes that are contract rather than commentary: - **A level is concluded, never denied.** A pair that clears a level has the value `True` for it; a pair that fails has none, rather than a false one, and `why_not` names the premise that failed. A pair that clears no level is kept. - **The ratio the pair uses is the one that applies.** The two ratios are the same quantity read from either side. A pair whose text is the lighter uses `ratio` and a pair whose background is the lighter, or equal to the text, uses `inverse`, so a light-on-dark pair and a dark-on-light pair of the same two colours clear the same levels. - **The thresholds are the guidelines' and are compared as they are written.** 4.5 and 7 are the AA and AAA levels for ordinary text, and 3 and 4.5 for large-scale text, which the guidelines set at 18 point or 14 point bold. A ratio exactly on a threshold clears it. - **A ray is totally reflected only into a rarer medium.** The rule needs `n1` above `n2`, a `sin_i` of at most 1.0 and a `sin_t` above 1.0. At a `sin_t` of exactly 1.0 the ray runs along the boundary, the critical angle, and refracts. Light entering a denser medium never meets the rule. - **Disagreement is reasoned about, not resolved.** When two sources give a luminance or an index two values, every value is reasoned about, and a level stands if any value on record clears it. `unsettled()` names the fact. ### 3.68 `colour` — queries Called by name after `import colour`. The first two write facts and answer nothing. The next four read what the rules concluded, and `unsettled()` names what is in disagreement. The last twelve are value scripts that return a value and write nothing. Floats are IEEE doubles. A colour is a triple of sRGB channels, 0 to 255, or a string `#rrggbb`. | Query | Answers | |---|---| | `pair(name, text, background)` | Nothing. Writes the `Pair` named `name`'s `fg` and `bg` under the source `"pairs"`. | | `ray(name, from_index, into_index, sine_of_incidence)` | Nothing. Writes the `Ray` named `name`'s `n1`, `n2` and `sin_i` under the source `"rays"`. | | `holds(values, name)` | Whether any claim in `values`, a list as `list_values` returns, is `True` for the subject `name`. The readings below are built on it. | | `levels(name)` | The contrast levels the pair clears, from `"AA"`, `"AAA"`, `"large AA"` and `"large AAA"` in that order; empty for a pair that clears none. | | `total(name)` | Whether the ray is totally reflected. | | `unsettled()` | Each pair or ray that holds two different values in force for a fact you write, given as `pair` or `ray`, its name and the field, `pair grey fg`, sorted. | | `srgb_linear(c)` | The linear light of an sRGB channel `c`, 0 to 255: `c / 255` over 12.92 up to 0.04045, and `((c / 255 + 0.055) / 1.055)` to the 2.4 above it. | | `luminance(r, g, b)` | The relative luminance of an sRGB colour: 0.2126 R + 0.7152 G + 0.0722 B in linear light. | | `luminance_hex(text)` | The relative luminance of a colour written `#rrggbb`; anything else is refused. | | `contrast_ratio(l1, l2)` | The contrast ratio of two relative luminances, the lighter plus 0.05 over the darker plus 0.05: 1.0 for equal ones, 21.0 for black and white. | | `contrast_hex(a, b)` | The contrast ratio of two colours written `#rrggbb`. | | `hsl(r, g, b)` | `[hue, saturation, lightness]` of an sRGB colour: hue in degrees from 0.0 up to 360.0, the others from 0.0 to 1.0; a grey has hue 0.0 and saturation 0.0. | | `refraction_angle(n1, n2, incidence_deg)` | The angle of the refracted ray in degrees, by Snell's law, the incidence taken modulo 360 degrees by `math.fmod` first; where `n1` times its sine over `n2` is not a normal real, that is worked on the mantissas and exponents `math.frexp` gives. Refused where the ray is totally reflected. | | `critical_angle(n1, n2)` | The critical angle in degrees for light going from index `n1` into `n2`; it exists only into a rarer medium, `n2` no larger than `n1`, and is refused otherwise. | | `lens_image(focal_length, object_distance)` | The image distance of a thin converging lens in air, `1 / (1/f - 1/u)`, in the unit of the two lengths; positive for a real image. Refused with the object at the focus. | | `lens_magnification(focal_length, object_distance)` | The magnification of the same lens, the negative of the image distance over the object distance, taken as `f / (f - u)`, which it equals, and of halves where `f - u` passes the largest real; negative for an inverted image. Refused with the object at the focus. | | `wien_peak(temperature_k)` | The wavelength in metres at which a black body at the temperature in kelvin radiates most strongly per unit wavelength, 2.897771955e-3 over the temperature. | | `frequency_hz(wavelength_nm)` | The frequency in hertz of light of the wavelength in nanometres in a vacuum, 299792458 over the wavelength in metres. | ### 3.69 `body` — declared fields **`body` is not medical advice.** It states rules taught in every introduction to the subject and arithmetic with published formulas. Blood compatibility in practice is decided by laboratory testing, a body mass index is a measure for populations that its own namer judged inappropriate for individual evaluation, and the energy and heart-rate formulas are estimates that may deviate significantly from a person's actual value. It gives no dose, no diagnosis and no treatment. The writing scripts of §3.72 write `Transfusion` under the source you pass and `Person` under `"people"`, and you may write the same fields yourself. A **transfusion** is a donor's blood group given to a recipient's, and a **person** a body of a mass and a height; each is named by you. A blood group is held as its three antigens, A, B and D, `1` for present and `0` for absent. **`Transfusion`** | Field | Class | Notes | |---|---|---| | `da` | `int` | 1 where the donor's red cells carry the A antigen. Written by `transfusion()`. | | `db` | `int` | 1 where they carry the B antigen. Written by `transfusion()`. | | `dd` | `int` | 1 where they carry the D antigen, the Rh-positive groups. Written by `transfusion()`. | | `ra` | `int` | 1 where the recipient's red cells carry the A antigen. Written by `transfusion()`. | | `rb` | `int` | 1 where they carry the B antigen. Written by `transfusion()`. | | `rd` | `int` | 1 where they carry the D antigen. Written by `transfusion()`. | | `lacks_a` | `bool` | Concluded by a rule (§3.71): the donor's red cells carry A and the recipient's do not. Never written. | | `lacks_b` | `bool` | Concluded by a rule (§3.71): the same for B. Never written. | | `lacks_d` | `bool` | Concluded by a rule (§3.71): the same for D. Never written. | | `reacts` | `bool` | Concluded by a rule (§3.71): the red cells would react, from a lacked A or B. Never written. | | `sensitises` | `bool` | Concluded by a rule (§3.71): the recipient is at risk of sensitisation, from a lacked D. Never written. | **`Person`** | Field | Class | Notes | |---|---|---| | `kg` | `real` | The person's mass in kilograms. Written by `person()`. | | `metres` | `real` | The person's height in metres. Written by `person()`. | | `bmi` | `real` | Computed from the two (§3.70). Never written. | | `underweight` | `bool` | Computed from `bmi` (§3.70). Never written. | | `overweight` | `bool` | Computed from `bmi` (§3.70). Never written. | | `obese` | `bool` | Computed from `bmi` (§3.70). Never written. | | `normal` | `bool` | Concluded by a rule (§3.71). Never written. | ### 3.70 `body` — derived fields | Field | Definition | |---|---| | `Person.bmi` | `kg / metres / metres` | | `Person.underweight` | `bmi < 18.5` | | `Person.overweight` | `bmi >= 25.0` | | `Person.obese` | `bmi >= 30.0` | `bmi` is the body mass index, the mass over the square of the height, divided by the height twice so that it is had wherever it is a real. The three bands are the World Health Organization's: `underweight` is an index strictly under 18.5, `overweight` 25 or more, the obese included, and `obese` 30 or more. They are bands of a population statistic, not a judgement of a person. A height of zero draws no index, so `bmi` is absent and so are the bands, and `why_not` says the conclusion computes a division that has none. Each is absent until the fields it reads are present. `bmi` is `real` and the bands are `bool`. ### 3.71 `body` — standing rules Each holds continuously, as in §3.17. A rule over a transfusion binds it as `t` and a rule over a person as `p`. | Rule | Over | Concludes | While | |---|---|---|---| | `lacks_a` | `Transfusion` | `lacks_a` | the donor's `da` is above the recipient's `ra`; concludes `True` | | `lacks_b` | `Transfusion` | `lacks_b` | the donor's `db` is above the recipient's `rb`; concludes `True` | | `lacks_d` | `Transfusion` | `lacks_d` | the donor's `dd` is above the recipient's `rd`; concludes `True` | | `reacts_for_a` | `Transfusion` | `reacts` | the transfusion's `lacks_a` is `True`; concludes `True` | | `reacts_for_b` | `Transfusion` | `reacts` | the transfusion's `lacks_b` is `True`; concludes `True` | | `sensitises_for_d` | `Transfusion` | `sensitises` | the transfusion's `lacks_d` is `True`; concludes `True` | | `normal_weight` | `Person` | `normal` | the person's `bmi >= 18.5` and `bmi < 25.0`; concludes `True` | `body` declares no standing constraint. Five notes that are contract rather than commentary: - **A verdict is a stated rule, not advice.** `reacts` is the ABO rule: the donor's red cells carry an antigen the recipient's lack. `sensitises` is the D antigen rule, which the sources describe as a risk of sensitisation to the D antigen and not an immediate reaction. Plasma and platelet compatibility, the Kell and other blood systems, a rare group and any dose are outside what the rules say. - **A conclusion is positive.** A transfusion that lacks nothing has none of the five conclusions rather than false ones, and `why_not` of `reacts` names the two premises that were not met. - **A band is the narrowest one that holds.** An index of 30 or more is `overweight` and `obese` both, the WHO bands being cumulative above 25, and `normal` is 18.5 up to but not including 25, so the four bands cover every index. A person whose `bmi` is absent has none. - **A group is three antigens.** O has neither A nor B, A has A, B has B and AB has both, and a plus sign puts D present. The writing script refuses a group written any other way. - **Disagreement is reasoned about, not resolved.** When two sources give an antigen, a mass or a height two values, every value is reasoned about, and a conclusion stands if any value on record supports it. `unsettled()` names the fact. `bmi()` reads one value and refuses while two are in force, as a person with two masses or two heights gives it. ### 3.72 `body` — queries Called by name after `import body`. The first three write facts, and the first returns the antigens it writes; the next five read what the rules concluded or what was written, and `unsettled()` names what is in disagreement; none refuses because sources disagree, except `bmi()` as §3.71 says. The last five are value scripts that return a value and write nothing. Floats are IEEE doubles, and `math.sqrt` is correctly rounded, so a result agrees with CPython's. The formulas are estimates for adults and are no substitute for a clinician. | Query | Answers | |---|---| | `antigens(group)` | The A, B and D antigens of a blood group written `"A+"`, `"B-"`, `"AB+"` or `"O-"` as `[a, b, d]`, each 1 or 0; any other writing is refused. | | `transfusion(name, donor, recipient, source)` | Nothing. Writes the `Transfusion` named `name`'s six antigens from the two groups, under `source`. Written again under another source it holds the rival value beside the first. | | `person(name, kilograms, height_metres)` | Nothing. Writes the `Person` named `name`'s `kg` and `metres` under the source `"people"`. | | `holds(values, name)` | Whether any claim in `values`, a list as `list_values` returns, is `True` for the subject `name`. The readings below are built on it. | | `verdict(name)` | What the rules conclude for a transfusion: `"reacts"`, `"sensitises"`, both in that order, or empty for neither. | | `lacks(name)` | The antigens of the donor the recipient lacks, from `"A"`, `"B"` and `"D"`, in that order. | | `bmi(name)` | A person's body mass index; 0.0 where none is drawn, as for a height of zero or before the facts are written. | | `band(name)` | The narrowest WHO band the rules conclude for a person, `"underweight"`, `"normal"`, `"overweight"` or `"obese"`; `""` where no index is drawn. | | `unsettled()` | Each transfusion or person that holds two different values in force for a fact you write, given as `transfusion` or `person`, its name and the field, `transfusion t4 rd`, sorted. | | `body_mass_index(kilograms, height_metres)` | The mass in kilograms over the square of the height in metres, divided by the height twice as `Person.bmi` is; a height of zero is refused with a division by zero. | | `mifflin_st_jeor(kilograms, height_cm, age_years, male)` | The resting energy in kilocalories a day by Mifflin and St Jeor (1990): 10 times the mass plus 6.25 times the height in centimetres minus 5 times the age, then 5 added for a male and 161 taken off for a female. | | `body_surface_mosteller(kilograms, height_cm)` | The body surface in square metres by Mosteller (1987), the square root of the height in centimetres times the mass over 3600; where that product passes the largest real or is under `1e-300` in size, the product of the two square roots over 60. | | `max_heart_rate_haskell_fox(age_years)` | The maximum heart rate in beats a minute by Haskell and Fox (1971), 220 minus the age; its standard deviation is 12 to 15. | | `max_heart_rate_tanaka(age_years)` | The maximum heart rate in beats a minute by Tanaka, Monahan and Seals (2001), 208 minus 0.7 times the age; its standard deviation is about 10. | ### 3.73 `sound` — declared fields **`sound` is not occupational-health advice.** It states published limits as data and arithmetic with published formulas. A limit is a figure on a page. Whether a worker is protected is decided by a measurement and a hearing conservation programme, and a dose over a limit is not a finding of hearing loss. It gives no diagnosis and no treatment. The writing scripts of §3.76 write `Exposure` under the source `"exposure"`, `Segment` under `"segment"`, `Worker` under `"segment"` and `Tone` under `"tone"`, and you may write the same fields yourself. An **exposure** is a sound level held for some hours and judged against a limit, a **segment** one period of a worker's day at one level, a **worker** that day as a whole, and a **tone** a frequency; each is named by you. A level is in decibels, A-weighted and taken as you give it, never computed from a spectrum. A **limit** is a pair, a reference level for eight hours and an **exchange rate**, the decibels by which a level may rise while the permitted time halves: 90 and 5 for the limit OSHA's Table G-16 tabulates, 85 and 3 for the level NIOSH recommends. **`Exposure`** | Field | Class | Notes | |---|---|---| | `level` | `real` | The level in decibels. Written by `exposure()`. | | `hours` | `real` | The hours it is held. Written by `exposure()`. | | `ref` | `real` | The limit's reference level, for eight hours. Written by `exposure()`. | | `rate` | `real` | The limit's exchange rate. Written by `exposure()`. | | `allowed` | `real` | The hours the limit permits at the level, from `permissible_hours` (§3.76). Written by `exposure()`. | | `dose` | `real` | Computed from `hours` and `allowed` (§3.74). Never written. | | `over` | `bool` | Concluded by a rule (§3.75): the dose is more than one. Never written. | **`Segment`** | Field | Class | Notes | |---|---|---| | `worker` | `string` | The name of the worker's day it belongs to. Written by `segment()`. | | `level` | `real` | The level in decibels. Written by `segment()`. | | `hours` | `real` | The hours it is held. Written by `segment()`. | | `allowed` | `real` | The hours the limit permits at the level. Written by `segment()`. | | `dose` | `real` | Computed from `hours` and `allowed` (§3.74). Never written. | **`Worker`** | Field | Class | Notes | |---|---|---| | `label` | `string` | The worker's name. Written by `segment()`, so that the day exists. | | `segments` | `int` | Concluded by a rule (§3.75): how many of the worker's segments have a `dose`. Never written. | | `claims` | `int` | Concluded by a rule (§3.75): how many claims of `dose` they hold. Never written. | | `disputed` | `bool` | Concluded by a rule (§3.75): `claims` is greater than `segments`. Never written. | | `total` | `real` | Concluded by a rule (§3.75): the sum of the doses of the worker's segments. Never written. | | `over` | `bool` | Concluded by a rule (§3.75): the total is more than one. Never written. | **`Tone`** | Field | Class | Notes | |---|---|---| | `hz` | `real` | The frequency in hertz. Written by `tone()`. | | `audible` | `bool` | Concluded by a rule (§3.75): 20 to 20,000 Hz, both ends inside. Never written. | | `infrasound` | `bool` | Concluded by a rule (§3.75): below 20 Hz. Never written. | | `ultrasound` | `bool` | Concluded by a rule (§3.75): above 20,000 Hz. Never written. | ### 3.74 `sound` — derived fields | Field | Definition | |---|---| | `Exposure.dose` | `hours / allowed` | | `Segment.dose` | `hours / allowed` | The **dose** is the share of a day's permitted exposure that the hours use: 1.0 is the whole of it, and 0.5 is half. It is absent until `hours` and `allowed` are present, and is `real`. `allowed` is a written field and not a derived one, because a power cannot be computed in a derived field; the script that writes it applies `permissible_hours` (§3.76). ### 3.75 `sound` — standing rules Each holds continuously, as in §3.17. A rule over an exposure binds it as `e`, a rule over a worker as `w` and over its segments as `s`, and a rule over a tone as `t`. | Rule | Over | Concludes | While | |---|---|---|---| | `over_limit` | `Exposure` | `over` | the exposure's `dose > 1.0`; concludes `True` | | `day_segments` | `Worker`, `Segment` | `segments` | the segment's `worker` is the worker and its `dose > -1.0e300`; concludes the number of distinct such segments | | `day_claims` | `Worker`, `Segment` | `claims` | the segment's `worker` is the worker and its `dose > -1.0e300`; concludes the number of claims of `dose` those segments hold | | `day_disputed` | `Worker` | `disputed` | the worker's `claims` is greater than its `segments`; concludes `True` | | `day_total` | `Worker`, `Segment` | `total` | the segment's `worker` is the worker and the worker has no `disputed`; concludes the sum of the `dose` of those segments | | `day_over` | `Worker` | `over` | the worker's `total > 1.0`; concludes `True` | | `audible_tone` | `Tone` | `audible` | the tone's `hz >= 20.0` and `hz <= 20000.0`; concludes `True` | | `infrasound_tone` | `Tone` | `infrasound` | the tone's `hz < 20.0`; concludes `True` | | `ultrasound_tone` | `Tone` | `ultrasound` | the tone's `hz > 20000.0`; concludes `True` | `sound` declares no standing constraint. Seven notes that are contract rather than commentary: - **A dose of exactly one is at the limit and is not over.** An exposure of 4 hours at 95 decibels against a limit of 90 and 5 has a dose of 1.0 and no `over`; `why_not` says the dose is 1.0. The same holds for a day whose total is exactly one. - **An exposure over its limit is marked and kept.** The exposure is a valid fact; `over` is the only consequence, and rewriting the exposure with fewer hours withdraws it. - **A conclusion is positive.** An exposure that is not over has no `over`, not a false one, and `why_not` names the premise that failed. A frequency that is not audible has no `audible`. - **A day is judged by the sum of its segments' doses.** The segments may have different limits, since each carries the hours its own limit permits. A worker with no segment has no day, and a segment name is used once. The sum reads every value of a dose, so a segment whose dose holds two values, or whose hours a second source writes, would be added twice; `segments` and `claims` count the segments and their claims over the one binding the sum reads, and while the claims are more the day is `disputed` and has no `total` or `over`. A segment with no `dose` is in neither count, and one whose `worker` holds two values counts in each day it names, each total being one source's. - **The hours a limit permits are this module's own derivation.** `permissible_hours` is `8 / 2^((level - ref) / rate)`, from a reference level, eight hours and an exchange rate. It is not a formula read from NIOSH or from OSHA. It reproduces the table's 95 decibels for 4 hours and 100 for 2 at 90 and 5, and it gives 6.06 hours at 92 decibels where the table has 6, 3.03 at 97 where it has 3 and 1.52 at 102 where it has 1.5: a published table rounds where the derivation does not. - **The range of hearing is a convention.** 20 to 20,000 Hz is the commonly stated range, and it shrinks during life; `infrasound` and `ultrasound` are the names used here for what lies below and above it. - **Disagreement is reasoned about by the lists and refused by the single read.** When two sources give an exposure's hours two values, every value is reasoned about, and an exposure is over if any value puts it over; the lists of §3.76 name it, and `unsettled()` names the fact. `dose` and `total_of` read one value and refuse while two are in force, saying that the cell holds two competing values. The module does not cover frequency weighting, octave bands, room acoustics and reverberation, sound in water, the action level and the hearing conservation programme of either limit, or any limit of another country. ### 3.76 `sound` — queries Called by name after `import sound`. The first three write facts and answer nothing. The next eight read what the rules concluded, two of them helpers the others are built on, and `unsettled()` names what is in disagreement. The last eight are value scripts that return a value and write nothing. Floats are IEEE doubles. Results are not rounded. `math.log10` is correctly rounded, and CPython's can differ from it by one unit in the last place at some arguments: the level of a pressure of 1.4142135623730951 against a reference of 1 is 3.0102999566398125 here and 3.010299956639812 in CPython 3.11. A decibel therefore agrees with CPython's to that unit, not always to the last bit. | Query | Answers | |---|---| | `exposure(name, level, hours, ref_level, exchange_rate)` | Nothing. Writes the `Exposure` named `name`'s `level`, `hours`, `ref` and `rate`, and its `allowed` from `permissible_hours`, under the source `"exposure"`. Written again with other hours it corrects the first. | | `segment(worker, name, level, hours, ref_level, exchange_rate)` | Nothing. Writes the `Segment` named `name` for the day of `worker`, with the hours its limit permits, and the worker's `label`, under the source `"segment"`. | | `tone(name, hertz)` | Nothing. Writes the `Tone` named `name`'s `hz` under the source `"tone"`. | | `holds(values, name)` | Whether any claim in `values`, a list as `list_values` returns, is `True` for the subject `name`. | | `names_of(values)` | The subjects for which any claim in `values` is `True`, sorted. | | `over_limit_names()` | The exposures whose dose is more than one, sorted. | | `days_over()` | The workers whose segments' doses sum to more than one, sorted. | | `dose(name)` | An exposure's dose; 0.0 before the facts are written. Refuses while two values are in force. | | `total_of(name)` | The sum of the doses of a worker's segments; 0.0 before the rule concludes it. Refuses while two values are in force, and refuses a worker with `disputed`. | | `disputed_days()` | The workers with `disputed`, sorted. | | `range_of(name)` | `"audible"`, `"infrasound"` or `"ultrasound"` for a tone; `""` before the facts are written. | | `unsettled()` | Each exposure, segment, worker and tone that holds two different values in force for a field you write: an exposure's `level`, `hours`, `ref`, `rate` or `allowed`, a segment's `worker`, `level`, `hours` or `allowed`, a worker's `label`, or a tone's `hz`. Given as its kind in lower case, its name and the field, `segment s1 hours`, sorted. | | `permissible_hours(level, ref_level, exchange_rate)` | The hours a day may hold at a level, `8 / 2^((level - ref_level) / exchange_rate)`, the rise taken of halves where `level - ref_level` passes the largest real; 8 at the reference level and half for each rise of the exchange rate. | | `level_of_pressure(pascals, reference_pascals)` | The sound pressure level in decibels, `20 log10(p / p0)`; the reference for sound in air is 0.00002 pascal. A pressure or a reference of zero or below has no level and is refused with a math domain error. Where `p / p0` is not a normal real, it is `20 (log10 p - log10 p0)`. | | `add_levels(a, b)` | The level of two incoherent sources of `a` and `b` decibels, `10 log10(10^(a/10) + 10^(b/10))`; two equal sources add 3.0103 decibels. It is computed as the louder level plus `10 log10(1 + 10^(-d/10))` for `d` the difference, so no power passes the largest real and any two levels have a sum. | | `at_distance(level_at_r1, r1, r2)` | The level at distance `r2` from a point source whose level at `r1` is given, in free field: the level less `20 log10(r2 / r1)`, 6.02 decibels for each doubling, the logarithm taken as `log10 r2 - log10 r1` where `r2 / r1` is not a normal real. A distance of zero or below is refused with a math domain error. | | `speed_of_sound(celsius)` | The speed of sound in dry air in metres a second, `331.32 * sqrt(1 + t / 273.15)`; 343.2353419474446 at 20. Below -273.15 it is refused with a math domain error. | | `wavelength(speed, hertz)` | The wavelength in metres, the speed over the frequency. | | `doppler(source_hz, speed, receiver_toward, source_toward)` | The observed frequency, `f0 (c + vr) / (c - vs)`: `receiver_toward` is the receiver's speed toward the source and `source_toward` the source's toward the receiver, each negative for motion away. The sums are taken of halves where one passes the largest real, and where the frequency is then not a normal real it is worked on the mantissas and exponents `math.frexp` gives. A source moving at the speed of sound is refused with a division by zero. | | `twa_from_dose(dose_percent)` | The 8-hour time-weighted average level of a dose written in percent, `16.61 log10(D / 100) + 90`, as OSHA's Appendix A gives it. | ### 3.77 `finance` — declared fields **`finance` is not financial advice.** It states which of several offers costs the least in total and which carry a payment over a limit you give it, and it does arithmetic with published formulas. It does not say which offer to take: the cheapest in total and an offer over a household's limit can be the same offer, and the module reports both. Every rate, price and income is yours. Ask a financial adviser. The writing scripts of §3.80 write `Offer` under the source `"offer"` and `Budget` under `"budget"`, and you may write the same fields yourself. An **offer** is a loan offer named by you, and a **budget** is a household's limit, named by the borrower it belongs to. An offer's **borrower** and **principal** together name the group in which it is compared. **`Offer`** | Field | Class | Notes | |---|---|---| | `borrower` | `string` | The borrower's name, which is also a `Budget`'s name. Written by `offer()`. | | `principal` | `real` | The sum lent. Written by `offer()`. | | `payment` | `real` | The monthly payment as the lender states it. Written by `offer()`. | | `months` | `real` | The number of payments. Written by `offer()`. | | `total` | `real` | Computed from `payment` and `months` (§3.78). Never written. | | `interest` | `real` | Computed from the three (§3.78). Never written. | | `cheapest` | `bool` | Concluded by a rule (§3.79): no offer of the same borrower and principal has a smaller total. Never written. | | `unaffordable` | `bool` | Concluded by a rule (§3.79): the payment is over the borrower's limit. Never written. | **`Budget`** | Field | Class | Notes | |---|---|---| | `limit` | `real` | The largest monthly payment the household can bear. Written by `budget()`. | ### 3.78 `finance` — derived fields | Field | Definition | |---|---| | `Offer.total` | `payment * months` | | `Offer.interest` | `(0.5 * payment * months - 0.5 * principal) * 2.0` | The total is what the lender is paid and the interest what is paid beyond the sum lent, taken of halves and doubled, which changes no digit of `payment * months - principal` and keeps a total past the largest real from making the interest one. Each is absent until the fields it reads are present, and both are `real`. **A result is a real number and is not a cent.** A bank rounds each payment to the cent and builds a schedule from those; this module does not, so a total is the payment times the months. Use it to compare, not to reproduce a lender's statement. ### 3.79 `finance` — standing rules Each holds continuously, as in §3.17. A rule over offers binds one as `a` and `b`, and the rule over an offer and a budget binds them as `o` and `g`. | Rule | Over | Concludes | While | |---|---|---|---| | `cheapest_offer` | `Offer` | `cheapest` | no offer `b` has the same `borrower` and `principal` as `a` and a `total` less than `a`'s; concludes `True` | | `unaffordable_offer` | `Offer`, `Budget` | `unaffordable` | the offer's `borrower` is the budget and its `payment` is above the budget's `limit`; concludes `True` | `finance` declares no standing constraint. Six notes that are contract rather than commentary: - **Cheapest is the absence of a cheaper one.** The rule is not "cheaper than some other offer", which would mark an offer that a third one beats. It holds while no offer of the group has a smaller total and is withdrawn when a cheaper one is written. `why_not` of it names the absence it needs and says that a cheaper offer is present. - **Offers with equal totals are each cheapest.** Neither has a cheaper one, and the module ranks nothing. That was measured, and is the rule's meaning. - **Offers are compared within a borrower and a principal.** An offer of another principal is not compared with them, so every group has a cheapest, and a group of one is its own. - **An offer over a limit is marked and kept.** The same offer can be both cheapest and unaffordable, and the module reports both. A borrower with no budget has no offer marked unaffordable: nothing is recorded to be over, and `why_not` says so. A payment exactly at the limit is not over it. - **A conclusion is positive.** An offer that is not cheapest has no `cheapest`, not a false one. - **Disagreement is reasoned about by the lists and refused by the single read.** When two sources give a payment two values, every value is reasoned about, and a conclusion stands if any value supports it. `unsettled()` names the fact. `total` reads one value and refuses while two are in force. The module does not cover fees folded into an annual percentage rate, taxes, a schedule row by row, variable rates, or any statute beyond the words of its sources. ### 3.80 `finance` — queries Called by name after `import finance`. The first three write facts and answer nothing. The next five read what the rules concluded, and `unsettled()` names what is in disagreement. The last nine are value scripts that return a value and write nothing. Floats are IEEE doubles. A rate is a fraction, 0.05 for 5 percent, except in the two doubling-time scripts, which take percent as the rule of 72 is written. Results agree with CPython's except where a logarithm is taken: `doubling_exact`'s can differ from CPython's by one unit in the last place. | Query | Answers | |---|---| | `offer(name, borrower, principal, payment, months)` | Nothing. Writes the `Offer` named `name` with its monthly payment as the lender states it, under the source `"offer"`. | | `quote(name, borrower, principal, annual_rate, months)` | Nothing. Writes an offer whose payment is `monthly_payment(principal, annual_rate, months)`. | | `budget(borrower, limit)` | Nothing. Writes the `Budget` named `borrower`'s `limit` under the source `"budget"`. | | `names_of(values)` | The subjects for which any claim in `values`, a list as `list_values` returns, is `True`, sorted. | | `cheapest_offers()` | The offers with no cheaper one among those of their borrower and principal, sorted. Equal totals are each in the list. | | `unaffordable_offers()` | The offers whose payment is over their borrower's limit, sorted. | | `total(name)` | An offer's total; 0.0 before the facts are written. Refuses while two values are in force. | | `unsettled()` | Each offer and budget that holds two different values in force for a field you write: an offer's `borrower`, `principal`, `payment` or `months`, or a budget's `limit`. Given as `offer` or `budget`, its name and the field, `offer a payment`, sorted. | | `monthly_payment(principal, annual_rate, months)` | The amortised payment, `P i / (1 - (1 + i)^-n)` with `i` the annual rate over 12, and `P / n` for a rate of zero. `1 - (1 + i)^-n` is taken as `-expm1(-n log1p(i))`, which keeps the digits the plain form loses where the power is near 1; where the payment is not a normal real, it is worked on the mantissas and exponents `math.frexp` gives. Zero months is refused with a division by zero, and fewer with `ValueError`. Not rounded to the cent. | | `compound_amount(present, annual_rate, periods_per_year, years)` | What a sum grows to, `P (1 + r/n)^(n t)`, for `n` above 0, others refused with `ValueError`; a sum of 0 stays 0. Where `n t` is too small for a real, the power is `((1 + r/n)^n)^t`. Where the sum is not a normal real while `P` is a real and `1 + r/n` above 0, it is `P e^(n t log1p(r/n))`, `log1p(r/n)` being `ln r - ln n` where `r/n` passes the largest real. | | `effective_annual_rate(annual_rate, periods_per_year)` | The annual rate equal to a nominal one compounded `n` times a year, `(1 + r/n)^n - 1`, for `n` above 0, others refused with `ValueError`. It is taken as `expm1(n log1p(r/n))`, which never forms the number near 1 that the plain form subtracts 1 from: for `n` of 1, 0.12 gives 0.12. A rate that loses all of a sum in a period gives -1, and one that loses more is refused with a math domain error. Where `r/n` passes the largest real, `log1p(r/n)` is `ln r - ln n`, and where it is below the smallest normal real, the rate is `expm1(r)`. | | `continuous_annual_rate(annual_rate)` | The limit as the periods grow without bound, `e^r - 1`, taken as `expm1(r)`. | | `doubling_exact(percent)` | The years to double at a rate in percent, `ln(2) / ln(1 + r/100)`. A rate of zero is refused with a division by zero, and -100 percent with a math domain error. | | `doubling_rule_of_72(percent)` | The rule of 72, `72 / r` for a rate in percent; it suits 6 to 10 percent. | | `present_value(future, annual_rate, years)` | A future sum discounted to now, `F / (1 + r)^t`; where that is not a normal real while `F` is a real and `1 + r` above 0, `F e^(-t log1p(r))`. | | `todays_value(nominal, inflation, years)` | A nominal sum in today's money after some years of a steady inflation, `N / (1 + inflation)^t`, kept in range as `present_value` is. | | `real_rate(nominal_rate, inflation)` | The real rate by the exact Fisher form, `(1 + i) / (1 + pi) - 1`; the approximation `i - pi` is slightly higher. | ### 3.81 `food` — declared fields **`food` is not food-safety or medical advice.** It states published guidance as data and rules over the facts you record, and arithmetic with published conversions. A temperature in it is a figure from a chart: whether a food is safe to eat is decided by the cook, with a thermometer that reads the food, and whether an ingredient is safe for a person with an allergy is decided by that person and their doctor. A dish it does not mark unsafe is not thereby safe, and a dish it does not mark as holding an allergen holds none only of the ingredients you recorded. It gives no diagnosis. Ask a clinician about an allergy. The writing scripts of §3.83 write `Standard` under the source `"standard"`, `Dish` under `"dish"`, `Item` under `"item"` and `Line` under `"line"`, and you may write the same fields yourself. A **standard** is a minimum internal temperature in Celsius named by a kind of food, a **dish** a cooked dish named by you, an **item** an ingredient named by you, and a **line** an item used in a dish. A dish is judged against the standard whose name is its `kind`. **`Standard`** | Field | Class | Notes | |---|---|---| | `minimum` | `real` | The minimum internal temperature in Celsius. Written by `standard()`, which converts the chart's Fahrenheit exactly. | **`Dish`** | Field | Class | Notes | |---|---|---| | `kind` | `string` | The name of the standard it is judged against. Written by `dish()`. | | `core` | `real` | The temperature its core reached, in Celsius. Written by `dish()`. | | `minutes` | `real` | The minutes it spent in the danger zone. Written by `dish()`. | | `undercooked` | `bool` | Concluded by a rule (§3.82): the kind has a standard and the core is below it. Never written. | | `held_too_long` | `bool` | Concluded by a rule (§3.82): more than two hours in the danger zone. Never written. | | `unsafe` | `bool` | Concluded by a rule (§3.82): either cause. Never written. | | `unknown` | `bool` | Concluded by a rule (§3.82): the kind has no standard recorded. Never written. | | `milk`, `egg`, `fish`, `shellfish`, `tree_nuts`, `peanuts`, `wheat`, `soybeans`, `sesame` | `bool` | Concluded by a rule each (§3.82): a line of the dish uses an item that holds the allergen. Never written. | **`Item`** | Field | Class | Notes | |---|---|---| | `milk`, `egg`, `fish`, `shellfish`, `tree_nuts`, `peanuts`, `wheat`, `soybeans`, `sesame` | `bool` | Whether the ingredient holds the allergen. All nine are written by `item()`: `True` for those you name and `False` for the rest. | **`Line`** | Field | Class | Notes | |---|---|---| | `dish` | `string` | The name of the dish. Written by `line()`. | | `item` | `string` | The name of the item. Written by `line()`. | `food` declares no derived field. Everything it knows about a dish is concluded by the rules of §3.82, and the chart's figures are facts that `chart()` and `standard()` write. ### 3.82 `food` — standing rules Each holds continuously, as in §3.17. A rule over a dish and a standard binds them as `d` and `s`, and a rule over a dish, a line and an item as `d`, `l` and `i`. | Rule | Over | Concludes | While | |---|---|---|---| | `undercooked_dish` | `Dish`, `Standard` | `undercooked` | the dish's `kind` is the standard and its `core` is below the standard's `minimum`; concludes `True` | | `held_too_long_dish` | `Dish` | `held_too_long` | the dish's `minutes > 120.0`; concludes `True` | | `unsafe_for_cooking` | `Dish` | `unsafe` | the dish's `undercooked` is `True`; concludes `True` | | `unsafe_for_holding` | `Dish` | `unsafe` | the dish's `held_too_long` is `True`; concludes `True` | | `unknown_kind` | `Dish` | `unknown` | no standard of the dish's `kind` has a `minimum > -1000.0`, which is to say a recorded one; concludes `True` | | `holds_milk` | `Dish`, `Line`, `Item` | `milk` | a line's `dish` is the dish, its `item` is the item, and the item's `milk` is `True`; concludes `True` | | `holds_egg` | `Dish`, `Line`, `Item` | `egg` | a line's `dish` is the dish, its `item` is the item, and the item's `egg` is `True`; concludes `True` | | `holds_fish` | `Dish`, `Line`, `Item` | `fish` | a line's `dish` is the dish, its `item` is the item, and the item's `fish` is `True`; concludes `True` | | `holds_shellfish` | `Dish`, `Line`, `Item` | `shellfish` | a line's `dish` is the dish, its `item` is the item, and the item's `shellfish` is `True`; concludes `True` | | `holds_tree_nuts` | `Dish`, `Line`, `Item` | `tree_nuts` | a line's `dish` is the dish, its `item` is the item, and the item's `tree_nuts` is `True`; concludes `True` | | `holds_peanuts` | `Dish`, `Line`, `Item` | `peanuts` | a line's `dish` is the dish, its `item` is the item, and the item's `peanuts` is `True`; concludes `True` | | `holds_wheat` | `Dish`, `Line`, `Item` | `wheat` | a line's `dish` is the dish, its `item` is the item, and the item's `wheat` is `True`; concludes `True` | | `holds_soybeans` | `Dish`, `Line`, `Item` | `soybeans` | a line's `dish` is the dish, its `item` is the item, and the item's `soybeans` is `True`; concludes `True` | | `holds_sesame` | `Dish`, `Line`, `Item` | `sesame` | a line's `dish` is the dish, its `item` is the item, and the item's `sesame` is `True`; concludes `True` | `food` declares no standing constraint. Eight notes that are contract rather than commentary: - **A kind with no standard is unknown, never safe.** `unknown` says that no standard was recorded to conclude from. An empty `unsafe` means that no rule concluded it, and a dish this module does not mark unsafe is not thereby safe. The test that a kind has a standard reads the standard's own `minimum`, so a kind nothing has been recorded for is unknown whether or not the dish names it. - **The chart's rows are the standards `chart()` writes.** Eleven kinds: `steak`, `ground`, `poultry`, `egg-dish`, `casserole`, `ham-raw`, `ham-precooked`, `ham-packaged`, `leftovers`, `rabbit-venison` and `fish`. A `casserole` is one with meat or poultry, or meatless: the chart gives both at 165 F. `ham-precooked` is precooked ham reheated, 165 F, and `ham-packaged` is cooked ham packaged in a USDA-inspected plant and reheated, 140 F, the chart's note to that row; a ham of the second kind recorded under the first kind is judged against 165. The rows that give no temperature (shrimp, lobster, crab and scallops until opaque, clams, oysters and mussels until the shells open, raw eggs until firm) are not in it, and the rest time of three minutes for a steak, a roast or a chop is a second fact that is not a rule here. - **The figures are converted exactly and not rounded.** A standard is written from the chart's Fahrenheit by `(f - 32) * 5 / 9`, so 145 F is 62.77777777777778 and 165 F is 73.88888888888889, where the chart prints 63 and 74. A core of 63 does not fall below the standard of a steak. - **The temperatures are FoodSafety.gov's.** They are the chart "Cook to a Safe Minimum Internal Temperature" (`https://www.foodsafety.gov/food-safety-charts/safe-minimum-internal-temperatures`), whose page reads "Date Last Reviewed November 21, 2024". They were read from a copy of that page downloaded on 2026-11-09, because an automated fetch of the agency's sites was refused. Check them against the agency that governs your kitchen. - **The danger zone is held as two ranges.** `danger_zone()` names the USDA's, 4 to 60 Celsius, and the United Kingdom's, 8 to 63; agencies define it differently. The two hours of the rule are the limit of the minutes a dish spent there, and a dish with exactly 120 minutes is not held too long. - **An item you never described is unknown, not free.** `item()` writes all nine allergen facts, so an item described as holding wheat is free from the other eight, and an item with no description holds nothing the rules can see. A dish holds an allergen only of the items recorded, so a dish with a line for an item never described may hold more than the module says. - **A dish that exists only through its lines has no kind.** The rules conclude its allergens, and it is `unknown`, since there is no kind to look up. - **A correction withdraws what rested on it, and a disagreement is reasoned about.** A core temperature written again above its minimum withdraws `unsafe`, and an ingredient replaced withdraws the allergen it brought. When two sources give a core two values, every value is reasoned about, and a dish is unsafe if any value puts it there. `unsettled()` names the fact. The module does not cover a cooling curve, a rest, nutrients beyond the four of `food_energy`, cooking losses or yields. ### 3.83 `food` — queries Called by name after `import food`. The first five write facts and answer nothing. `danger_zone` returns a value and writes nothing. The next five read what the rules concluded, two of them helpers, and `unsettled()` names what is in disagreement. The last six are value scripts that return a value and write nothing. Floats are IEEE doubles, and each result agrees with CPython's. A density is a number you supply: the module holds none. | Query | Answers | |---|---| | `standard(kind, minimum_fahrenheit)` | Nothing. Writes the `Standard` named `kind`'s `minimum` from the Fahrenheit figure, converted exactly, under the source `"standard"`. | | `chart()` | Nothing. Writes the eleven standards of the chart that give a temperature (§3.82). | | `dish(name, kind, core_celsius, minutes_in_zone)` | Nothing. Writes the `Dish` named `name`'s `kind`, `core` and `minutes` under the source `"dish"`. Written again it corrects them. | | `item(name, allergens)` | Nothing. Writes all nine allergen facts of the `Item` named `name`, `True` for those in the list and `False` for the rest. A name that is not one of the nine is refused. | | `line(name, dish_name, item_name)` | Nothing. Writes the `Line` named `name`: the item is used in the dish. | | `danger_zone(agency)` | `[low, high]` in Celsius of the danger zone as the agency defines it: `[4.0, 60.0]` for `"usda"` and `[8.0, 63.0]` for `"uk"`. Any other name is refused. Writes nothing. | | `holds(values, name)` | Whether any claim in `values`, a list as `list_values` returns, is `True` for the subject `name`. | | `names_of(values)` | The subjects for which any claim in `values` is `True`, sorted. | | `unsafe_dishes()` | The dishes the rules conclude unsafe, for either cause, sorted. | | `unknown_dishes()` | The dishes whose kind has no standard recorded, sorted. | | `allergens_of(name)` | The allergens the rules conclude a dish holds, in the order `milk`, `egg`, `fish`, `shellfish`, `tree_nuts`, `peanuts`, `wheat`, `soybeans`, `sesame`; empty for a dish with none. | | `unsettled()` | Each standard, dish, item and line that holds two different values in force for a field you write: a standard's `minimum`, a dish's `kind`, `core` or `minutes`, an item's nine allergens, or a line's `dish` or `item`. Given as its kind in lower case, its name and the field, `dish d1 core`, sorted. | | `fahrenheit_to_celsius(fahrenheit)` | `(f - 32) * 5 / 9`, in that order; `(f - 32) / 9 * 5` where `(f - 32) * 5` passes the largest real. | | `scale_by_servings(quantity, from_servings, to_servings)` | A quantity for one number of servings, for another: `quantity * to / from`; where that is not a normal real, the same worked on the mantissas and exponents `math.frexp` gives. | | `bakers_percentage(part, flour)` | An ingredient's weight as a percentage of the flour's, `100 * part / flour`; the flour is 100 and the water's is the hydration, kept in range as `scale_by_servings` is. A flour of zero is refused with a division by zero. | | `volume_to_mass(cups, density_grams_per_ml)` | Grams for a volume in US customary cups of 236.5882365 millilitres, by a density in grams per millilitre that you supply, kept in range as `scale_by_servings` is. | | `food_energy(protein_g, carbohydrate_g, fat_g, alcohol_g)` | Kilocalories by the labelling table's approximate factors: 4 for protein, 4 for carbohydrate, 9 for fat and 7 for alcohol. | | `kilocalories_to_kilojoules(kilocalories)` | One kilocalorie is 4.184 kilojoules. | ### 3.84 `architecture` — declared fields **`architecture` is not engineering, naval-architecture, acoustic-design or heritage advice.** It states published definitions and simple models as rules over the facts you record. A tower in it is a straight column of even weight, a hull is a box, and a room is Sabine's equation: whether a real structure is safe, a real ship stable or a real hall good for music is decided by those who survey, test and certify it. A style is a family resemblance that a rule makes strict, and a record of height is a verdict over the records you wrote. The writing scripts of §3.87 write `Building` under the source `"building"`, `Structure` under `"structure"`, `Tower` under `"tower"`, `Hull` under `"hull"`, `Room` under `"room"`, `Surface` under `"surface"` and `Channel` under `"channel"`, and `Fall` under the source you name; you may write the same fields yourself. A **building** is a building with the features recorded for it, a **structure** anything with a height and a year of completion, a **tower** a column with a lean, a **hull** a ship's hull taken as a box, a **room** a volume with a range of reverberation times wanted, a **surface** an area lining a room, and a **channel** a watercourse with a fall; each is named by you. A **fall** is a standard, a minimum gradient, named by its name, and a channel is judged against the fall whose name is its `standard`. Lengths are in metres, except a channel's, which are in any one unit. **`Building`** | Field | Class | Notes | |---|---|---| | `pointed_arch`, `rib_vault`, `flying_buttress`, `round_arch`, `thick_walls`, `barrel_vault`, `groin_vault`, `dome`, `pendentives` | `bool` | Whether the building has the feature. All nine are written by `building()`: `True` for those you name and `False` for the rest. | | `gothic` | `bool` | Concluded by a rule (§3.86): pointed arches, rib vaults and flying buttresses. Never written. | | `romanesque` | `bool` | Concluded by two rules (§3.86): round arches and thick walls, with a barrel vault or a groin vault. Never written. | | `pendentive_dome` | `bool` | Concluded by a rule (§3.86): a dome and pendentives. Never written. | **`Structure`** | Field | Class | Notes | |---|---|---| | `height` | `real` | Its height in metres. Written by `structure()`. | | `completed` | `real` | The year it was completed, negative before the common era. Written by `structure()`. | | `until` | `real` | The year it fell, or the part of it that made its height. `structure()` writes 10000.0, standing, and `fell()` writes the year. | | `building` | `bool` | Whether it is a building. Written by `structure()`. | | `tallest_structure` | `bool` | Concluded by a rule (§3.86): it was the tallest structure recorded when it was completed. Never written. | | `tallest_building` | `bool` | Concluded by a rule (§3.86): it was the tallest building recorded when it was completed. Never written. | | `undated` | `bool` | Concluded by a rule (§3.86): it has a height and no year of completion. Never written. | **`Tower`** | Field | Class | Notes | |---|---|---| | `height` | `real` | Its height in metres. Written by `tower()`. | | `offset` | `real` | Its top's distance from the vertical, in metres. Written by `tower()`. | | `base` | `real` | Its base's outer diameter, in metres. Written by `tower()`. | | `shift` | `real` | Computed from `offset` (§3.85). Never written. | | `radius` | `real` | Computed from `base` (§3.85). Never written. | | `tips` | `bool` | Concluded by a rule (§3.86): the shift passes the radius. Never written. | **`Hull`** | Field | Class | Notes | |---|---|---| | `beam` | `real` | Its breadth, in metres. Written by `hull()`. | | `draught` | `real` | Its depth in the water, in metres. Written by `hull()`. | | `kg` | `real` | The height of its centre of gravity above the keel, in metres. Written by `hull()`. | | `kb`, `bm`, `gm` | `real` | Computed (§3.85). Never written. | | `unstable` | `bool` | Concluded by a rule (§3.86): the metacentric height is not positive. Never written. | **`Room`** | Field | Class | Notes | |---|---|---| | `volume` | `real` | Its volume in cubic metres. Written by `room()`. | | `low` | `real` | The shortest reverberation time wanted, in seconds. Written by `room()`. | | `high` | `real` | The longest reverberation time wanted, in seconds. Written by `room()`. | | `surfaces` | `int` | Concluded by a rule (§3.86): how many of the room's surfaces have `sabins`. Never written. | | `claims` | `int` | Concluded by a rule (§3.86): how many claims of `sabins` they hold. Never written. | | `disputed` | `bool` | Concluded by a rule (§3.86): `claims` is greater than `surfaces`. Never written. | | `absorption` | `real` | Concluded by a rule (§3.86): the sum of the `sabins` of the room's surfaces. Never written. | | `rt` | `real` | Computed from `volume` and `absorption` (§3.85). Never written. | | `too_live` | `bool` | Concluded by a rule (§3.86): the time is longer than `high`. Never written. | | `too_dead` | `bool` | Concluded by a rule (§3.86): the time is shorter than `low`. Never written. | | `unmeasured` | `bool` | Concluded by a rule (§3.86): the room has a volume and no surface. Never written. | **`Surface`** | Field | Class | Notes | |---|---|---| | `room` | `string` | The name of the room it lines. Written by `surface()`. | | `area` | `real` | Its area in square metres. Written by `surface()`. | | `coefficient` | `real` | Its absorption coefficient, as you give it. Written by `surface()`. | | `sabins` | `real` | Computed from `area` and `coefficient` (§3.85). Never written. | **`Fall`** | Field | Class | Notes | |---|---|---| | `minimum` | `real` | The minimum gradient, a drop over a length. Written by `fall()` under the source you name; `vitruvius()` writes two values of it. | **`Channel`** | Field | Class | Notes | |---|---|---| | `length` | `real` | Its length. Written by `channel()`. | | `drop` | `real` | Its drop over that length, in the same unit. Written by `channel()`. | | `standard` | `string` | The name of the fall it is held to. Written by `channel()`. | | `gradient` | `real` | Computed from `drop` and `length` (§3.85). Never written. | | `too_flat` | `bool` | Concluded by a rule (§3.86): the gradient is below the standard's minimum. Never written. | | `no_standard` | `bool` | Concluded by a rule (§3.86): no fall of that name has a minimum recorded. Never written. | ### 3.85 `architecture` — derived fields | Field | Definition | |---|---| | `Tower.shift` | `offset / 2.0` | | `Tower.radius` | `base / 2.0` | | `Hull.kb` | `draught / 2.0` | | `Hull.bm` | `beam * beam / (12.0 * draught)` | | `Hull.gm` | `(0.5 * kb + 0.5 * bm - 0.5 * kg) * 2.0` | | `Room.rt` | `0.161 * volume / absorption` | | `Surface.sabins` | `area * coefficient` | | `Channel.gradient` | `drop / length` | `shift` is the distance of a tower's centre of mass from the vertical, on the model of a straight tower of even weight: half the top's. `radius` is half the base's outer diameter. `kb` is the height of a hull's centre of buoyancy above the keel, `bm` the distance from it to the metacentre, and `gm` the metacentric height, the distance from the centre of gravity to the metacentre. For a box the centre of buoyancy is half the draught and BM is the beam squared over twelve times the draught; those two forms are this module's derivation from KM = KB + BM and BM = I/V, not a published formula. `gm` is `kb + bm - kg` taken of halves and doubled, which changes no digit of it and keeps a sum past the largest real from making it one. `bm` is a real for any beam and draught from `10^-150` to `10^150` metres, which is the range the class states. `rt` is Sabine's reverberation time, `0.161 V / A` in seconds; the constant is given as about 0.1611 elsewhere, and the module uses 0.161. `sabins` is a surface's absorption in square metres, and `gradient` a channel's drop over its length. Each is absent until the fields it reads are present, and all are `real`. `rt` reads `absorption`, which a rule concludes, so it follows the surfaces: a surface added or corrected moves it. A zero divisor draws no value: a hull of zero draught has no `bm` and no `gm`, a channel of zero length no `gradient`, and a room whose surfaces absorb nothing no `rt`. No rule concludes from a field with no value, and `why_not` says that nothing is recorded there. ### 3.86 `architecture` — standing rules Each holds continuously, as in §3.17. A rule over a building binds it as `b`, a structure as `s` and those it is compared with as `o`, a tower as `t`, a hull as `h`, a room as `r` and its surfaces as `s`, and a channel as `c` and its standard as `f`. | Rule | Over | Concludes | While | |---|---|---|---| | `gothic_building` | `Building` | `gothic` | the building's `pointed_arch`, `rib_vault` and `flying_buttress` are `True`; concludes `True` | | `romanesque_barrel_vault` | `Building` | `romanesque` | the building's `round_arch`, `thick_walls` and `barrel_vault` are `True`; concludes `True` | | `romanesque_groin_vault` | `Building` | `romanesque` | the building's `round_arch`, `thick_walls` and `groin_vault` are `True`; concludes `True` | | `dome_on_pendentives` | `Building` | `pendentive_dome` | the building's `dome` and `pendentives` are `True`; concludes `True` | | `tallest_structure_when_completed` | `Structure` | `tallest_structure` | the structure's `height > 0.0` and `completed > -1000000.0`, which is to say a recorded one, and no structure completed in that year or before it still stood after it and is taller; concludes `True` | | `tallest_building_when_completed` | `Structure` | `tallest_building` | the structure's `building` is `True`, its `height > 0.0` and `completed > -1000000.0`, and no building completed in that year or before it still stood after it and is taller; concludes `True` | | `undated_structure` | `Structure` | `undated` | the structure's `height > 0.0` and it has no `completed`; concludes `True` | | `tower_tips` | `Tower` | `tips` | the tower's `shift` is greater than its `radius`; concludes `True` | | `unstable_hull` | `Hull` | `unstable` | the hull's `gm <= 0.0`; concludes `True` | | `room_claims` | `Room`, `Surface` | `claims` | a surface's `room` is the room and its `sabins > -1.0e300`; concludes the number of claims of `sabins` those surfaces hold | | `room_surfaces` | `Room`, `Surface` | `surfaces` | a surface's `room` is the room and its `sabins > -1.0e300`; concludes the number of distinct such surfaces | | `room_disputed` | `Room` | `disputed` | the room's `claims` is greater than its `surfaces`; concludes `True` | | `room_absorption` | `Room`, `Surface` | `absorption` | a surface's `room` is the room and the room has no `disputed`; concludes the sum of the `sabins` of those surfaces | | `room_too_live` | `Room` | `too_live` | the room's `rt` is greater than its `high`; concludes `True` | | `room_too_dead` | `Room` | `too_dead` | the room's `rt` is less than its `low`; concludes `True` | | `room_unmeasured` | `Room` | `unmeasured` | the room's `volume > 0.0` and no surface whose `room` is the room has an `area > -1.0`, which is to say a recorded one; concludes `True` | | `channel_too_flat` | `Channel`, `Fall` | `too_flat` | the channel's `standard` is the fall, the fall's `minimum > -1.0`, which is to say a recorded one, and the channel's `gradient` is less than it; concludes `True` | | `channel_without_standard` | `Channel` | `no_standard` | no fall named by the channel's `standard` has a `minimum > -1.0`; concludes `True` | `architecture` declares no standing constraint. Nine notes that are contract rather than commentary: - **A style is three features, and a building never described is unknown.** `building()` writes all nine features, so a building you described lacks what you did not name, and `why_not` names the feature that is `False`. A building with no facts has no style, and `why_not` says that nothing is recorded there. Gothic's definition names four features, and the rule takes the three that are parts of the structure; the fourth is its windows. A pendentive is a device and not a period, so `pendentive_dome` is a form and not a style, and a building may have both. - **A record is judged over the records you wrote.** A structure is the tallest when it was completed if no structure you recorded was completed in that year or before it, still stood after it and was taller; one that is not recorded cannot end a record. A structure stands in every year before its `until`. A year before the common era is written negative, as -2570 for 2570 BC, and is compared like any other. `tallest_building` asks the same among buildings only, so a monument or a tower that is not a building ends a structure's record and not a building's. The rules ask which structure was the tallest when it was completed: one that became the tallest later, when taller ones fell, is not concluded. Recorded as the list of the tallest structures built before the twentieth century gives them, Cologne Cathedral is the tallest structure until the Washington Monument of 1884 and the tallest building until Ulm Minster of 1890. - **A record with no year is undated and never ranked.** With no year, nothing could be completed before it, so it would be concluded the tallest, and nothing could be ended by it. `undated` marks it, and writing its year ranks it. - **A fall is a correction.** `fell()` writes `until`, and a record that a taller structure ended only while it stood is concluded once the fall is written. A fall in the year another structure was completed does not end that structure's record. - **The tower model sees the structure and not the ground.** On the model, a straight tower of even weight tips when its centre of mass, half the top's offset, passes the edge of its base; a shift exactly at the radius does not tip. Whether a real tower stands depends also on the ground under it, which the model does not see. - **GM is initial stability.** It measures how a hull resists heel at small angles, where the metacentre can be taken as fixed; stability at large angles is not modelled here. A hull with a GM of exactly zero is `unstable`, and ballast that lowers `kg` withdraws the verdict. - **A room is judged by its surfaces.** `absorption` is the exact sum of its surfaces' sabins, rounded once, so the order in which the surfaces were written does not move it. A room with no surface is `unmeasured` and has no `rt`, so it is neither too live nor too dead. A time exactly at an end of the range is inside it. Sabine's equation is the module's whole acoustics; Eyring's, which the literature gives for small rooms with much absorption, is not here. - **Vitruvius's minimum is held as two values.** `vitruvius()` writes the two readings the sources give, half a foot in a hundred and one in 4,800, as two values of one fact. A channel is too flat if any value in force puts it there, so a channel marked too flat is too flat under at least one reading, and a channel not marked is within all of them. `unsettled()` names `fall vitruvius minimum`. A channel whose standard has no value is `no_standard`, never within it. - **A correction withdraws what rested on it, and a disagreement is reasoned about.** A fact written again withdraws the conclusions that rested on its old value. When two sources give a fact two values, every value is reasoned about. A verdict a rule concludes from what it finds holds under any of them, as a style, an unstable hull or a flat channel does. A verdict a rule concludes from what it does not find holds only if nothing is found under any of them: a taller value of any height ends a record, and a structure whose own height holds two values is never the tallest, since under one of them it is taller than under the other. `unsettled()` names the fact, and `record_until()` refuses while a fact it reads holds two values. A sum reads every value too, so a surface whose `sabins` holds two values would be added twice to its room's `absorption`; `surfaces` and `claims` count the surfaces and their claims over the one binding the sum reads, and while the claims are more the room is `disputed` and has no `absorption`, `rt` or verdict. A surface with no `sabins` is in neither count, and one whose `room` holds two values lines each room it names, each absorption being one source's. A conclusion over a group-wise absence names, in `why_not`, a field of the form `__none1` that is "to be absent, and it is present": it means that something the rule asks to be missing was found, as the [Python Specification §14.2](/spec/dke/python/) defines it. The module does not cover loads, materials or foundations, wind or earthquakes, stability at large angles of heel, hull forms other than a box, Eyring's or any other reverberation formula, the frequency of a reverberation time, or the flow of water in a channel. ### 3.87 `architecture` — queries Called by name after `import architecture`. The first ten write facts and answer nothing. The next seventeen read what the rules concluded, three of them helpers, and `unsettled()` names what is in disagreement. The last eight are value scripts that return a value and write nothing. Floats are IEEE doubles. Results are not rounded. Each step is rounded once: `math.atan` and `math.tan` are correctly rounded, and `math.degrees` and `math.radians` give a·180/π and a·π/180 rounded once. A lean or an offset can therefore differ from CPython's in the last place, where CPython rounds twice or its library misses the correctly rounded value: `lean_degrees(1.0, 14.0)` is 4.085616779974876 here and 4.085616779974877 in CPython 3.11. Every other script gives CPython's digits. | Query | Answers | |---|---| | `building(name, features)` | Nothing. Writes all nine features of the `Building` named `name`, `True` for those in the list and `False` for the rest, under the source `"building"`. A name that is not one of the nine is refused. | | `structure(name, height, completed, is_building)` | Nothing. Writes the `Structure` named `name`'s `height`, `completed` and `building`, and its `until` as 10000.0, standing, under the source `"structure"`. Written again it corrects them and writes the structure standing, so `fell()` comes after it. | | `fell(name, year)` | Nothing. Writes the `Structure` named `name`'s `until`, the year it fell, under the source `"structure"`. | | `tower(name, height, offset, base)` | Nothing. Writes the `Tower` named `name`'s `height`, `offset` and `base` under the source `"tower"`. | | `hull(name, beam, draught, kg)` | Nothing. Writes the `Hull` named `name`'s `beam`, `draught` and `kg` under the source `"hull"`. | | `room(name, volume, low, high)` | Nothing. Writes the `Room` named `name`'s `volume`, `low` and `high` under the source `"room"`. | | `surface(name, room_name, area, coefficient)` | Nothing. Writes the `Surface` named `name`'s `room`, `area` and `coefficient` under the source `"surface"`. | | `fall(standard, minimum, source)` | Nothing. Writes the `Fall` named `standard`'s `minimum` under the source you name. A second source that gives another value writes a second value of the same fact. | | `vitruvius()` | Nothing. Writes the `Fall` named `"vitruvius"` twice: `0.5 / 100.0` under the source `"half-a-foot-in-a-hundred"` and `1.0 / 4800.0` under `"one-in-4800"`. | | `channel(name, length, drop, standard)` | Nothing. Writes the `Channel` named `name`'s `length`, `drop` and `standard` under the source `"channel"`. | | `names_of(values)` | The subjects for which any claim in `values`, a list as `list_values` returns, is `True`, sorted. | | `styles_of(name)` | The styles and forms the rules conclude for a building, in the order `gothic`, `romanesque`, `pendentive_dome`; empty for a building with none. | | `tallest_structures()` | The structures that were the tallest when they were completed, sorted. | | `tallest_buildings()` | The buildings that were the tallest building when they were completed, sorted. | | `undated_structures()` | The structures with a height and no year of completion, sorted. | | `reals(values)` | A dict from each subject in `values` to its number. A subject that holds two different values is refused, and so is a value that is not a number. | | `record_until(name, buildings_only)` | The year a record passed: the earlier of the year the structure fell and the year a taller one was completed after it, over all structures, or over buildings when `buildings_only` is `True`. 10000.0 when nothing you recorded passed it and it stands: passed by nothing recorded, not held for ever. A structure that was not the tallest when it was completed is refused, and so is any call while a structure's height, year of completion, year of falling or building flag holds two values, since any of them can move the year. | | `tipping_towers()` | The towers whose `shift` passes their `radius`, sorted. | | `unstable_hulls()` | The hulls whose `gm` is not positive, sorted. | | `live_rooms()` | The rooms whose `rt` is longer than their `high`, sorted. | | `dead_rooms()` | The rooms whose `rt` is shorter than their `low`, sorted. | | `disputed_rooms()` | The rooms with `disputed`, sorted. | | `unmeasured_rooms()` | The rooms with a volume and no surface, sorted. | | `flat_channels()` | The channels whose gradient is below their standard's minimum under at least one of its values, sorted. | | `channels_without_standard()` | The channels whose standard has no minimum recorded, sorted. | | `disputes(values, noun)` | The facts in `values` that hold two different values, each as `noun`, the subject and the field; the helper `unsettled()` is built on. | | `unsettled()` | Each building, structure, tower, hull, room, surface, fall and channel that holds two different values in force for a field you write: a building's nine features, a structure's `height`, `completed`, `until` or `building`, a tower's `height`, `offset` or `base`, a hull's `beam`, `draught` or `kg`, a room's `volume`, `low` or `high`, a surface's `room`, `area` or `coefficient`, a fall's `minimum`, or a channel's `length`, `drop` or `standard`. Given as its kind in lower case, its name and the field, `fall vitruvius minimum`, sorted. | | `lean_degrees(offset, height)` | A lean in degrees from the top's offset and the height, `degrees(atan(offset / height))`. A height of zero is refused with a division by zero. | | `top_offset(height, degrees)` | The top's offset for a height and a lean in degrees, `height * tan(radians(degrees))`, the lean taken modulo 360 degrees by `math.fmod` first; where the product is not a normal real, it is worked on the mantissas and exponents `math.frexp` gives. | | `reverberation_time(volume, absorption)` | Sabine's time in seconds, `0.161 * volume / absorption`, the volume in cubic metres and the absorption in sabins. An absorption of zero is refused with a division by zero. | | `metacentric_height(beam, draught, kg)` | A box hull's GM, `draught / 2 + beam * beam / (12 * draught) - kg`, taken of halves and doubled as `Hull.gm` is, so that it is that field to the last digit; where `beam * beam / (12 * draught)` is not a normal real, its half is worked on the mantissas and exponents `math.frexp` gives. A draught of zero is refused with a division by zero. | | `gradient(length, drop)` | A channel's gradient, `drop / length`. A length of zero is refused with a division by zero. | | `one_in(length, drop)` | The gradient as one in N, `length / drop`: a drop of 0.025 in 456 is one in 18240.0. A drop of zero is refused with a division by zero. | | `pendulum_period(length)` | A pendulum's period in seconds for a length in metres, at standard gravity and for a small swing, `2 pi sqrt(length / 9.80665)`. A negative length is refused with a math domain error. | | `pendulum_length(period)` | The length in metres of a pendulum with a period in seconds, at standard gravity and for a small swing, `9.80665 * (period / (2 pi))^2`. | ### 3.88 `elections` — declared fields **`elections` is not legal or electoral advice.** It states published counting methods as rules and calculations over the ballots and populations you record. It certifies no election and counts no real ballot for anyone: which method an election uses, who may vote and what a ballot says are decided by the law and the officials who run it. A winner in it is a verdict over the numbers you wrote, under the method named. The writing scripts of §3.91 write `Election`, `Candidate` and `Duel` under the source `"election"` and `Ballot` and `Pref` under `"ballot"`; `recount()` writes a ballot's `count` under the source you name. You may write the same fields yourself. An **election** is named by you and has two candidates or more; a **candidate** is named by you and stands in one election, and a candidate's name is its own across all your elections; a **ballot** is the ranking of every candidate of one election, first to last, with the number of voters who cast it; a **preference** records, for one ballot and one pair of candidates, which of the two the ballot ranks higher; a **duel** is one ordered pair of the candidates of an election, `a` against `b`. `election()` also writes, for each election, a ballot named by the election's name and `__baseline`, of no voters, so that an election has a total and a tally for every duel before its first ballot is written. Counts are numbers of voters. **`Election`** | Field | Class | Notes | |---|---|---| | `candidates` | `real` | How many candidates it has. Written by `election()`. | | `total` | `real` | Concluded by a rule (§3.90): the voters over all its ballots. Never written. | | `matches`, `firstclaims`, `rankclaims`, `ballots` | `real` | Concluded by rules (§3.90): the counts that `disputed` compares. Never written. | | `disputed` | `bool` | Concluded by three rules (§3.90): a ballot holds a second claim on its count, ranking or first choice. Never written. | | `no_condorcet` | `bool` | Concluded by a rule (§3.90): no candidate beats every other head to head. Never written. | **`Candidate`** | Field | Class | Notes | |---|---|---| | `election` | `string` | The name of the election it stands in. Written by `election()`. | | `firsts` | `real` | Concluded by a rule (§3.90): the voters who put it first. Never written. | | `twice` | `real` | Computed from `firsts` (§3.89). Never written. | | `borda` | `real` | Concluded by a rule (§3.90): its Borda score. Never written. | | `plurality`, `majority`, `condorcet`, `condorcet_loser`, `borda_winner` | `bool` | Concluded by rules (§3.90). Never written. | **`Ballot`** | Field | Class | Notes | |---|---|---| | `election` | `string` | The name of the election it is cast in. Written by `ballot()`. | | `first` | `string` | Its first choice. Written by `ballot()`. | | `ranking` | `string` | The candidates' names joined by `>`, first to last. Written by `ballot()`. | | `count` | `real` | The number of voters who cast it. Written by `ballot()`, and by `recount()` under another source. | **`Pref`** | Field | Class | Notes | |---|---|---| | `ballot` | `string` | The name of the ballot. Written by `ballot()`. | | `over` | `string` | The candidate the ballot ranks higher of the pair. Written by `ballot()`. | | `under` | `string` | The candidate it ranks lower. Written by `ballot()`. | **`Duel`** | Field | Class | Notes | |---|---|---| | `election` | `string` | The name of the election. Written by `election()`. | | `a`, `b` | `string` | The two candidates, `a` against `b`. Written by `election()`. | | `ab` | `real` | Concluded by a rule (§3.90): the voters ranking `a` over `b`. Never written. | | `ba` | `real` | Concluded by a rule (§3.90): the voters ranking `b` over `a`. Never written. | | `margin` | `real` | Computed from `ab` and `ba` (§3.89). Never written. | ### 3.89 `elections` — derived fields | Field | Definition | |---|---| | `Candidate.twice` | `firsts * 2.0` | | `Duel.margin` | `ab - ba` | `twice` is twice the voters who put a candidate first, so that a majority, which is more than half of the voters, is a comparison of two numbers with no division. `margin` is the voters who rank `a` over `b` less those who rank `b` over `a`, positive where `a` wins the duel. Each is absent until the fields it reads are present, and both are `real`. No rule concludes from a field with no value, and `why_not` says that nothing is recorded there. ### 3.90 `elections` — standing rules Each holds continuously, as in §3.17. A rule binds an election as `e`, a candidate as `c` and the candidates it is compared with as `o`, a ballot as `b`, a duel as `d` and a preference as `p`. | Rule | Over | Concludes | While | |---|---|---|---| | `first_preferences` | `Candidate`, `Ballot` | `firsts` | a ballot's `first` is the candidate; concludes the sum of those ballots' `count` | | `election_total` | `Election`, `Ballot` | `total` | a ballot's `election` is the election; concludes the sum of those ballots' `count` | | `duel_for` | `Duel`, `Pref`, `Ballot` | `ab` | a preference's `over` is the duel's `a`, its `under` is the duel's `b` and its `ballot` is the ballot; concludes the sum of those ballots' `count` | | `duel_against` | `Duel`, `Pref`, `Ballot` | `ba` | a preference's `over` is the duel's `b`, its `under` is the duel's `a` and its `ballot` is the ballot; concludes the sum of those ballots' `count` | | `borda_score` | `Candidate`, `Duel` | `borda` | a duel's `a` is the candidate; concludes the sum of those duels' `ab` | | `election_matches` | `Election`, `Ballot` | `matches` | a ballot's `election` is the election and it has a `count > -1.0`, which is to say a recorded one; concludes how many such claims there are | | `election_first_matches` | `Election`, `Ballot` | `firstclaims` | a ballot's `election` is the election and its `first` is not `">"`; concludes how many such claims there are | | `election_rank_matches` | `Election`, `Ballot` | `rankclaims` | a ballot's `election` is the election and its `ranking` is not `">"`; concludes how many such claims there are | | `election_ballots` | `Election`, `Ballot` | `ballots` | a ballot's `election` is the election; concludes how many distinct ballots there are | | `election_disputed` | `Election` | `disputed` | the election's `matches` is greater than its `ballots`; concludes `True` | | `election_disputed_first` | `Election` | `disputed` | the election's `firstclaims` is greater than its `ballots`; concludes `True` | | `election_disputed_ranking` | `Election` | `disputed` | the election's `rankclaims` is greater than its `ballots`; concludes `True` | | `plurality_winner` | `Candidate`, `Election` | `plurality` | the election has no `disputed`, the candidate's `firsts > 0.0` and no other candidate of the election has more `firsts`; concludes `True` | | `majority_winner` | `Candidate`, `Election` | `majority` | the election has no `disputed` and the candidate's `twice` is greater than the election's `total`; concludes `True` | | `condorcet_winner` | `Candidate`, `Election` | `condorcet` | the election has no `disputed` and no duel with the candidate as `a` has a `margin <= 0.0`; concludes `True` | | `condorcet_loser` | `Candidate`, `Election` | `condorcet_loser` | the election has no `disputed` and no duel with the candidate as `a` has a `margin >= 0.0`; concludes `True` | | `borda_winner` | `Candidate`, `Election` | `borda_winner` | the election has no `disputed`, the candidate's `borda > 0.0` and no other candidate of the election has a higher `borda`; concludes `True` | | `no_condorcet_winner` | `Election` | `no_condorcet` | the election's `total > 0.0`, it has no `disputed` and no candidate of it has `condorcet` `True`; concludes `True` | `elections` declares no standing constraint. Seven notes that are contract rather than commentary: - **Each method concludes its own winner, and they may differ.** `plurality` is the candidate the most voters put first, `majority` the candidate more than half put first, `condorcet` the candidate who beats every other head to head, and `borda_winner` the candidate with the highest Borda score. A candidate's Borda score is the sum of its head-to-head tallies: over every ballot and every other candidate, the voters who rank it higher, which is the Borda count of n - 1 points for a first place down to 0 for a last. With the four cities of the Tennessee example the sources share, the most voters put Memphis first, and Nashville beats every other city head to head and has the highest Borda score. `condorcet_loser` is the candidate every other beats. - **A tie is no win and no loss.** A duel with a `margin` of zero is neither, so a candidate who ties another head to head is not a Condorcet winner or loser. A tie for the most first choices, or for the highest Borda score, concludes the verdict for each candidate in it. - **A cycle leaves no Condorcet winner.** Where the head-to-head counts run in a cycle, A over B, B over C and C over A, no candidate beats every other and `no_condorcet` is concluded for the election. `without_condorcet_winner()` names it. - **A count in dispute decides nothing.** A rule that adds up a fact adds every value it holds, so a second count of a ballot, from a second source, would be added to the first, and a winner concluded from the total would be the winner under neither count. `recount()` writes such a second count. While any ballot of an election holds a second claim on its count, its ranking or its first choice, `disputed` is concluded for the election, no winner is concluded for it, and its readers refuse; `why_not` on a candidate's verdict names the dispute. Forgetting the claim that is not to stand settles it, and every verdict returns. - **A ballot ranks every candidate once, and writing it again replaces it.** A tied or partial ranking cannot be written. The candidates of an election are fixed once it is written, and a ballot written again under its name with another ranking withdraws what rested on the first. - **The seat methods compare in whole numbers.** `largest_remainder` and `highest_averages` give seats from populations that are whole numbers, and compare only whole numbers, so a tie is found exactly. A tie that more states share than there are seats left to give refuses rather than be broken, as does an instant-runoff tie for last place, since the methods name no way to break one. Huntington-Hill gives every state one seat first, and its comparison of squared populations is exact only up to a population of 3,037,000,499, which larger populations are refused. - **A conclusion over a group-wise absence names, in `why_not`, a field of the form `__none1`** that is "to be absent, and it is present": it means that something the rule asks to be missing was found, as the [Python Specification §14.2](/spec/dke/python/) defines it. A `why` on that cell names the head-to-head count that beats the candidate, and under it each ballot's preference and count. The module does not cover the law of any election, who may vote, what a ballot says, ballots that tie or leave candidates out, write-in or spoiled ballots, runoffs between two rounds of voting, systems that transfer votes beyond the instant-runoff count, or the allocation of seats from ballots rather than from populations. ### 3.91 `elections` — queries Called by name after `import elections`. The first three write facts and answer nothing. The next thirteen read what the rules concluded, five of them helpers, and `runoff` counts the ballots round by round. The last nine write nothing and, but for `checked`, return a value: the quotas, the two seat methods, a priority and four helpers of the seat methods. Floats are IEEE doubles and results are not rounded. | Query | Answers | |---|---| | `election(name, roster)` | Nothing. Writes the `Election` named `name` and its candidates, two or more, each named once, under the source `"election"`, with every duel and preference of the pairs and the election's ballot of no voters. A name that holds `__` or `>` is refused, and so is a candidate named twice, one already standing in another election and an election already written. | | `ballot(name, poll, voters, order)` | Nothing. Writes the `Ballot` named `name` in election `poll`, ranking every candidate of it once in `order`, first to last, cast by `voters`, with the preferences of every pair, under the source `"ballot"`. Written again it replaces. A negative count, an election not written, a candidate not of it and a candidate ranked twice or left out are refused. | | `recount(name, voters, reason)` | Nothing. Writes a second count of the ballot `name` under the source `reason`, which is not `"ballot"`, and so puts its election in dispute until one of the two claims is forgotten. | | `strings(values)` | A dict from each subject in `values`, a list as `list_values` returns, to its string; a value that is not a string is refused. | | `candidates_of(name)` | The candidates of the election `name`, sorted; empty for one not written. | | `names_of(values)` | The subjects for which any claim in `values` is `True`, sorted. | | `disputed_elections()` | The elections whose count is in dispute, sorted. | | `without_condorcet_winner()` | The elections in which no candidate beats every other head to head, sorted. | | `settled(name)` | The candidates of the election `name`, sorted. An election not written, and one whose count is disputed, are refused. | | `chosen(values, names)` | The subjects of `names` for which any claim in `values` is `True`, sorted. | | `winners(name)` | A dict with the keys `plurality`, `majority`, `condorcet`, `condorcet_loser` and `borda`, each the list of the election's candidates the rules conclude it for, sorted. A list is empty where no candidate wins and holds more than one where candidates tie. A disputed election is refused. | | `tallies(values, names)` | A dict from each of `names` to its number in `values`, 0.0 where it has none; a value that is not a number is refused. | | `first_choices(name)` | A dict from each candidate of the election to the voters who put it first. | | `borda_scores(name)` | A dict from each candidate of the election to its Borda score. | | `head_to_head(name)` | A dict from each ordered pair `"a>b"` of the election's candidates to the voters who rank `a` over `b`. | | `runoff(name)` | An instant-runoff count: a list of dicts, one tally per round. Each round every ballot counts for the highest candidate on it still standing, and the candidate with the fewest votes is eliminated, until one stands. A tie for last place is refused. | | `hare_quota(votes, seats)` | The Hare quota, `float(votes) / float(seats)`. Fewer than one seat is refused. | | `droop_quota(votes, seats)` | The exact Droop quota, `float(votes) / float(seats + 1)`. Fewer than one seat is refused. | | `checked(populations, seats)` | Nothing. Refuses a dict with no state, a negative number of seats and a population that is not positive; the helper the seat scripts begin with. | | `largest_remainder(populations, seats)` | Hamilton's method: a dict from each state to its seats. Each state takes the whole part of its share, and the seats left go one each to the largest remainders. A tie for the last seat is refused. | | `wide(x, p)` | `x` times `p` as a list of two ints, the high and the low half of 31 bits each; the helper of `wide_compare`. | | `wide_compare(x, p, y, q)` | 1, 0 or -1 as `x * p` is greater than, equal to or less than `y * q`, compared exactly; the helper of `ahead`. | | `ahead(a, na, b, nb, method)` | 1, 0 or -1 as a state of population `a` holding `na` seats has a higher, an equal or a lower priority for the next seat than one of population `b` holding `nb`, under `method`; the helper of `highest_averages`. | | `highest_averages(populations, seats, method)` | A dict from each state to its seats, given one at a time to the state with the highest priority: its population over 1, 2, 3 and on by `"dhondt"`, over 1, 3, 5 and on by `"sainte_lague"`, and over the square root of n (n + 1) by `"huntington_hill"`, which first gives every state one seat. Any other method, fewer seats than states under Huntington-Hill and a tie for the last seat are refused. | | `priority_value(population, held)` | Huntington-Hill's priority for a state's next seat, `population / sqrt(held * (held + 1))`. A state holding fewer than one seat is refused. | ## 4. `dkepy` The Python package a customer installs to write facts. **Distribution name `dkepy`; import name `dke`.** They differ because `dke` is taken on PyPI, and neither may change casually — both appear in customer code. `dkepy` is **not** required. It is one conformant producer, published so that you have a worked example and do not have to write the boring half yourself. A producer in any language that satisfies §5 is equally conformant. ### 4.1 What the package guarantees about itself These are properties a caller may depend on. LangSyn's tests assert each one before a release is published; the tests are not part of the release, and each property can be checked against the source it describes: - **No network.** No module in the package opens a connection, except `dke.client` and `dke.keys`, whose purposes are to. Nothing else in the package reaches either. - **No subprocess.** The package spawns nothing. - **Zero runtime dependencies.** Nothing beyond the Python standard library, except that `dke.keys` needs `cryptography`, the `keys` extra. - **Python 3.10 or later**, a hard floor with a named cause. - **No engine code.** The package contains none and never will. ### 4.2 `dke.factwriter` — domain-free The layer that knows how to write a fact-loading program and nothing about what the facts mean. Public surface: | Name | Contract | |---|---| | `sanitize(name) -> str` | Make a name safe to use as an identifier. | | `Ids` | Stable subject allocation. `get(qual)` returns the same subject for the same qualified name, for the life of the instance. | | `FactProgram` | Builds one DKE Python program. `comment`, `open`, `q`, `put`, `table`, `load_marker`, `render`. | `FactProgram.put(attr, value)` is **the one way a target cell is named**, and its argument is the `Kind.subject.field` path of §2.1. A producer that writes through anything else is outside what §5.4's check can see. `dke.factwriter` is re-exported at the package root: `from dke import FactProgram, Ids, sanitize`. ### 4.3 `dke.ingest` — the `code` readers Readers for one domain — source code — that are both consumers of `dke.factwriter` and the worked example of §5. `dke.ingest.core` holds the domain-shared layer and `MODULE = "code"`, which names the module these facts are for, and one reader submodule per source language sits beside it. > **Naming asymmetry, stated because it will otherwise look like a bug.** The > reader class for `code.Class` is spelled `Klass` in Python, because `class` is > a Python keyword. The *fact* it writes is `code.Class`. The Python spelling is > the producer's business; the kind name is the contract. Exit statuses are part of the contract: `EXIT_OK`, `EXIT_NO_SUCH_PATH`, `EXIT_NOTHING_TO_READ`. A reader that read nothing MUST NOT exit zero — an empty load and a successful one are the two outcomes it exists to distinguish. ### 4.4 `dke.client` — reaching the service The wire client. `DEFAULT_ENDPOINT` and `PROTOCOL_VERSION` name what it talks to. Its error hierarchy is a contract: `DkeError` is the base, `TransportError` carries an HTTP status, `ProtocolError` carries a wire code, and `PaymentRequired` is a `ProtocolError` a caller SHOULD handle distinctly. **On telling an empty answer from an empty store.** When a query returns nothing and you cannot tell which it is, `checkup` reports `unmet .` for a cell a standing rule reads that holds nothing — including the case where a field is absent-read and was never recorded anywhere. That is the difference between *no test reaches these* and *no test was looked for*, and it is the intended instrument for §2.4 going wrong. ### 4.5 `dke.quantum` and `dke.pqc` — the `quantum` and `pqc` readers Readers for two more modules, built on `dke.factwriter` like `dke.ingest`. Each splits its load over as many programs as the size it is given needs, through `FactLoad`, and each program records a load marker. That size is the caller's to pass, because it is a setting of the store. `dke.quantum.device` writes a device's calibration snapshot as the `Device`, `PhysicalQubit` and `Native` facts of §3.16. A snapshot is a directory named for the device, holding `conf_.json` and `props_.json` as Qiskit's fake backends ship them. An operation keeps the device's name for it, except `cx`, which is written `cnot`. `reset`, `measure` and `delay` are not written, and a value the snapshot lacks is not written at all. Its command is `dke-quantum-device --max-bytes N [--module M]`. `dke.quantum.qasm` reads OpenQASM 2.0 into the gate lists the module runs, and writes one back. An angle keeps an exact rational multiple of pi when the text makes it one, so a quarter turn written `pi/2` is told apart from its decimal. `dke.quantum.provenance` computes the digests the rules of §3.17 compare, and writes a `Result`: | Name | Contract | |---|---| | `text_digest(text)` | `sha256:` and the SHA-256 of `text` as UTF-8. | | `snapshot_digest(dir)` | `sha256:` and the SHA-256 of one line per `.json` file in `dir`, in name order, each the file's name, a space and its own SHA-256. | | `digest_name(digest)` | `c_` and the first 16 hex digits of `digest`: the subject of a circuit the store knows only by its digest. | | `lines(module, name, result, writer)` | The `update` lines that record `result` as `Result.`. A field left `None` is not written. | | `circuit_line(module, circuit, digest, writer)` | The `update` line that records a circuit's `digest`. | `dke.pqc.cbom` reads a CycloneDX document of version 1.6 or later and writes the facts of §3.19 it states: an algorithm's `quantum`, `"vulnerable"` when its `nistQuantumSecurityLevel` is 0 and `"resistant"` when it is 1 or more, and its `strength`, its `classicalSecurityLevel`; and one `Use` for each `dependsOn` edge from a component that is not a cryptographic asset to an algorithm. A `provides` edge is not a use. What the document holds and the reader does not read is counted in each program's header. Its command is `dke-pqc-cbom --max-bytes N [--source S] [--module M]`. --- ## 5. The fact-writing contract The vocabulary of §2 and §3 is what a producer and a module must agree on. There is no negotiation and no error at load time for disagreeing: a fact whose field the module does not declare is written, stored, and read by nothing. ### 5.1 Requirements on a producer 1. A producer MUST write only into fields the module declares (§3.3). A field the module does not declare is a fact that lands where nothing reads. 2. A producer MUST NOT write a derived field (§3.4) or a rule conclusion (§3.5). 3. A producer MUST write absence-read fields only where true (§2.4). 4. A producer MUST use subjects, not display names, wherever a field holds a reference to another fact (§3.3, `Call`). 5. A producer MUST NOT assert an edge it did not resolve; it SHOULD record the unresolved call instead (§3.3, `UnresolvedCall`). 6. A producer SHOULD write every field it can determine. Writing fewer narrows what the module can conclude; it does not make anything wrong. ### 5.2 What is normal and not an error **A field the module declares that no producer writes is fine, and expected.** Several exist. Some a customer supplies by hand — `Function.deprecated`. One whole kind, `Counterpart`, is written by nothing LangSyn publishes, because it records a claim about intent that only a reader can make. This asymmetry is deliberate: the contract is **one-way**. A module may declare more than any producer writes. A producer may not write more than the module declares. ### 5.3 Compatibility - Adding a class, a field, a rule or a query to a module is a **compatible** change. Existing producers keep working; the new field is simply unwritten. - Removing or renaming a class or field a producer writes is a **breaking** change, and the module's version reflects it. - Changing a rule's threshold changes what your store concludes without changing any name. It is a **semantic** change, and it is checked: the thresholds in §3.5 and the module's own must agree, so a threshold cannot move without this document moving with it. - Changing a rule's condition in any *other* way — which fields it reads, how they combine — is a semantic change that **no mechanical check sees** (§5.4). It is visible in the module's version and in §3.5's prose, and nowhere else. - The two artifacts version **independently**: `dkepy` and each module carry their own versions, and this specification carries its own. Read a version from the artifact it belongs to, never from prose. ### 5.4 What is mechanically checked, and what is not Stated plainly, because the gap is where a producer author will otherwise assume protection that does not exist. **Checked.** - One direction of §5.1(1): a field written by any `dkepy` emitter that the module does not declare fails a gate before release. The check spans every generation of the emitter the published surface has ever held, not just the current one, because a customer may hold any of them. - **This document against the module it specifies**, in both directions: every kind, field, derived field, rule and query the module declares is named here, and every rule, query and derived field this document promises exists there. Rule thresholds, the kind a rule ranges over, the field it concludes, and a derived field's definition are compared as values, not merely as names. **Not checked, and each of these is real:** - **Types.** A field declared `string` that a producer writes as an `int` passes every check here. - **What a rule reads.** Thresholds are compared, but the rest of a condition is not: a module can keep every field name and every threshold and still change which fields a rule combines, or how. - **Producers we do not publish.** A producer you wrote is bound by §5.1 and measured by nothing. `checkup` is the instrument that answers from your own store. - **Absence discipline.** §2.4 is a requirement no gate enforces. Its failure mode is a plausible answer rather than an error, which is exactly why it is written as a MUST. --- ## 6. What this specification does not cover - **The DKE Python language** — [Python Specification](/spec/dke/python/). - **The wire** — [MCP Reference](/ref/dke/mcp/), including the `language` parameter and its accepted values. - **How to use a module** — [Library Tutorial](/tutorial/dke/library/). - **Your store's contents**, which are yours, and which this document deliberately says nothing about. ## Revision history Newest first. The revision is the surface's — one number stated by every published document, the web pages and the service wire, moving whenever any document changes. This list records the revisions at which this document changed and what changed in it; a revision absent here left this document as it was. The Version line at the top states this document's version, the revision it last changed in and the current revision; from rev 148 each entry opens with the version that revision gave this document. The history starts at rev 1. What a revision promises is stated in the [Python Specification](/spec/dke/python/), its section 11.1. - **1.0.4** · **rev 163** (2026-11-14) — The Version line states API 1.4: `range` is a value of its own, walked without being built, so a `for` over a million numbers runs, and a range keeps its three bounds as `.start`, `.stop` and `.step` ([Specification §8.6](/spec/dke/python/#indexing-slicing-and-string-methods)), and an addition moves the API's MINOR. - **1.0.3** · **rev 151** (2026-11-13) — The Version line states API 1.3: a rule premise may test part of a text, as `r.path.startswith("/srv/")`, `t.name.endswith(".test")` and `"admin" in a.role` ([Specification §14.2](/spec/dke/python/#premises)), and an addition moves the API's MINOR. Nothing else changed, and no module did. - **1.0.2** · **rev 150** (2026-11-13) — The Version line states API 1.2: calls made with keys that may only read run on one store together, where every call on a store ran alone ([MCP §9.8](/ref/dke/mcp/#stop-end-the-call-running-on-your-store)), and an addition moves the API's MINOR. Nothing else changed, and no module did. - **1.0.1** · **rev 149** (2026-11-13) — The Version line states API 1.1: DKE Python gained a form a rule's conclusion may take, a text written from values the rule read (Python Specification §14.3), and an addition moves the API's MINOR. Nothing else changed, and no module did. - **1.0.0** · **rev 148** (2026-11-12) — This document states a version of its own, 1.0.0, first on the Version line and followed by the revision it last changed in, and from this revision each entry here opens with the version it made (Python Specification §11.1). Nothing else changed. - **rev 147** (2026-11-12) — The Version line states API 1.0: the API version is `MAJOR.MINOR`. Nothing else changed. - **rev 145** (2026-11-12) — `physics` 1.0.3, `chemistry` 1.0.3, `biology` 1.0.2, `astronomy` 1.0.2, `geography` 1.0.2 and `mathematics` 1.0.2: each section states how its value scripts keep their work in range, so that each answers wherever its value is a real, where a sum, square, product, ratio or multiplier in the work answered `inf`, `nan`, `0.0` or a wrong solution past the range of a real. §3.28 defines `Quantity.converted` as `value * (factor / efactor)` and states the range of factors over which it is a real. Angles are taken modulo 360 degrees by `math.fmod` in §3.41 and §3.44; `kepler` reduces its mean anomaly first and finds `E` for any `M`; `equilibrium_exact` takes its root as `2 k a0 b0 / (p + r)`, which subtracts nothing; a class `chi_square`'s ratio gives no share adds nothing where it is empty; `pendulum` integrates for up to the exact period; and `physics.solve` reads a system as singular only where a pivot is 0. `gmst`, `kepler`, `charge_ph`, `titration`, `consecutive`, `consecutive_exact`, `peak_time`, `equilibrium_exact`, `chi_square`, `logistic`, `logistic_exact`, `predator_prey`, `small_period`, `agm`, `period`, `pendulum`, `orbit` and `bridge` refuse inputs outside their domain. - **rev 144** (2026-11-12) — `body` 1.0.2, `food` 1.0.3, `colour` 1.0.1, `sound` 1.0.4, `finance` 1.0.2, `earthscience` 1.0.2 and `architecture` 1.0.2: each section states how its value scripts and computed fields keep their work in range, so that each answers wherever its value is a real, where a sum, square, product or ratio in the work answered `inf`, `nan` or `0.0` past the range of a real. §3.70 defines `Person.bmi` as `kg / metres / metres`, §3.78 `Offer.interest` and §3.85 `Hull.gm` of halves, and §3.85 states the range of beam and draught over which `bm` is a real. §3.65 states that a refractive index is 1 or more. `monthly_payment`, `effective_annual_rate` and `continuous_annual_rate` are worked through `expm1` and `log1p`, so that 0.12 compounded once gives 0.12; `lens_magnification` is `f / (f - u)`; an incidence and a lean are taken modulo 360 degrees. `level_of_pressure`, `at_distance`, `dew_point`, `monthly_payment`, `compound_amount` and `effective_annual_rate` refuse inputs outside their domain. - **rev 143** (2026-11-12) — `statistics` 1.0.3: §3.52 states how every value script keeps its work in range, so that it answers wherever its value is a real, where `binom_pmf`, `poisson_pmf` and the descriptive statistics answered `inf`, `nan` or `0.0` from rev 142 when a sum, square or product in their work passed the range. It adds `scale_of`, `stirling_error`, `deviance` and `exact_product`, states the binomial's correction for the rounding of `1 - p` and the measured accuracy of each probability, and the figures `binom_pmf`, `binom_cdf`, `poisson_pmf`, `bayes`, `chi_square`, `stirling_error` and `deviance` refuse. - **rev 142** (2026-11-12) — `sound` 1.0.3: §3.76 states how `add_levels` is computed, as the louder level plus `10 log10(1 + 10^(-d/10))`, so that no power passes the largest real and any two levels have a sum, where the sum of powers answered `inf` from this revision for levels past about 3080 decibels. - **rev 133** (2026-11-10) — The library carries `pqc` at 1.0.2, `harmony` 1.0.1, `physics` 1.0.2, `chemistry` 1.0.2, `biology` 1.0.1, `geography` 1.0.1, `mathematics` 1.0.1, `statistics` 1.0.2, `computing` 1.0.1, `sound` 1.0.2 and `architecture` 1.0.1, on the source surface. Every sum in §3.23–§3.34, §3.45–§3.52, §3.57–§3.60, §3.73–§3.76 and §3.84–§3.87 gains derived fields over the sum's own binding: a count of the members that carry a value into it, a count of the claims they hold, and a flag where the claims outnumber the members. The sum is concluded only where the flag is absent, and so are the rules that rest on it; `chemistry` also raises a molecule's flags from an atom whose bonds are disputed. The queries `disputed_rooms`, `disputed_codes`, `disputed_days`, `disputed_equations`, `disputed_groups`, `disputed_molecules`, `disputed_reactions` and `disputed_studies` are new, and a query that answers a disputed sum raises `ValueError`. `chemistry.formula` counts each atom once and refuses an atom that holds two elements; `unexplained` in §3.36 and `holds` in §3.43 count each member once; §3.21 states that a use's deadline is the earliest year of any value of any deadline. Where each fact is written once, every module answers as before. - **rev 132** (2026-11-10) — The library carries `quantum` at 1.3.0, on the source surface. §3.18 gains the step `mx`, which measures a qubit in the X basis, and the controlled steps `x_if`, `cnot_if`, `ccx_if`, `z_if`, `cz_if`, `ccz_if`, `swap_if` and `cswap_if`, and the helpers `rev_apply_under` and `rev_measures`. `rev_meets` holds a circuit over every assignment of the outcomes and answers the count of cases and the lowest failing case; `rev_same` raises `ValueError` for a circuit that measures; `rev_code` answers operation 8 for `mx` and refuses a controlled step whose qubit no `mx` measured. A circuit with no `mx` is answered as 1.2.0 answered it. - **rev 131** (2026-11-10) — The library carries `quantum` at 1.2.0, on the source surface. §3.18 gains eight queries: `ccx`, `ccz` and `cswap`, the Toffoli, CCZ and Fredkin gates; `rev_same`, which holds two reversible circuits equal when, on every input, they give the same output bits under one sign shared by all inputs; `rev_meets`, which holds a reversible circuit to a specification of its inputs, outputs, zeroed qubits and sign; and the helpers `rev_code`, `rev_apply` and `lowest_lane`. A step of a reversible circuit is `x`, `cnot`, `ccx`, `z`, `cz`, `ccz`, `swap` or `cswap`; any other gate is refused. Everything 1.1.0 answered, 1.2.0 answers the same. - **rev 130** (2026-11-10) — The library carries `elections` at 1.0.0, on the source surface. §3.2 lists twenty-four modules. §3.88 to §3.91 specify `elections`: its declared fields, its derived fields, its standing rules and its queries. §3.88 states that `elections` is not legal or electoral advice, and §3.90 that a count in dispute decides nothing and a tie for the last seat is refused rather than broken. - **rev 129** (2026-11-09) — The library carries `architecture` at 1.0.0, on the source surface. §3.2 lists twenty-three modules. §3.84 to §3.87 specify `architecture`: its declared fields, its derived fields, its standing rules and thresholds, and its queries. §3.84 states that `architecture` is not engineering, naval-architecture, acoustic-design or heritage advice, and §3.87 that a lean or an offset can differ from CPython's in the last place, where `math.atan`, `math.tan`, `math.degrees` and `math.radians` round once. - **rev 126** (2026-11-09) — §3.82 and §3.83: `food` is at 1.0.2 and credits FoodSafety.gov's chart "Cook to a Safe Minimum Internal Temperature", reviewed November 21, 2024, read from a copy downloaded on 2026-11-09. A `casserole` is one with meat or poultry, or meatless, at 165 F, and `chart()` writes eleven standards, `ham-packaged` at 140 F, the chart's note on cooked ham packaged in a USDA-inspected plant, among them. - **rev 125** (2026-11-09) — §3.40, §3.41, §3.55, §3.56, §3.71 and §3.72: `astronomy`, `earthscience` and `body` are at 1.0.1 and each names the readers that refuse while sources disagree, which the sections had said none did: `up()` and `window()`, `dryness_threshold()` and `category()`, and `bmi()`. - **rev 124** (2026-11-09) — §3.75, §3.76, §3.79, §3.80, §3.82 and §3.83: `sound`, `finance` and `food` are at 1.0.1 and each has an `unsettled()` that names each subject that holds two different values for any field you write, eleven in `sound`, five in `finance` and fifteen in `food`. `dose`, `total_of` and `total` are stated to refuse a cell that holds two values. - **rev 123** (2026-11-08) — The library carries `calendars`, `colour`, `body`, `sound`, `finance` and `food` at 1.0.0, each on the source surface. §3.2 lists twenty-two modules. §3.61 to §3.64 specify `calendars`, §3.65 to §3.68 `colour`, §3.69 to §3.72 `body`, §3.73 to §3.76 `sound`, §3.77 to §3.80 `finance` and §3.81 to §3.83 `food`: their declared fields, their derived fields, their standing rules and thresholds, and their queries. §3.69 states that `body` is not medical advice, §3.73 that `sound` is not occupational-health advice, §3.77 that `finance` is not financial advice and §3.81 that `food` is not food-safety or medical advice. - **rev 122** (2026-11-08) — The library carries `statistics`, `earthscience` and `computing` at 1.0.0, each on the source surface. §3.2 lists sixteen modules. §3.49 to §3.52 specify `statistics`, §3.53 to §3.56 `earthscience` and §3.57 to §3.60 `computing`: their declared fields, their derived fields, their standing rules and thresholds, and their queries. - **rev 121** (2026-11-08) — The library carries `astronomy`, `geography` and `mathematics` at 1.0.0, each on the source surface. §3.2 lists thirteen modules. §3.38 to §3.41 specify `astronomy`, §3.42 to §3.44 `geography` and §3.45 to §3.48 `mathematics`: their declared fields, the derived fields of the two that have them, their standing rules and thresholds, and their queries. - **rev 119** (2026-11-08) — §3.30 and §3.34: `unsettled()` in `physics` and `chemistry` names each subject that holds two different values for any field you write, where it named a dispute over five fields of each. - **rev 118** (2026-11-08) — §3.2 lists ten modules. §3.27 to §3.30 specify `physics`, §3.31 to §3.34 `chemistry` and §3.35 to §3.37 `biology`: their declared fields, the derived fields of the two that have them, their standing rules and their thresholds, and their queries. - **rev 117** (2026-11-08) — §3.25 states that the `harmony` rules asking for something to be missing, `chromatic` and the three open readings, are answered for the note rather than for each of its values. - **rev 116** (2026-11-08) — §3.2 lists seven modules. §3.23 to §3.26 specify `harmony`: its declared fields, its derived fields, its standing rules and their thresholds, and its queries. - **rev 114** (2026-11-06) — §3.18 specifies `quantum` 1.1.0's generator from a 256-bit key, ChaCha20 as RFC 8439 defines it: `chacha_quarter`, `chacha_block`, `chacha_unit`, `chacha_uniform` and `advance_chacha`. - **rev 33** (2026-10-23) — §1: every kind, field, rule and query name is written in English. - **rev 31** (2026-10-19) — The DKE Library's three documents are one family. Cross-references name the Library Reference and the Library Tutorial at their new addresses, and §1 says the Reference describes `dkepy` as well as the modules. - **rev 26** (2026-10-17) — The header states Version, Status, Audience and the Markdown copy, one field to a line. §1 places `dkekey`: the store key it issues is specified by MCP Reference §3.1, which `dke.keys` implements too. §3.1's citation of the Python Reference links to §8.8. §4.1: the properties the package guarantees are asserted by LangSyn's tests, which are not part of the release, and each can be checked against the source it describes. - **rev 24** (2026-10-16) — §3.2 lists six modules. §3.16 to §3.18 specify `quantum` and §3.19 to §3.22 `pqc`, and §4.5 their readers in `dkepy`, `dke.quantum` and `dke.pqc`. §4.1 is corrected: `dke.keys` opens a connection as `dke.client` does, and needs `cryptography`, the `keys` extra, where §4.1 said only `dke.client` did and that nothing beyond the standard library was needed. - **rev 22** (2026-10-14) — §1 and §3.2: the modules and `dkepy` are served from `https://dke.langsyn.com/source/`. The `dke.langsyn.org` addresses still lead to the same files. - **rev 20** (2026-10-14) — §3.6: the sentence on how far `impact_of` walks is reworded. What it answers is unchanged. - **rev 4** (2026-10-11) — Cross-references take the published documents' short names, the ones the footer uses — MCP Reference, Python Specification, Python Reference, Modules Reference, Modules Tutorial. Nothing else changed. - **rev 3** (2026-10-11) — The revision is the surface's: one number shared by every published document, the web pages and the service wire. This section says so, and the Version line moves from rev 1 to it. Nothing else changed. - **rev 1** (2026-10-11) — The Version line states the document's revision and this section is added. Nothing else changed.