Verification

What we claim, and how we know

Every statement our engines make is written down, numbered and tied to the evidence that checks it. Each one says how sure we are, and what you have to trust to believe it.

Read the statements Check a proof yourself

Levels

Three levels, each says what you trust

A single badge hides what matters. A proof and a passing test are different things, so every statement carries the level it has earned and nothing higher.

  • Proved
  • Certified
  • Tested
  1. Proved

    True for every input.

    How
    A solver or proof assistant checks the statement.
    You rely on
    The checker, which is small and public.
    An example, SI-01

    For any non-negative module charges, the basic SCR is never above the plain sum of the charges and never below the largest single charge.

  2. Certified

    True for the case in hand, with evidence anyone can recheck.

    How
    The engine emits a witness and a separate checker validates it.
    You rely on
    A few lines of checking code.
    An example, FR-03

    Each prescribed GIRR delta correlation matrix is indefinite, shown by an integer witness vector whose quadratic form, summed in exact arithmetic on the stored matrix, is negative by far more than rounding in the entries could explain.

  3. Tested

    True on every input we tried.

    How
    Property tests over generated inputs and published results.
    You rely on
    The test inputs and the oracle.
    An example, FR-04

    The risk weights, the decay parameter, the floor and the scenario rules reproduce every entry of the published correlation table and the worked example in the January 2019 text of MAR21.

Statements

Every statement, with its evidence

Each row has a number you can cite. The files named under it are the ones that check it. A statement that has not earned a level does not appear.

Proved

True for every input.

A solver or proof assistant checks the statement. You rely on the checker, which is small and public.

Show the 38 statements Hide the statements

PR-01

The MRM class is defined for every VEV, is between 1 and 7, never decreases as the VEV rises, and changes class exactly at the limits in the table.

PRIIPs Read the proof of PR-01

Evidence
  • proofs/smt2/PR-01.smt2

WL-01

For every vehicle inside the family, the interpolated CO2 lies between the CO2 of the low vehicle and the CO2 of the high vehicle.

WLTP Read the proof of WL-01

Evidence
  • proofs/smt2/WL-01.smt2

WL-02

Inside the family, a vehicle that demands more energy never gets a lower interpolated CO2, provided the high vehicle emits at least as much as the low one.

WLTP Read the proof of WL-02

Evidence
  • proofs/smt2/WL-02.smt2

SI-01

For any non-negative module charges, the basic SCR is never above the plain sum of the charges and never below the largest single charge.

Solvency II Read the proof of SI-01

Evidence
  • proofs/smt2/SI-01.smt2

PQ-01

When only the quantum computer sets the date, the latest start is the years until it arrives less the years to keep the data secure and the years to migrate. Nothing later keeps the data safe, and the use is late exactly when those two add up to more than the years until it arrives.

PQC Read the proof of PQ-01

Evidence
  • proofs/smt2/PQ-01.smt2

PQ-02

A use is at least medium risk under the EU roadmap exactly when it protects confidentiality or takes more than eight years to migrate. It is high risk exactly when it has a high impact and either protects confidentiality for ten years or more or takes more than eight years to migrate.

PQC Read the proof of PQ-02

Evidence
  • proofs/smt2/PQ-02.smt2

PQ-03

A use that others wait for finishes no later than it would alone and no later than any of them can start, and no later finish does both. It starts strictly earlier than each of them, so a use that is late makes every use it waits for late too.

PQC Read the proof of PQ-03

Evidence
  • proofs/smt2/PQ-03.smt2

AE-01

For every number of days with data in a year, from 1 to 366, the rank that Table 1 of Appendix N gives for the 98th percentile is the smallest whole number that is at least 2 per cent of the days, and the rank that Table 1 of Appendix T gives for the 99th percentile is the smallest whole number that is at least 1 per cent of them. Every count of days has a rank, and more days never lower it.

AERMOD Read the proof of AE-01

Evidence
  • proofs/smt2/AE-01.smt2

AE-02

In every stability class both spreads of the plume grow with the distance downwind, from 100 m to 10 km. At every distance the spread of a more stable class is smaller than that of the class before it, both across the wind and upward.

AERMOD Read the proof of AE-02

Evidence
  • proofs/smt2/AE-02.smt2

AE-03

A day read as a monitor network keeps it is never above the same day read as a model takes it. It is below it by less than 0.2 for a mean of 24 hours and by less than 0.1 for the highest hour. The network cuts each hour off at a tenth and then cuts the mean of those off at a tenth again.

AERMOD Read the proof of AE-03

Evidence
  • proofs/smt2/AE-03.smt2

AE-04

A daily value of PM10 that a monitor keeps in tenths is an exceedance of a level exactly when it is at least 5 below the next multiple of 10 above the level, so for the level of 150 it is an exceedance from 155.0 on. A day from 150.1 to 154.9 is above the level and is not counted, and every day that is counted is above the level.

AERMOD Read the proof of AE-04

Evidence
  • proofs/smt2/AE-04.smt2

AE-05

A design value that is the mean of three values and is rounded half up as Appendices N and T say is at most the level exactly when the three add up to at most 1064 tenths for the 24-hour PM2.5 level of 35, which holds for values kept in whole tenths, and at most 2264 for the 1-hour SO2 level of 75 ppb. The annual mean is at most 9.0 exactly when the three annual means, which need not be whole tenths, add up to less than 27.15. For PM10 the design value is at most 1.0 exactly when the three yearly counts of days add up to at most 3.

AERMOD Read the proof of AE-05

Evidence
  • proofs/smt2/AE-05.smt2

RS-01

For positive amounts, the development factor of a year is the mean of the ratios from that year to the next, weighted by the amounts of the first of the two. So it is not below the smallest of those ratios and not above the largest, and it is their common value when they are all alike.

Reserving and ESG Read the proof of RS-01

Evidence
  • proofs/smt2/RS-01.smt2

RS-02

In a triangle of four origin years, what the chain ladder expects to be paid in the three calendar years to come adds up to the reserve, which is the ultimate less the latest amount of each origin year. The first year pays the next factor of every open origin year, and when no factor is below one, no payment is below zero.

Reserving and ESG Read the proof of RS-02

Evidence
  • proofs/smt2/RS-02.smt2

RS-03

The variance that the formula of Mack gives to the last development year, which rests on a single ratio, is never below zero and never above either of the two estimates before it. It is the continuation of their decline when they do not rise, the earlier of the two when they rise, and nothing when the earlier is nothing.

Reserving and ESG Read the proof of RS-03

Evidence
  • proofs/smt2/RS-03.smt2

RS-04

The ultimate forward rate of a year is the rate of the year before, or that rate plus 15 basis points, or that rate less 15 basis points. It rises exactly when the rate before the limit is at least 15 basis points above the rate of the year before, and falls exactly when it is at least 15 basis points below. It never ends farther from the rate before the limit than it began, and a higher rate before the limit never gives a lower ultimate rate.

Reserving and ESG Read the proof of RS-04

Evidence
  • proofs/smt2/RS-04.smt2

RS-05

Beyond the first smoothing point, the weight of the last liquid forward rate, which is (1 − e^(−a×h)) over a×h, is above zero and not above one. It is not below 1 − a×h/2, and a×h times it is not above one.

Reserving and ESG Read the proof of RS-05

Evidence
  • proofs/smt2/RS-05.smt2

RS-06

Beyond the first smoothing point, the forward rate of each horizon lies between the last liquid forward rate and the ultimate forward rate. Its distance from the first is at most a×h/2 of the distance between the two, and its distance from the second is at most 1/(a×h) of it.

Reserving and ESG Read the proof of RS-06

Evidence
  • proofs/smt2/RS-06.smt2

RS-07

Beyond the first smoothing point, the zero rate of each horizon lies between the zero rate at the point and the forward rate of that horizon. It is nearer to the one that covers more years, which is the forward rate when the horizon is longer than the point and the zero rate at the point when it is shorter.

Reserving and ESG Read the proof of RS-07

Evidence
  • proofs/smt2/RS-07.smt2

RS-08

The expected real rate is rounded to a whole number of five basis points, upwards when it is below the rounded rate of the year before and downwards otherwise. The rounded rate is less than five basis points from the unrounded one, a rate that is already a whole number of five basis points stays as it is, and a higher unrounded rate never gives a lower rounded one.

Reserving and ESG Read the proof of RS-08

Evidence
  • proofs/smt2/RS-08.smt2

SC-01

When the hedges of a bucket offset every one of its risk factors in the same proportion, the quantity under the root of its capital is (1 − ratio)² × Q + R × ratio² × N, where Q is the form of the CVA weighted sensitivities through the correlation matrix, N is the sum of their squares and R is the hedging disallowance of 0.01. No ratio takes it below R × Q × N / (Q + R × N), the ratio Q / (Q + R × N) reaches that value, and so the capital of a bucket with a position is never zero.

SA-CVA Read the proof of SC-01

Evidence
  • proofs/smt2/SC-01.smt2

SC-02

With the hedges of the previous statement, a ratio of hedging above zero and below 2 × Q / (Q + R × N) lowers the quantity under the root of the capital of a bucket, that ratio leaves it where it was with no hedge, and a ratio above it or below zero raises it. With the disallowance of 0.01 and a single factor, a hedge of more than 198 per cent of the exposure costs more capital than no hedge.

SA-CVA Read the proof of SC-02

Evidence
  • proofs/smt2/SC-02.smt2

SC-03

In an interest rate bucket of six factors, the share that rests on the CVA sensitivity of each factor, which is the CVA weighted sensitivity times the matching entry of the correlation matrix times the net weighted sensitivities, and the share that rests on its hedge, which is the weighted hedge times R times itself less that entry, add up to the quantity under the root, whatever the sensitivities are. Divided by the capital, the shares add up to it.

SA-CVA Read the proof of SC-03

Evidence
  • proofs/smt2/SC-03.smt2

SC-04

For three buckets that each have the same correlation of 0.5 with every other, or of 0.6, and whose sums of weighted sensitivities are cut to the range of their capital, the quantity under the root of the capital of a class is never below zero and never above the square of the sum of the bucket capitals. The capital of the class is then a real number, and the diversification it gives never lifts it above the plain sum of the buckets.

SA-CVA Read the proof of SC-04

Evidence
  • proofs/smt2/SC-04.smt2

IC-01

For any five charges of the life risks that are not below zero, the quantity under the root of the life charge, which is the form of Table 6 of the Level 2 text, is at least 15/16 of the square of each charge and at most the square of their sum. So the life charge is never below the root of 15/16, which is 96.8 per cent, of its largest charge, and never above the sum of the charges. The floor is reached with a mortality charge of 4 and a longevity charge of 1, so that no higher floor can be proved.

ICS Read the proof of IC-01

Evidence
  • proofs/smt2/IC-01.smt2

IC-02

With a mortality charge M above zero and a longevity charge L, and nothing else in the life risks, the quantity under the root of the life charge is M² + L² − M × L / 2. It is below M² for any L above zero and below M / 2, it equals M² at M / 2, and it is above M² beyond. It is lowest at L = M / 4, where it is 15/16 of M². A longevity charge of a quarter of the mortality charge therefore lowers the life charge by 3.2 per cent, and a larger one lowers the requirement too, as long as it is below half.

ICS Read the proof of IC-02

Evidence
  • proofs/smt2/IC-02.smt2

IC-03

For charges that are not below zero, the quantity under the root of the market charge, in the row of Table 16 for an upward spread stress and in the row for a downward one, and the quantity under the root of the top level of Table 34, are each at least the sum of the squares of the charges and at most the square of their sum. So each aggregate is at least the root of the sum of the squares, which is what no correlation at all gives, and at most the sum of the charges. The charge of a category is real, and diversification never lifts it above the plain sum.

ICS Read the proof of IC-03

Evidence
  • proofs/smt2/IC-03.smt2

IC-04

Before the operational charge, a life, catastrophe or market risk has the part of the insurance risk charge that is its share inside its category, c × (R × c) / A, times the weighted charge of the category over the aggregate. Non-life and credit take their own charge times that factor. The parts add up to the aggregate. The terms c × (R × c) of each table add up to the square of the charge of their category, and the terms of Table 34 add up to the square of the aggregate. Terms that add up to the square of a number add up to it when divided by it. A factor times shares that add up to a charge adds up to the factor times it.

ICS Read the proof of IC-04

Evidence
  • proofs/smt2/IC-04.smt2

IC-05

The tax effect taken off the insurance risk charge lies between zero and 80 per cent of the notional effect, which is the requirement times the group effective tax rate, so at least a fifth of the requirement is left. The carry-back component is at most 85 per cent of the notional effect. The net deferred tax asset is at most 15 per cent of the requirement and is never held against a net liability. An asset can only lower what is used, and a sum of components between nothing and the cap is what is used. It holds for any notional effect up to the requirement and any three sub-groups, capacity, earnings and deferred taxes.

ICS Read the proof of IC-05

Evidence
  • proofs/smt2/IC-05.smt2

IC-06

For any capital resources and any requirement, what counts and what is left out add up to what is held, for a group that is not mutual and for a mutual. For a group that is not mutual, Tier 1 Limited counts up to 15 per cent of the requirement, Tier 2 up to 50 per cent and the basket up to 15 per cent, and none of the Non-Paid-Up capital counts. For a mutual, Tier 1 Limited counts up to 30 per cent, Non-Paid-Up up to 10 per cent, and Tier 1 Limited and Tier 2 together up to 60 per cent. What Tier 1 Limited has over its limit moves to Tier 2. What is left out is not below zero and what counts is not above what is held.

ICS Read the proof of IC-06

Evidence
  • proofs/smt2/IC-06.smt2

SM-01

For margins of the six risk classes that are not below zero, the quantity under the root of the margin of a product class is at least the sum of the squares of the margins and at most the square of their sum. So the margin is at least the root of the sum of squares, which is what independent risk classes give, and at most the sum of the six margins.

SIMM Read the proof of SM-01

Evidence
  • proofs/smt2/SM-01.smt2

SM-02

The concentration factor is never below one and is one up to the threshold. Above it, its square times the threshold is the exposure, so the margin of a lone factor grows with the exposure to the power 3/2. It rises with the exposure, so more exposure never lowers a weighted sensitivity, and it depends only on the exposure over the threshold, so the unit of both does not matter.

SIMM Read the proof of SM-02

Evidence
  • proofs/smt2/SM-02.smt2

SM-03

In a bucket, the parts that rest on the factors add up to K² + S × C, where K² is the quantity under the root of the bucket margin, S is the clipped sum of the weighted sensitivities and C is what the other buckets put in the cross term. It holds when the sum is inside the clip, above it or below it, or when K is zero, and for any number of factors, because each step of the sum keeps the invariant.

SIMM Read the proof of SM-03

Evidence
  • proofs/smt2/SM-03.smt2

SM-04

The parts of a product class add up to its margin. In a risk class, the parts of the regular buckets add up to the quantity under the root over the root, which is the core margin, and the residual bucket gives its own margin. The parts of the six risk classes, each the margin times the weighted margin over the total, add up to the total, which is the Euler identity of the table between risk classes.

SIMM Read the proof of SM-04

Evidence
  • proofs/smt2/SM-04.smt2

SM-05

For three buckets with the cross-bucket correlation of 3/10, any clipped sums within their K and any ratios of the concentration factors between 0 and 1, the quantity under the root of a risk class is at most the square of the sum of the bucket margins and at least 2/5 of the sum of their squares. So the cross-bucket aggregation never adds to the plain sum, the quantity is never below zero, and the floor in the engine is not reached.

SIMM Read the proof of SM-05

Evidence
  • proofs/smt2/SM-05.smt2

SM-06

The clipped sum of a bucket is never beyond K and has the sign of the sum. It is the sum inside the clip and K with the sign of the sum outside it. It rises with the sum, and a book with every sign changed has the clipped sum with its sign changed, so that the margin does not depend on which side of the market the book is on.

SIMM Read the proof of SM-06

Evidence
  • proofs/smt2/SM-06.smt2

Certified

True for the case in hand, with evidence anyone can recheck.

The engine emits a witness and a separate checker validates it. You rely on a few lines of checking code.

FR-03

Each prescribed GIRR delta correlation matrix is indefinite, shown by an integer witness vector whose quadratic form, summed in exact arithmetic on the stored matrix, is negative by far more than rounding in the entries could explain.

FRTB-SA

Evidence, 3 tests
  • tests/kernel/frtb.test.ts
  • src/kernel/frtb.ts
  • src/kernel/rational.ts
  • certifies that the ‹scenario› matrix is indefinite with a checkable witness
  • shows the ‹scenario› matrix to be indefinite in exact arithmetic, by far more than rounding in its entries could explain
  • asks for a margin: a negative form inside the allowed error, or exactly at it, is not enough

SI-02

The prescribed basic SCR correlation matrix is positive definite, shown by an exact factorisation into a lower triangle, a diagonal and the transpose of the triangle, which a separate checker accepts.

Solvency II

Evidence, 2 tests
  • tests/kernel/exact.test.ts
  • src/kernel/certify.ts
  • certifies the Solvency II basic SCR correlation matrix
  • rejects a forged certificate

PQ-04

A migration plan is accepted by a second method that builds no order. It starts from the date each use has on its own, lets every use pull the ones it waits for earlier until no date moves, and then confirms every date, the exposure, the order and every sum of bytes. A plan with one figure changed, two uses swapped or a use placed before one it waits for is refused.

PQC

Evidence, 5 tests
  • tests/kernel/pqc.test.ts
  • src/kernel/pqc.ts
  • accepts every plan the engine makes, by a route that builds no order
  • rejects a plan that has been tampered with
  • rejects a plan whose order is wrong while its ranks and dependencies are right
  • rejects a plan with a wrong figure in each place that a plan carries one
  • rejects a plan that puts a use before the one it waits for

AE-06

The day that the engine takes as the highest, the second highest or the nth highest of a year is accepted by a second check that sorts nothing. It counts the days above the value and the days at or above it. It refuses a value that is not at the place the engine names, and a rank that the year does not have.

AERMOD

Evidence, 2 tests
  • tests/kernel/aermod.test.ts
  • src/kernel/aermod.ts
  • accepts what nthHighest finds and nothing else
  • rejects a claim whose value is not at the index it names, and a rank out of range

SC-05

The correlation matrix of Table 4, for the interest rates of a specified currency, and that of Table 6, across the seven credit spread buckets, are positive definite. An exact LDL factorisation shows it, and a separate checker accepts the factorisation. A certificate with one pivot or one entry changed is refused. The engine finds no certificate for a table in which two neighbouring factors are perfectly correlated, or a far pair is correlated too much for the pairs between.

SA-CVA

Evidence, 3 tests
  • tests/kernel/sacva.test.ts
  • src/kernel/certify.ts
  • src/kernel/rational.ts
  • certifies that %s is positive definite, with an exact factorisation that a separate checker accepts
  • rejects a certificate for %s with one pivot or one entry changed
  • finds no certificate for a table whose two neighbouring factors are perfectly correlated, and none for one in which a far pair is correlated too much for the pairs between

IC-07

Four correlation tables are positive definite. They are Table 6 for life, Table 34 for the categories, and the six by six tables of Table 16 for the up stress and for the down stress of the spread. An exact LDL factorisation shows it, a separate checker accepts it, and a certificate with one pivot or one entry changed is refused. The engine finds no certificate for the whole seven row Table 16, where a vector makes the form negative, so the two spread rows are never in one aggregation. It finds none for a life table with mortality and longevity at minus 100 per cent, or for a top table in which a pair is correlated beyond what the others allow.

ICS

Evidence, 4 tests
  • tests/kernel/ics.test.ts
  • src/kernel/certify.ts
  • src/kernel/rational.ts
  • certifies that %s is positive definite, with an exact factorisation that a separate checker accepts
  • rejects a certificate for %s with one pivot or one entry changed
  • finds no certificate for the whole of Table 16, and shows with a vector that the form of it is below zero, so that no such certificate exists
  • finds no certificate for a life table in which longevity and mortality are correlated at -100%, and none for a top table in which a pair is correlated beyond what the others allow

SM-07

The correlation tables of the sketch are positive definite. They are the tables between the six risk classes, between the vertices of a rate, between the buckets of qualifying credit, equity and commodity, and between FX rates for any mix of currencies. An exact LDL factorisation shows it, a separate checker accepts it, and a certificate with one pivot or one entry changed is refused. The engine finds no certificate for a table with one pair correlated beyond what the others allow.

SIMM

Evidence, 5 tests
  • tests/kernel/simm.test.ts
  • src/kernel/certify.ts
  • src/kernel/rational.ts
  • certifies that %s is positive definite, with an exact factorisation that a separate checker accepts
  • rejects a certificate for %s with one pivot or one entry changed
  • certifies the whole correlation of a rate, the vertices and the sub-curves together, which is the product of the two tables
  • certifies the correlation of FX rates for any mix of regular and high volatility currencies
  • finds no certificate for a table with one pair correlated beyond what the others allow

Tested

True on every input we tried.

Property tests over generated inputs and published results. You rely on the test inputs and the oracle.

Show the 115 statements Hide the statements

KE-01

exp and ln stay within three units in the last place of the platform library over generated inputs.

Kernel

Evidence, 2 tests
  • tests/kernel/dmath.test.ts
  • agrees with the platform exp to a few ulps across the whole range
  • agrees with the platform log to a few ulps from subnormals to the top of the range

KE-02

Changing any single bit of an input number changes the receipt, except that every not-a-number is written as the same one.

Kernel

Evidence, 1 test
  • tests/kernel/rng-receipt.test.ts
  • changes when any single input changes

KE-03

Node, workerd, Chromium, Firefox and WebKit return identical receipts for every parity fixture.

Kernel

Evidence
  • scripts/parity/run.mjs

KE-04

The cube root stays within two units in the last place of the platform library over generated inputs. Sine and cosine in degrees are exact at every quarter turn, never return a negative zero, and stay within a few units of 1e-16 of the platform at every whole degree.

Kernel

Evidence, 3 tests
  • tests/kernel/dmath.test.ts
  • agrees with the platform cbrt to two units in the last place from subnormals to the top of the range
  • is exact at every multiple of a quarter turn and never returns a negative zero
  • agrees with the platform to a few units of 1e-16 at every whole degree, where the receptors of the model sit

FR-01

Risk factor shares add up to the capital charge in every correlation scenario, and each matches a numerical derivative of the charge.

FRTB-SA

Evidence, 2 tests
  • tests/kernel/frtb.test.ts
  • allocates the charge exactly: Euler contributions sum to the total in every scenario
  • matches a finite difference of the charge for every risk factor

FR-02

The capital charge is positively homogeneous of degree one and unchanged when every position flips sign.

FRTB-SA

Evidence, 2 tests
  • tests/kernel/frtb.test.ts
  • is positively homogeneous of degree one
  • is symmetric under flipping every position

FR-04

The risk weights, the decay parameter, the floor and the scenario rules reproduce every entry of the published correlation table and the worked example in the January 2019 text of MAR21.

FRTB-SA

Evidence, 5 tests
  • tests/kernel/frtb.test.ts
  • reproduces every entry of Table 2 (MAR21.46) at the published precision
  • reproduces the worked example in footnote 13: one year against five years is 88.69%
  • uses the risk weights of Table 1 (MAR21.42), which are in basis points here
  • uses 3 per cent for theta, a 40 per cent floor and 50 per cent across currencies (MAR21.46, MAR21.50)
  • shifts correlations by the high and low rules

FR-05

A bucket whose quadratic form is negative is floored at zero, and the clipped fallback applies when the cross-bucket quantity under the root is negative.

FRTB-SA

Evidence, 3 tests
  • tests/kernel/frtb.test.ts
  • floors a bucket at zero when its quadratic form is negative
  • applies the clipped fallback when the cross-bucket radicand is negative
  • lets a nonzero book carry zero GIRR delta capital under the prescribed parameters

FR-06

The capital charge is never negative and equals the largest of the three scenario charges.

FRTB-SA

Evidence, 2 tests
  • tests/kernel/frtb.test.ts
  • is never negative and equals the largest scenario charge
  • marks exactly one scenario as binding and it carries the total

SI-03

At every level of the Solvency II trace, the shares of the parts add up to the share of the whole.

Solvency II

Evidence, 2 tests
  • tests/kernel/solvency.test.ts
  • shares sum to the total
  • shares of siblings sum to the share of their parent at every node

SI-04

Every module’s share of the basic SCR is at least zero and at most the module’s own charge.

Solvency II

Evidence, 1 test
  • tests/kernel/solvency.test.ts
  • gives every module a share between zero and its own standalone charge

SI-05

The SCR is the basic SCR plus operational risk less the loss-absorbing adjustment, which is limited so the SCR cannot go below zero.

Solvency II

Evidence, 3 tests
  • tests/kernel/solvency.test.ts
  • builds the SCR from the basic SCR, operational risk and the adjustment
  • clamps an adjustment that would make the requirement negative
  • rejects a negative operational charge or adjustment

PR-02

The VEV matches a case worked by hand, rises with negative skew and with fat tails, and tracks annualised volatility for normal returns.

PRIIPs

Evidence, 3 tests
  • tests/kernel/priips.test.ts
  • matches a hand computed Gaussian case
  • rises with negative skew and with fat tails
  • is close to annualised volatility for a normal return, and never below it

PR-03

The parts of the Cornish-Fisher value at risk add up to the whole, and for a normal return they reduce to the normal value at risk less the drift. Returns are the logarithms of price ratios and add up to the logarithm of the whole move.

PRIIPs

Evidence, 4 tests
  • tests/kernel/priips.test.ts
  • shows the parts of the value at risk and they add up to the whole
  • is the normal value at risk less the drift when the returns are normal
  • uses the coefficients of point 12
  • adds up to the logarithm of the whole move

EN-03

The adaptive proportion cutoffs reproduce every entry of Table 2 in SP 800-90B. They match exact big integer arithmetic for whole bit claims of one to eight bits, except at an exact tie with the false positive rate, where rounding can put a cutoff one above.

Entropy validation

Evidence, 3 tests
  • tests/kernel/entropy.test.ts
  • reproduces every entry of Table 2 in SP 800-90B
  • matches exact big integer arithmetic for every whole bit claim up to eight bits
  • matches exact arithmetic for small windows, apart from the floor of two and from an exact tie

EN-04

The most common value estimate reproduces the worked example in SP 800-90B section 6.3.1 and matches the closed form for a biased stream.

Entropy validation

Evidence, 2 tests
  • tests/kernel/entropy.test.ts
  • reproduces the worked example in SP 800-90B section 6.3.1
  • matches the closed form for a known biased bit stream

EN-05

Each adaptive proportion window counts its first sample as often as it occurs in the window, and the test fails at the first sample that brings a window to the cutoff.

Entropy validation

Evidence, 2 tests
  • tests/kernel/entropy.test.ts
  • counts the first sample of each window as often as it occurs in the window
  • fails at the first sample that brings a window to the cutoff

EN-06

A health run reports what each test and the estimate report on their own, and puts its alarm at the earlier of the two failures.

Entropy validation

Evidence, 2 tests
  • tests/kernel/entropy.test.ts
  • reports what each test reports on its own
  • puts the alarm at the earlier of the two failures

EN-07

The repetition count test fails at the sample that completes a run of the cutoff length and never when every run is shorter, and it reports where the longest run ended.

Entropy validation

Evidence, 3 tests
  • tests/kernel/entropy.test.ts
  • repetition count fails exactly when a run reaches the cutoff
  • repetition count never fails on a stuck-free alternating stream
  • reports where the longest run ended and keeps the first of equal runs

WL-03

Energy demand over a cycle is the sum of force times distance over its one second periods, counting only positive force. It equals force times distance at a steady speed and rises with every road load coefficient and with test mass.

WLTP

Evidence, 6 tests
  • tests/kernel/wltp.test.ts
  • matches a case worked by hand, with every term of the force
  • gives the force of each period, and the energy is the positive part of it times the distance
  • equals force times distance when the speed is steady
  • counts only positive driving force
  • rises with every road load coefficient
  • rises with test mass on the WLTC

WL-04

The class 3b trace has 1,801 speeds in phases of 589, 433, 455 and 323 seconds, and its sums over each phase and over the whole cycle reproduce the checksums that the regulation prints in Table A1/13.

WLTP

Evidence, 2 tests
  • tests/kernel/wltp.test.ts
  • has a speed for every second of four phases of 589, 433, 455 and 323 seconds
  • reproduces every checksum in Table A1/13

WL-05

An individual vehicle with the mass, tyres and drag of vehicle H has the road load of H. One with those of vehicle L has the refitted road load of L. In between, the first coefficient moves in proportion to test mass times rolling resistance and the second in proportion to drag area.

WLTP

Evidence, 4 tests
  • tests/kernel/wltp.test.ts
  • is vehicle H when mass, rolling resistance and drag are those of vehicle H
  • is the refitted vehicle L when mass, rolling resistance and drag are those of vehicle L
  • moves the first coefficient in proportion to test mass times rolling resistance
  • moves the second coefficient in proportion to the drag area

WL-06

The curve of vehicle L is refitted, over the reference speeds from 20 to 130 km/h, by least squares with the linear coefficient of vehicle H, and a curve that already has that coefficient is not moved.

WLTP

Evidence, 2 tests
  • tests/kernel/wltp.test.ts
  • refits vehicle L over the reference speeds with the linear coefficient of vehicle H, by least squares
  • does not move vehicle L when the linear coefficients already agree

WL-07

An individual vehicle that has the parameters of vehicle H or of vehicle L is given the CO2 of that vehicle, in every phase and over the cycle, and one between them is given a figure between theirs.

WLTP

Evidence, 3 tests
  • tests/kernel/wltp.test.ts
  • gives vehicle H its own CO2, in every phase and over the cycle, when it has the parameters of H
  • gives vehicle L its own CO2 when it has the parameters of L
  • stays between the CO2 of L and H for every combination that lies between them on all three counts

WL-08

The method is allowed when vehicle H emits at least 5 g/km more than vehicle L and no more than the lower of 30 g/km and 20 per cent of its own CO2. The line may be extended by 3 g/km at either end, and no further than the largest difference.

WLTP

Evidence, 4 tests
  • tests/kernel/wltp.test.ts
  • allows a difference of 5 g/km and no less
  • allows the lower of 30 g/km and 20 per cent of the CO2 of vehicle H, and no more
  • may be extended by 3 g/km at either end and no further
  • does not let the extended line grow past the largest difference allowed

WL-09

The CO2 for the whole cycle weights the phases by their driven distance. The CO2 of the test vehicles is carried to two decimal places, and an individual vehicle is declared to the nearest whole g/km, for each phase and for the cycle.

WLTP

Evidence, 4 tests
  • tests/kernel/wltp.test.ts
  • weights the phases by the distance driven in each
  • carries the CO2 of a test vehicle to two decimal places, and stays there
  • declares an individual vehicle to the nearest whole g/km
  • takes the CO2 of the test vehicles to two decimals before it interpolates, and declares each phase and the cycle on its own

WL-10

An individual vehicle takes the class value of its tyres from Table A4/1 for C1 tyres, which are 5.9, 7.1, 8.4, 9.8, 11.3 and 12.9 kg per tonne for classes A, B, C, E, F and G. There is no class D.

WLTP

Evidence, 1 test
  • tests/kernel/wltp.test.ts
  • gives the class values of Table A4/1 for C1 tyres, with no class D

PQ-05

Every key, ciphertext and signature size of ML-KEM, ML-DSA and SLH-DSA is derived from the formulas of FIPS 203, 204 and 205 and equals the size that the standard prints, in a table or in the sentence that gives it. That covers the three ML-KEM sets, the three ML-DSA sets and the six rows of Table 2 of FIPS 205. The hybrid key shares of TLS 1.3 are derived from RFC 10024 and equal the sizes it writes.

PQC

Evidence, 10 tests
  • tests/kernel/pqc.test.ts
  • derives every ML-KEM size from the formulas of FIPS 203 and each equals Table 3
  • derives every ML-DSA size from the formulas of FIPS 204 and each equals Table 2
  • derives every SLH-DSA size from the formulas of FIPS 205 and each equals Table 2
  • derives the hybrid shares of TLS 1.3 and each equals the size that RFC 10024 writes
  • lists every derived size beside its published size, and they agree
  • says where the standard prints each size, which is a table for most and a sentence of the text for the rest
  • has the parameters that FIPS 203 prints in Table 2
  • has the parameters that FIPS 204 prints in Table 1
  • has the parameters that FIPS 205 prints in Table 2, for the SHA2 sets
  • computes the length of a WOTS+ signature as repeated multiplication does, for every n and every Winternitz parameter

PQ-06

The dates are those of NIST IR 8547, the EU roadmap and the NCSC timeline, at every boundary they set, and the EU risk level follows the four rules of its section 5, including the difference between nine years of confidentiality and ten and between a migration of eight years and nine.

PQC

Evidence, 7 tests
  • tests/kernel/pqc.test.ts
  • follows the four rules of section 5 of the EU roadmap
  • keeps a use high risk when a later rule only asks for medium
  • never falls when the years to keep it secure, the years to migrate or the impact rise
  • uses the dates of NIST IR 8547 for federal systems
  • treats encryption like key establishment under the federal dates
  • uses the dates of the EU roadmap, by the risk level it assigns
  • uses the dates of the NCSC timeline, by whether the asset is critical

PQ-07

A use is exposed exactly when the years to keep it secure plus the years to migrate exceed the years until a quantum computer. It is late when its latest start is before the planning year, and a quantum computer that is further away never makes a use start earlier.

PQC

Evidence, 3 tests
  • tests/kernel/pqc.test.ts
  • flags a use exactly when the years to keep it secure plus the years to migrate exceed the years until a quantum computer
  • reports a use as late by the shortfall, and as now when there is no slack
  • never starts a use earlier when a quantum computer is further away

PQ-08

Every use that changes is listed once, in order of its latest start, key establishment first when two tie, and never before a use it waits for. A use never starts later than it could on its own, and the same inventory written in another order gives the same plan.

PQC

Evidence, 6 tests
  • tests/kernel/pqc.test.ts
  • lists every use that changes once, and never before a use it waits for
  • puts uses in order of their latest start
  • never starts a use later than it could on its own
  • is the same for any order of the inventory
  • orders uses by latest start, key establishment before signatures when equal, then by id
  • carries a pull through a chain of uses, from the last to the first

PQ-09

What a replacement adds on the wire is the sum of sizes that the standards give: both key shares for a hybrid exchange, the ciphertext for a wrapped key, and the signature with the public key for a signature. A use whose algorithm survives a quantum computer has nothing to send.

PQC

Evidence, 4 tests
  • tests/kernel/pqc.test.ts
  • sends the shares of both sides for an exchange, one ciphertext for a wrapped key, and a signature with its public key
  • prices every algorithm for every purpose it serves, from the sizes of its public value and its signature
  • has nothing to send for an algorithm that survives a quantum computer
  • gives each use its replacement and what it adds on the wire

PQ-10

The receipt of a plan covers the dates, the thresholds, the sizes, the inventory and every figure of the plan. It changes when any input changes, and it does not change with a name or with the order in which the inventory is written.

PQC

Evidence, 5 tests
  • tests/kernel/pqc.test.ts
  • covers the dates, the thresholds and the sizes, so a change in the rules is a change in the receipt
  • changes when any input changes
  • names every figure of the plan, one row at a time
  • does not change with a name or with the order the inventory is written in
  • does not change with the order that the prerequisites of a use are listed in

AE-07

The spread of the plume across the wind and upward is the open-country row of Table 4.5 of the Handbook on Atmospheric Diffusion for each class. The engine gives the values that the formulas give at 100 m, 1 km and 10 km, and refuses a distance outside 100 m to 10 km, which is the range the table holds for.

AERMOD

Evidence, 3 tests
  • tests/kernel/aermod.test.ts
  • are the rows of Table 4.5 of the Handbook, for the open country
  • gives the open-country values at 100 m, 1 km and 10 km
  • refuses a distance outside the range that the table holds for

AE-08

The rise of the plume follows equation 91 of the AERMOD formulation, in which a momentum term and a buoyancy term are added under a cube root. It starts from nothing, never falls and stops at the limit of the Handbook, which is equation 2.25 in the unstable and neutral classes and equation 2.19 in the stable ones. A gas no warmer than the air, a wind below calm and a stack outside the range are refused.

AERMOD

Evidence, 6 tests
  • tests/kernel/aermod.test.ts
  • gives the buoyancy and momentum fluxes of the invented stack
  • has no buoyancy when the gas is as warm as the air, and more of it the warmer the gas is
  • refuses a plume that is not warmer than the air, a wind below calm and a stack outside the range
  • limits the rise by equation 2.25 in the unstable and neutral classes and by 2.19 in the stable ones
  • rises from nothing, never falls, and stops at its limit
  • follows equation 91 before the limit

AE-09

The wind at the height of the stack is the wind at ten metres raised by the power that Table 4.6 gives for the class. It stops growing at 200 m and never falls below calm, which is 0.5 m/s.

AERMOD

Evidence, 2 tests
  • tests/kernel/aermod.test.ts
  • is the wind at ten metres at ten metres and grows with the power of the class
  • stops growing at 200 m and never falls below calm

AE-10

The concentration at the ground is equation 4.1 of the Handbook with the plume and its image added, and it matches that equation worked independently, on the axis and off it. The plume carries the whole emission through every plane across the wind, which a numerical sum confirms. It is proportional to the emission, highest on the axis, equal on either side of it and nothing far to the side.

AERMOD

Evidence, 4 tests
  • tests/kernel/aermod.test.ts
  • matches the equation worked independently, on the axis and off it
  • holds the whole of the emission: the plume integrates to the emission over the wind
  • is the emission times a number that depends on nothing else about the stack
  • is highest on the axis, equal either side of it and gone far to the side

AE-11

The curve of the figure lies on 400 distances at an equal ratio from 100 m to 10 km. Its maximum is the one that an independent search finds, in every class, and no point of the curve or neighbour of it is higher. In the classes C and D a taller stack, from 30 m to 120 m, gives a lower maximum when the wind at the stack is the same.

AERMOD

Evidence, 4 tests
  • tests/kernel/aermod.test.ts
  • lays the curve on 400 distances from 100 m to 10 km at an equal ratio
  • finds the maximum that an independent search finds, in every class
  • has a maximum that no point of the curve and no neighbour of it exceeds
  • gives a lower maximum for a taller stack when the class and the wind at the stack are the same

AE-12

The illustrative weather is five years of hourly records made from a seed, 43,824 hours with the leap day of 2020. The same seed gives the same weather and another seed gives another. Every record is in the range of what it means, and stable classes come at night and unstable ones only by day, as the key of Table 4.1 says. It looks like weather, with a mean wind near 4 m/s, every class present, neutral the most common, one prevailing wind, and harder wind in winter and in the afternoon.

AERMOD

Evidence, 8 tests
  • tests/kernel/aermod.test.ts
  • is five years of hourly records, with the leap day in 2020
  • is made once and kept
  • is the same for the same seed and different for another
  • keeps every record in the range of what it means
  • gives the stable classes at night and the unstable ones only by day, as the key of the Handbook does
  • looks like weather: a mean wind near four, every class present, neutral the most common and a prevailing wind
  • blows harder in winter than in summer, and harder in the afternoon than before dawn
  • refuses a seed or a list of years it cannot use

AE-13

The calendar knows the leap years and names every day of every year, so that each day follows the one before it. It refuses a day that the year does not have. It puts 90, 91, 92 and 92 days in the quarters of an ordinary year, and one more in the first quarter of a leap year.

AERMOD

Evidence, 5 tests
  • tests/kernel/aermod.test.ts
  • knows the leap years
  • names the day of the year
  • refuses a day that the year does not have
  • walks every day of every year to a date that the next day follows
  • puts 90, 91, 92 and 92 days in the quarters of an ordinary year and one more in the first of a leap year

AE-14

The rank tables are Table 1 of Appendices N and T, row by row. They cover every count of days from 1 to 366 once, and give the nearest rank above the percentile. The nth highest of a list agrees with sorting, and of equal values it takes the one that comes first. The annual mean is the mean of the quarterly means, so a quarter counts the same however many days it has.

AERMOD

Evidence, 7 tests
  • tests/kernel/aermod.test.ts
  • say which highest day of a year is the 98th and the 99th percentile, as Table 1 of Appendices N and T do
  • cover every count from 1 to 366 once, and give the nearest rank above the percentile
  • refuse a count of days that a year cannot have
  • picks the nth highest and, for equal values, the one that comes first
  • refuses a rank that the list does not have
  • agrees with sorting
  • takes the annual mean as the mean of the quarterly means, so a quarter counts the same however many days it has

AE-15

A number is read as the decimal that prints for it, so that a value such as 1.005 is cut off or rounded by its digits and not by the binary number below them. Cutting off and rounding half up agree with whole-number arithmetic on every decimal with up to five places. A fraction is rounded half up exactly, with no drift on a tie.

AERMOD

Evidence, 9 tests
  • tests/kernel/aermod.test.ts
  • read a number as the decimal that prints for it
  • cut off and round the way the appendices say
  • read a number that has a tail of digits by the digits it has
  • agree with whole-number arithmetic on every decimal with up to five places
  • cut off at most the unit of the last place, round to within half of it and change nothing twice
  • keep their order
  • refuse what is negative, is not a number or asks for places they do not keep
  • rounds a fraction half up and does not drift on a tie
  • refuses a negative fraction

AE-16

The expected number of PM10 exceedances reproduces Examples 1, 2 and 3 of Appendix K, from the 2.36 of the first to the 2.19 of the third. A quarter or a year that lands on a tie rounds up, the sums agree with a whole-number formula on every quarter given, equation 3 reduces to equation 1 when each stratum has one sample, and the rate 1.05 rounds to 1.1.

AERMOD

Evidence, 9 tests
  • tests/kernel/aermod.test.ts
  • gives Example 1: one exceedance in 39 of 92 days is 2.36, and with 2.30, 0 and 0 the year is 4.66, which is 4.7
  • rounds a quarter that lands on a tie up, and does not let binary arithmetic move it
  • rounds a year that lands on a tie up: 1.15 and 2.00 make 3.15, which is 3.2
  • agrees with an integer formula on every quarter and every year of three quarters it is given
  • gives Example 2: a first exceedance that is not scaled is 1.0, then 1.2 makes 2.2, and the three years give 0.7
  • gives Example 3: 14 strata and 92 days, with 2 exceedances among 6 samples in one of them, is 2.19
  • reduces equation 3 to equation 1 when each stratum has one sample
  • rounds the rate 1.05 to 1.1, which is the lowest rate of nonattainment
  • refuses quarters and strata that cannot be real

AE-17

The four forms carry the levels of 40 CFR Part 50. They are 35 and 9 micrograms per cubic metre for PM2.5, 150 micrograms per cubic metre with one expected exceedance a year for PM10, and 75 parts per billion for sulfur dioxide. A name that is not a form is refused.

AERMOD

Evidence, 2 tests
  • tests/kernel/aermod.test.ts
  • carry the levels of 40 CFR Part 50
  • refuse a name that is not a form

AE-18

The proofs about a day, an exceedance and a design value are about the formulas that the engine runs. A day read by a monitor is below the model by less than two tenths for a mean and one tenth for a highest hour, and never above it. A day of PM10 is an exceedance from 155. A mean of three values kept in tenths is rounded as the whole-number formula does.

AERMOD

Evidence, 4 tests
  • tests/kernel/aermod.test.ts
  • reads a day below the model by less than two tenths for a mean and one tenth for a highest hour, and never above it
  • reads a day from the hours that start at an index, and keeps every hour in whole tenths
  • counts a day of PM10 as an exceedance from 155, which is where Appendix K rounds a day above 150
  • rounds a mean of three values kept in tenths as the whole-number formula does, and meets the level below half a unit above it

AE-19

Worked cases, each made by hand, show where a monitor and a model part. A day of 35.37 is 35.3 to a monitor and a design value of 35 that meets the standard, and a model reads it as over. The hour 35.49999 stays 35.4 for a monitor, and 35.5 gives 36. The annual form rounds to a tenth and the model rounds nothing. Sulfur dioxide becomes parts per billion and takes the highest hour of each day. The counts of three years are averaged and rounded to a tenth, and the peak hour keeps the weather it came in.

AERMOD

Evidence, 9 tests
  • tests/kernel/aermod.test.ts
  • reads 35.37 as a monitor does, which is 35.3 and a design value of 35 that meets the standard, and as a model, which exceeds it
  • does not round the hour up: 35.49999 stays 35.4 for a monitor and 35.5 is a design value of 36
  • meets as both when the hours are below the level
  • takes the rank that the table gives for the days of the year
  • gives the annual form its own rounding to a tenth, and the model reading nothing
  • turns a concentration of sulfur dioxide into parts per billion, and takes the highest hour of each day
  • counts a day of PM10 as an exceedance for a monitor only from 155 and for a model from above 150
  • averages the counts of three years and rounds the result to a tenth
  • keeps the peak hour with the weather it came in

AE-20

Over the five years the engine gives a row for every year and a window for every three. The day it takes in a year is the one that an independent sort puts at the rank of the table. A monitor never reads above a model, and by less than the cutting off at a tenth can take, and never counts more days of PM10. The value of the model is the mean of the years, the peak is the highest hour of the record, and moving the background moves a model by exactly that much. The defaults start where the figure starts, with a monitor reading 35 where the model reads just over it.

AERMOD

Evidence, 10 tests
  • tests/kernel/aermod.test.ts
  • has a row for every year and a window for every three
  • takes in each year the day that an independent sort puts at the rank of the table
  • is the mean of the days in each quarter, then the mean of the four, for the annual form
  • never reads a monitor above a model, and by less than the two cuts-off at a tenth can take
  • never counts more days for a monitor than for a model
  • moves by exactly the background in the mean of a model for every form that takes a rank or a mean
  • is the mean of the years for a model, and the peak is the highest hour of the record
  • puts the default design values where the figure starts: a monitor reads 35 where the model reads just over it
  • starts each of the other three forms where the two readings part
  • refuses an input that is not valid

AE-21

A receptor is placed in the plume at its along-wind and cross-wind distance in every hour. Straight downwind it gets the plume of the equation. It gets nothing upwind, nothing crosswind and nothing nearer than the spread formulas hold for, and a bearing or distance that is not valid is refused. The wind rose puts a steady wind from the west-southwest in the sector toward the east-northeast.

AERMOD

Evidence, 5 tests
  • tests/kernel/aermod.test.ts
  • gives the plume of the equation at a receptor straight downwind, in every hour
  • puts a receptor off the line of the plume at its along-wind and cross-wind distances
  • gives nothing upwind, nothing crosswind, and nothing nearer than the spread formulas hold for
  • refuses a bearing or a distance that is not valid
  • puts a steady wind from the west-southwest in the sector toward the east-northeast

AE-22

The receipt of a plume and the receipt of a design run are the same for the same input and different when any input moves. Running a design again changes nothing.

AERMOD

Evidence, 2 tests
  • tests/kernel/aermod.test.ts
  • puts equal inputs to equal bits and a changed input to a changed receipt
  • does not change when it is run again, and changes its receipt when any input moves

RS-09

A run-off triangle has from two to forty origin years, and each has one amount fewer than the year before it. Every amount is a finite number, and every development year that has a successor adds up to more than zero, or no factor could be found. A zero or a negative amount is allowed where its column still adds up to more than zero. A message names the origin year or the development year, counting from one. The first origin year is held to the number of years, since no year comes before it, and a later one to the year before it.

Reserving and ESG

Evidence, 7 tests
  • tests/kernel/reserving.test.ts
  • refuses too few and too many origin years
  • names the origin year with the wrong number of amounts, counting from one
  • holds the first origin year to the number of years, because no year comes before it, and says amount for one
  • refuses an amount that is not a finite number, after the shape
  • refuses a development year that adds up to zero, and names it counting from one
  • does not look at the last development year, which no factor takes from
  • allows a zero or a negative amount where the column still adds up to more than zero

RS-10

The amounts of each development year are added from left to right into running totals, and taken back out of them. The two are inverses of each other for whole amounts, keep the shape and check it. The amounts of Taylor and Ashe give the running totals that the vignette prints as the latest amounts.

Reserving and ESG

Evidence, 4 tests
  • tests/kernel/reserving.test.ts
  • turns the Taylor and Ashe amounts into the running totals that the vignette prints as the latest amounts
  • is a sum from left to right
  • are inverses of each other for amounts that are whole numbers
  • keeps the shape, and checks it

RS-11

The development factors of the RAA triangle are the nine that the vignette prints, to the three decimals it prints, and the ones that an independent script gives, to the last digit but a few. A factor is the total of the next year over the total of this one, for the origin years that have both. It is a mean of the link ratios with the earlier amounts as weights, it lies between the smallest and the largest of them, and it agrees with exact fractions. The argument is checked before anything is done.

Reserving and ESG

Evidence, 7 tests
  • tests/kernel/reserving.test.ts
  • gives the factors that the vignette prints for the RAA triangle, to the three decimals it prints
  • gives the factors that an independent script gives, to the last digit but a few
  • is the total of the next year over the total of this one, for the origin years that have both
  • is a mean of the link ratios, with the earlier amounts as weights
  • lies between the smallest and the largest link ratio of its year
  • agrees with the exact fractions
  • checks its argument before it does anything

RS-12

On the RAA triangle the chain ladder keeps what was observed and has for the rest the amounts that the vignette prints, to the unit. The ultimate and the reserve of each origin year, and the totals of 213,122.23 and 52,135.23, are the ones that the vignette prints. On the triangle of Taylor and Ashe the reserve of each origin year is the one that the vignette prints, to the unit. The reserve is the ultimate less the latest amount and each total is the sum of its column. The oldest year has nothing to come, a triangle of two origin years is enough, and the ultimate of every origin year agrees with exact fractions to fourteen digits.

Reserving and ESG

Evidence, 8 tests
  • tests/kernel/reserving.test.ts
  • keeps what was observed and has the amounts that the vignette prints for the rest, to the unit
  • gives the ultimate and the reserve of each origin year that the vignette prints
  • gives the totals that the vignette prints
  • gives for the Taylor and Ashe triangle the reserve that the vignette prints for each origin year, to the unit
  • has an oldest origin year that is finished, with nothing to come
  • has the latest diagonal, the ultimate less the latest as the reserve, and the totals as the sums
  • gives the factors again for a triangle with two origin years, and works with no more
  • agrees with the exact fractions, for the ultimate of every origin year

RS-13

What the factors say will be paid in each calendar year to come is listed with the next year first. Each year holds the next development year of every origin year that is still open. Together the years pay out the whole reserve, on every triangle the generator made. A proof shows the same for four origin years.

Reserving and ESG

Evidence, 2 tests
  • tests/kernel/reserving.test.ts
  • has the next calendar year first in its payments, and the year to come of each origin year in its place
  • pays out the whole reserve over the calendar years to come

RS-14

When every amount is scaled by a power of two, the factors stay the same and the ultimates, the reserves and the payments scale by that number exactly. When every origin year is a multiple of the first, the factors are those of the first. The triangle that was given is not changed, and the same triangle gives the same answer on every run.

Reserving and ESG

Evidence, 4 tests
  • tests/kernel/reserving.test.ts
  • leaves the factors alone and scales the reserve by the same number, when every amount is scaled by a power of two
  • gives the factors of the first row, when every row is a multiple of it
  • does not change the triangle that it was given
  • is the same on every run

RS-15

The standard error of Mack needs at least four origin years, because the variance of the last factor is extrapolated from the two before it. It needs every amount above zero, wherever that amount stands. The reason is one of two messages, the shape is looked at first, and a chain ladder that was made from other rows is refused.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/reserving.test.ts
  • is null when the formula can be applied
  • wants four origin years, because the variance of the last year is extrapolated from the two before it
  • wants every amount above zero, wherever it stands
  • looks at the shape first
  • refuses what the formula cannot be applied to, with the reason that mackReason gives
  • refuses a chain ladder that was made from other rows

RS-16

On the RAA triangle the standard error of each origin year is the one that the vignette prints, to the tenth, and that of the whole reserve is the 26,909.01 that it prints, to the hundredth. An independent script gives the variances, the errors and the total to thirteen digits, for this triangle and for the one of Taylor and Ashe. The variances, the squares of the errors and the square of the total agree with exact fractions. The oldest year has no error, and the smallest triangle that can be used has four origin years and a variance for each of three factors.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/reserving.test.ts
  • gives the standard error of each origin year that the vignette prints, to the tenth
  • gives the standard error of the whole reserve that the vignette prints, to the hundredth
  • gives what an independent script gives, to the last digit but a few
  • has no error for the oldest origin year, and the variances of the factors for the rest
  • agrees with the exact fractions: the variances, the squares of the errors and the square of the total
  • is a triangle of four origin years at its smallest, which has a variance for each of three factors

RS-17

The error of the whole reserve is at least that of any one origin year, because the years share their factors. Scaling every amount by a power of two scales every error by it. A triangle whose origin years are all multiples of the first has next to no error. The variance of the last factor is the geometric continuation of the two before it when they do not rise, held to no more than either, and nothing when the earlier one is nothing. What was given is not changed.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/reserving.test.ts
  • has a total at least as large as the error of any single origin year, because the years share their factors
  • scales the errors by the number that scales every amount, when it is a power of two
  • has next to no error when every origin year is a multiple of the first
  • extrapolates the variance of the last factor as the geometric continuation, when the two before it do not rise
  • holds the extrapolated variance to no more than either of the two before it, and to nothing when the earlier one is nothing
  • does not change what it was given

RS-18

A triangle copied from a sheet is read with tabs, spaces, commas or semicolons between the amounts, and with either kind of line end. Cells copied empty or as NA at the end of a line are dropped, and so are blank lines, but NA in the middle of a line is not. Signs, decimals, exponents and the minus sign of typography are read. A text that is not an amount is named with its line and shortened if it is long, and an empty text says that there is nothing to read. A triangle written out is read back as it was, and the two sample triangles come back as the page prints them.

Reserving and ESG

Evidence, 9 tests
  • tests/kernel/reserving.test.ts
  • reads a triangle that was copied with its tabs from a sheet
  • reads spaces, commas and semicolons, and lines that end in a return and a line feed
  • drops the cells that were copied empty or as NA at the end of a line, and blank lines
  • does not drop NA from the middle of a line
  • reads signs, decimals, exponents and the minus sign of typography
  • names the line and the text that is not an amount, shortening a long one
  • says that there is nothing to read
  • gives back the triangle that it was written from
  • gives back the sample triangles as the page prints them

RS-19

A run takes running totals, or the amounts of each development year, which it adds first, and gives the chain ladder and the formula of Mack. It says why when the formula cannot be applied and then gives no error. It refuses a triangle that is not one on either basis, and shares no array with its input. The receipt covers the amounts, the basis, the factors, what comes to be paid and every error, with nothing where there is no error. It is the same for the same amounts, and it changes with the last bit of any amount and with the basis.

Reserving and ESG

Evidence, 9 tests
  • tests/kernel/reserving.test.ts
  • is the chain ladder and the formula of Mack for running totals
  • sums the amounts of each year first when they are not running totals
  • has no standard error, and says why, when the formula cannot be applied
  • refuses a triangle that is not one, whatever the basis
  • does not share its arrays with its input
  • covers the amounts, the basis, the factors, what comes to be paid and every error
  • has nulls where the formula could not be applied
  • changes with the last bit of any amount, and with the basis
  • is the same for the same amounts

RS-20

On the numerical illustration of Annex D of the technical documentation of October 2025, the Smith-Wilson fit finds the convergence parameter and the quasi-constant that the page prints. It gives the vector Q b to its three decimals and every one of the 242 numbers of Table 29 to the fifth decimal, and it prices each of the twenty swaps at par. The search for the parameter runs a few hundred times at most.

Reserving and ESG

Evidence, 5 tests
  • tests/kernel/curve.test.ts
  • finds the convergence parameter that the page prints, and its quasi-constant
  • gives the vector Q b that the page prints, to its three decimals
  • gives every one of the 242 numbers of Table 29 to the fifth decimal
  • prices every one of the twenty swaps at par
  • runs the search once for the root and once for each of the checks, and no more than a few hundred times

RS-21

The table of Annex D was made with the root of the gap, which is 0.12376048 to eight places, and the page prints it as 0.123760. The rule of the documentation asks for the lowest value of six decimals that brings the gap within one basis point. That value is 0.123761, one millionth above the root, and the printed 0.123760 misses the tolerance by a hair. The engine follows the rule, and the test keeps the difference in view.

Reserving and ESG

Evidence, 1 test
  • tests/kernel/curve.test.ts
  • is the lowest value of six decimals that meets the tolerance, one millionth above the root of the table

RS-22

The rule in force is Smith-Wilson up to 29 January 2027 and the closed form from 30 January 2027, and it never goes back to the old one on a later day. A day is written year-month-day, and the calendar knows which centuries have a leap day. A day that is not on the calendar, or that is written another way, is refused, and the message says what it wants.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/curve.test.ts
  • accepts a day of the calendar written year-month-day
  • refuses a day that is not on the calendar and a text that is not written that way
  • knows which centuries have a leap day
  • is Smith-Wilson up to 29 January 2027 and the closed form from 30 January 2027
  • refuses a date that is not a date, and says what it wants
  • never goes back to the old rule on a later day

RS-23

The convergence parameter of the closed form is 11 per cent for every currency but the Swedish krona and 40 per cent for the krona. An undertaking that phases in follows Table 4 year by year from 2027 and ends where the plain value starts, stepping down by the same amount each year within each group. At 40 years past the first smoothing point every one of these values leaves at least 77.5 per cent of the weight on the ultimate forward rate, which is the floor of Article 77a, and 11 per cent is the lowest value of two decimals that does. Before 2027 there is nothing to phase in, and the message says so.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/curve.test.ts
  • is 11% for every currency but the Swedish krona and 40% for the krona
  • follows Table 4 year by year for an undertaking that phases in, and ends where the plain value starts
  • steps down by the same amount each year for the krona and for the others
  • puts at least 77.5 per cent of the weight on the ultimate forward rate 40 years past the first smoothing point, for every convergence parameter in force
  • does not phase in before 2027 and says why
  • refuses a date that is not a date

RS-24

The ultimate forward rate moves by 15 basis points when the rate before the limit is 15 or more away, and stays otherwise. At the boundary of 15 it moves, as the text puts it. Rates are read to a hundredth of a basis point, so a sum of doubles cannot decide a boundary. The rate changes by one step or none, never against the pull and never past it, and it does not fall when the rate before the limit rises. A proof shows the same for every rate.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/curve.test.ts
  • moves the rate by 15 basis points when the rate before the limit is 15 or more away, and not otherwise
  • takes the rate before the limit at the boundary of 15 basis points, which the text puts on the side that moves
  • reads a rate to a hundredth of a basis point, so that a sum of doubles cannot decide a boundary
  • refuses what is not a number
  • changes by one step or none, never by more, never against the pull, and never past it
  • does not decrease when the rate before the limit rises

RS-25

An inflation target falls in one of four buckets, with the edges where paragraph C.4.1 puts them, and a target at or below one per cent falls in the lowest. The expected real rate is rounded to five basis points, up when it is below the rounded rate of the year before and down when it is not, a negative rate included, and a rate already on the grid stays. A year of Annex C gives the euro rate 4.05 per cent from 4.20 when the rounded real rate falls to 2.00 per cent and the target is 2 per cent. It says when the rate does not move and when it rises.

Reserving and ESG

Evidence, 10 tests
  • tests/kernel/curve.test.ts
  • puts a target in one of four buckets, with the edges where paragraph C.4.1 puts them
  • puts a target at or below one percent, a negative one included, in the lowest bucket
  • rises with the target
  • rounded rate, and down when it is not
  • leaves a rate that is on the grid where it is, on either side
  • rounds a negative rate the same way
  • gives a multiple of five basis points within five basis points of the rate, on the side the last year says
  • moves the euro rate from 4.20% to 4.05% when the rounded real rate falls to 2.00% and the target is 2%
  • says when the rate does not move, and when it rises
  • keeps the rate of the year before when the rate before the limit is within 15 basis points of it

RS-26

The function of Wilson is the same from either side, and is the form that the documentation writes in three ways. It is zero at zero, and on the diagonal it is alpha u less half of one minus the exponential of minus two alpha u. It does not overflow where a product of an exponential and a hyperbolic sine would. Its slope and its second derivative are those that the documentation gives, on both sides of the diagonal and across it.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/curve-fit.test.ts
  • is the same from either side
  • is the form that the documentation writes in three ways
  • is zero at zero, and on the diagonal is alpha u less half of one minus exp(-2 alpha u)
  • does not overflow where the product of exp and sinh would
  • has the slope that the documentation gives, on both sides of the diagonal and across it
  • has the second derivative alpha squared H less alpha cubed min of the documentation

RS-27

The fit refuses a setup that cannot be fitted and says which part, an alpha that is not above zero, and instruments that do not fix the curve. It gives the same fit twice for the same alpha and another for another. The price starts at one and the spot is the zero-year limit of the yield. Beyond the last date the forward intensity is the closed form, it is the slope of minus the logarithm of the price, and the yield is its average. The gap is the distance of the forward intensity at the convergence point from the ultimate one.

Reserving and ESG

Evidence, 10 tests
  • tests/kernel/curve-fit.test.ts
  • refuses a setup that cannot be fitted, and says which part
  • refuses an alpha that is not a number above zero
  • refuses instruments that do not fix the curve
  • gives the same fit twice for the same alpha, and a different one for another
  • starts at a price of one, and the spot is the zero-year limit of the yield
  • has the forward intensity of the closed form beyond the last date
  • has the forward intensity that is the slope of minus the logarithm of the price
  • has a yield that is the average of the forward intensity
  • gap is the distance of the forward intensity at the convergence point from the ultimate one
  • refuses a maturity that is not a number of years, zero or more

RS-28

The fit reprices what it was fitted to. Every par swap of a smooth curve is priced at par, for any curve the generator makes, and so is every zero coupon bond at its price, at the maturities it was fitted to and at the odd ones in between. A curve that already sits at the ultimate forward rate stays there. A curve of negative rates is fitted too, because the method needs the instruments to be independent and nothing more.

Reserving and ESG

Evidence, 4 tests
  • tests/kernel/curve-fit.test.ts
  • prices every par swap of a smooth curve at par, for any curve the generator makes
  • prices every zero coupon bond at its price, at the maturities it was fitted to and at the odd ones in between
  • is a curve that sits at the ultimate forward rate when the market already does
  • is fitted, because the method needs the instruments to be independent and nothing more, and prices each swap at par

RS-29

The search takes the lower bound when that is enough. Otherwise it returns an alpha that meets the tolerance and, to the decimals asked for, no lower one does. It agrees with a scan of a coarser step for any curve the generator makes, and a looser tolerance gives a lower alpha and a tighter one a higher alpha. It looks at the convergence point of the last date, which is 40 years after the last liquid point and never before year 60. Options that make no sense, and a tolerance that nothing can meet, are refused.

Reserving and ESG

Evidence, 10 tests
  • tests/kernel/curve-fit.test.ts
  • takes the lower bound when the lower bound is enough
  • meets the tolerance at the alpha it returns, and not one decimal lower
  • leaves alpha as it is found when asked for no rounding
  • rounds to the decimals that are asked for, and each is the lowest that meets the tolerance
  • takes a tolerance that is looser to a lower alpha and one that is tighter to a higher one
  • takes a lower bound that is higher than the root as the answer
  • looks at the convergence point of the last date unless it is told another
  • refuses options that make no sense, and a tolerance that nothing can meet
  • gives the lowest alpha, as a scan of a coarser step would find it, for any curve the generator makes
  • is 40 years after the last liquid point and never before year 60

RS-30

A curve lists 150 years, each with an intensity, an annual rate and a forward, and a spot. It tends to the ultimate forward rate from below and passes it by no more than the tolerance at the convergence point. It keeps the rate at 20 years where the swaps put it. A fit whose price falls to zero or below, which very high swap rates can cause, has no rate for that year, so it is refused with the first such year named, and a curve that is given never has a gap.

Reserving and ESG

Evidence, 5 tests
  • tests/kernel/curve-fit.test.ts
  • lists 150 years, each with an intensity, an annual rate and a forward, and a spot
  • tends to the ultimate forward rate, from below, and passes it by no more than the tolerance at the convergence point
  • keeps the rate at 20 years where the swaps put it
  • refuses a fit whose price falls to zero or below, and names the first year, instead of giving a rate that is not a number
  • gives a rate for every one of the 150 years whenever it gives a curve, so no list has a gap in it

RS-31

The bootstrap of Annex D gives the zero rates that the swaps imply, as an independent Newton-Raphson on equation D.5.9 gives them. It prices every swap at par, for any curve and any choice of maturities, and has one rate for each year to the last. It agrees with the Smith-Wilson fit at every maturity the swaps cover, is flat up to the first maturity, and keeps the forward constant between two maturities that are not a year apart. Zero coupon rates give back the rate at each maturity, with the forward that D.9.3 gives. What cannot be bootstrapped is refused, and the message says why.

Reserving and ESG

Evidence, 13 tests
  • tests/kernel/curve-rules.test.ts
  • gives the zero rates that the swaps imply, as an independent Newton-Raphson on equation D.5.9 gives them
  • prices every swap at par
  • agrees with the Smith-Wilson fit at every maturity the swaps cover, because the swaps fix the curve there
  • is flat up to the first maturity, at the rate of the first swap
  • keeps the forward constant between two maturities that are not a year apart, as the documentation assumes
  • satisfies equation D.5.9 at each step that has a gap, and prices each swap at par
  • prices every swap at par for any curve and any choice of maturities, and has one rate for each year to the last
  • gives a curve of negative rates when the swaps are negative
  • refuses what cannot be bootstrapped, and says why
  • gives back the rate at each maturity it was given
  • is flat up to the first maturity and keeps the forward constant between two maturities
  • has the forward that D.9.3 gives, the ratio of two discount factors to the power of one over the years
  • refuses what the par bootstrap refuses

RS-32

The weight of the last liquid forward rate is one at the start and falls to zero, whatever alpha is. It is one less the exponential of minus a h, over a h, the same in alpha and in the horizon, and it keeps its digits for a small product, to four units in the last place, where a difference of two numbers close to one would lose them. It is continuous where the series gives way to the closed form. The forward rate is a weighted mean of the last liquid forward rate and the ultimate one for every horizon, the first at once and the second in the end. An alpha or a horizon that is not above zero is refused.

Reserving and ESG

Evidence, 7 tests
  • tests/kernel/curve-rules.test.ts
  • is one at the start and falls to zero, whatever alpha is
  • has the closed form (1 - exp(-a h)) / (a h), and it is the same in alpha and in the horizon
  • keeps its digits for a small product, where a difference of two numbers close to one would lose them
  • is continuous where the series gives way to the closed form
  • refuses an alpha or a horizon that is not a number above zero
  • is a weighted mean of the last liquid forward rate and the ultimate one, for every horizon
  • is the last liquid forward rate at once and the ultimate one in the end

RS-33

The extrapolation from the first smoothing point gives the zero rates, the last liquid forward rate and the ultimate forward rate that an independent script gives, to thirteen digits. That holds for a point at 20, 15, 10, 5 and 1 years, for other values of the ultimate rate and of alpha, and for forwards weighted by notionals in the order of the maturities from the point. The zero rates up to the point are those of the bootstrap.

Reserving and ESG

Evidence, 5 tests
  • tests/kernel/curve-rules.test.ts
  • gives the zero rates that an independent script gives for the first smoothing point at 20 years
  • gives the zero rates for a first smoothing point earlier than the last swap, where the forwards after it weigh equally
  • gives the zero rates for other values of the ultimate forward rate and of alpha
  • weighs the forwards by the notionals, in the order of the maturities from the first smoothing point
  • leaves the zero rates up to the point as the bootstrap made them

RS-34

The forward just before the point is the only leg, with the whole weight, when the point is the longest maturity, and the first leg runs from zero when the point is the first maturity. With gaps between the maturities the forward before the point is the constant forward of the bootstrap. The curve is continuous at the point, and a point at the last year has nothing after it.

Reserving and ESG

Evidence, 5 tests
  • tests/kernel/curve-rules.test.ts
  • has the forward just before the point as the only leg, with the whole weight, when the point is the longest maturity
  • has a first leg that runs from zero when the point is the first maturity
  • has a forward before the point that is the constant forward of the bootstrap, when the maturities have gaps
  • is continuous at the point, with a zero rate one year after it that is near the rate at it
  • has no extrapolation when the first smoothing point is the last year

RS-35

A curve run builds the Smith-Wilson curve before 30 January 2027 and the closed form from that day, with the alpha of the day, and it says that the date decided. It takes the rule that is asked for whatever the date, and says that it was a choice. It uses the alpha of the krona and the phasing in when they apply, gives the same rates under both rules where the swaps fix the curve and different ones after, fits zero coupon rates too, and uses the notionals that it is given. A date that is not a date is refused under either rule, and so is a point that is not a maturity.

Reserving and ESG

Evidence, 9 tests
  • tests/kernel/curve-rules.test.ts
  • builds the Smith-Wilson curve before the day the new rule applies, and says that the date decided
  • builds the closed form from the day it applies, with the alpha of that day
  • takes the rule that is asked for whatever the date, and says that it was a choice
  • uses the alpha of the krona, and the phasing in, when they apply
  • gives the same rates under both rules where the swaps fix the curve, and different ones after
  • fits zero coupon rates too
  • uses the notionals that it is given
  • refuses a date that is not a date under either rule, and a point that is not a maturity
  • is the same on every run

RS-36

A payment at the end of year t is discounted by one over one plus the rate of that year, to the power t. Payments add, nothing is worth nothing, and the value is linear in the payments and falls at a higher rate when no payment is negative. A payment after the last year of the curve, and a payment that is not a number, are refused.

Reserving and ESG

Evidence, 5 tests
  • tests/kernel/curve-rules.test.ts
  • discounts a payment at the end of year t by one over one plus the rate of that year, to the power t
  • adds the payments, and is nothing for no payments
  • is linear in the payments
  • is worth less at a higher rate, for payments that are not negative
  • refuses a payment after the last year of the curve and a payment that is not a number

RS-37

The receipt of a curve covers every input, the rule that was applied and how it was chosen, alpha and the rate of every year. It is the same for the same inputs, it does not depend on the type of the arrays, and it changes when any input changes, even by the last bit.

Reserving and ESG

Evidence, 4 tests
  • tests/kernel/curve-rules.test.ts
  • covers every input, the rule that was applied and how it was chosen, alpha and the rate of every year
  • changes when any input changes, even by the last bit
  • is the same for the same inputs
  • does not depend on the type of the arrays

RS-38

After the point the zero rate lies between the rate at the point and the forward for every horizon. The forward runs from the last liquid forward rate to the ultimate one, between the two the whole way and faster for a higher alpha, and a curve that already sits at the ultimate rate stays there. What does not fit is refused in a fixed order, and the message says what.

Reserving and ESG

Evidence, 6 tests
  • tests/kernel/curve-rules.test.ts
  • has a continuously compounded zero rate after the point that lies between the rate at the point and the forward, for every horizon
  • has a forward that runs from the last liquid forward rate to the ultimate one, between the two the whole way
  • moves to the ultimate rate faster for a higher alpha
  • stays at the ultimate forward rate from the start when the curve already sits there
  • refuses what does not fit, and says what
  • checks the maturities before the notionals, and the notionals before the rates

SC-06

The rule is as the July 2020 text of the Basel Committee prints it. The multiplier is 1, the hedging disallowance is 0.01 and the risk-weighted assets are 12.5 times the capital. The seven specified currencies, and every risk weight and every correlation of interest rates, FX and counterparty credit spreads, are those of Tables 3 to 7 and paragraphs MAR50.54 to MAR50.65. Every matrix is symmetric, with a diagonal of one and entries from zero to one.

SA-CVA

Evidence, 6 tests
  • tests/kernel/sacva.test.ts
  • has the rule parameters of MAR50.41, MAR50.53 and MAR50.1
  • has the five risks in the order that the capital is added up in, and the seven specified currencies of MAR50.56
  • has the risk weights and the correlations of interest rates, MAR50.56 to MAR50.58, as printed
  • has the weight and the correlation across currencies of FX, MAR50.59 to MAR50.62
  • has the weights, the tenors and the correlations of counterparty credit spreads, MAR50.63 to MAR50.65, as printed
  • has matrices that are symmetric, with a diagonal of one and entries from zero to one

SC-07

A specified currency and the reporting currency have six interest rate factors, and any other currency has two. The weighted sensitivity of a line is its sensitivity times the weight of its factor, which is the weight that the tables give for each factor of each risk, and for each sector of credit spread, for investment grade and for the rest. A bucket of one factor and no hedge has a capital equal to its weighted sensitivity, which is the weight times the change that one shift makes, over the size of the shift.

SA-CVA

Evidence, 6 tests
  • tests/kernel/sacva.test.ts
  • gives six interest rate factors for a specified currency and the reporting currency, and two for any other
  • gives the rest by risk
  • gives the weight of MAR50.51 for each line
  • is the weighted sensitivity itself for one factor, as the weight times the change that one shift makes, over the size of the shift
  • takes the weight of every factor of a specified currency
  • takes the weight of every sector, for investment grade and for the rest

SC-08

The correlation of two factors in a bucket is the entry of the table for a specified currency. It is 0.4 for the two factors of any other currency and for the volatilities of rates. For two credit spreads it is the product of three factors, one for the tenors, one for the names and one for the qualities. The two sectors of bucket 1 make one bucket, with their own weights and one correlation between their names.

SA-CVA

Evidence, 4 tests
  • tests/kernel/sacva.test.ts
  • takes the correlation of every pair of factors of a specified currency from the table, and the weights of both
  • takes one correlation of 0.4 and one weight for the two factors of a currency that is not specified, and for the volatilities of rates
  • takes the correlation of two spreads as the product of the three factors of MAR50.65(4)
  • puts the two sectors of bucket 1 in one bucket, with their own weights and one correlation between their names

SC-09

For one factor with an exposure A and a hedge of L times it, the capital of the bucket is A times the square root of (1 - L)^2 + R L^2, with R the hedging disallowance. A perfect hedge leaves A times the square root of R, not zero. The capital is lowest at L = 1 / (1 + R), and is that of no hedge again at 2 / (1 + R). A hedge of the same sign as the CVA offsets it, one of the opposite sign is more exposure, and a hedge alone is exposure of its own. The net weighted sensitivity of a factor enters the correlation and its hedge enters its own R term only. A share of the hedges scales every hedge and nothing else, and the capital at each share is listed in order.

SA-CVA

Evidence, 7 tests
  • tests/kernel/sacva.test.ts
  • leaves K(L)^2 = A^2 ((1 - L)^2 + R L^2) for a hedge of L times the exposure, which is what MAR50.53(1) says for one factor
  • does not take a bucket to zero with a perfect hedge, by the square root of R
  • has its lowest capital at a ratio of 1 / (1 + R), and the capital of no hedge again at 2 / (1 + R)
  • takes a hedge of the same sign as the CVA off it, and a hedge of the opposite sign as more exposure, and a hedge alone as exposure of its own
  • takes the hedge of another factor of the bucket into the correlation, and the hedge of a factor into its own R term only
  • scales the hedges and nothing else with withHedgeRatio, and does not make a minus zero
  • gives the capital of a book at each ratio of hedging, in the order of the ratios, and the unhedged capital at none

SC-10

The capital of a class puts its buckets together at 0.5 for every pair of currencies, 0.6 for every pair of FX buckets and the entries of Table 6 for credit, times the multiplier. The sum of the weighted sensitivities of a bucket enters at no more than its capital and at no less than minus it. A one sided bucket is held to its capital, a bucket whose sum is smaller is left alone, and a bucket of one factor is never held. The class says which of its buckets were held, and the quantity under its root is that of the book with its hedges.

SA-CVA

Evidence, 9 tests
  • tests/kernel/sacva.test.ts
  • adds two currencies at a correlation of 0.5, MAR50.55
  • adds two FX buckets at a correlation of 0.6, for delta and for vega
  • takes the correlation of every pair of the seven credit buckets from the table
  • does not clip a bucket of one factor, whose sum is its K to the last digit, with a hedge or without
  • clips the sum of the weighted sensitivities of a bucket to its K, which is what a one sided bucket does
  • leaves the sum alone when its size is below K, and says that it was not clipped
  • takes the clipped sum of each bucket across buckets, with a bucket that is clipped and one that is not
  • gives the radicand that the capital of a class is the root of, times the multiplier
  • gives the radicand of the book with its hedges, and not the one it would have without them

SC-11

The capital is the sum of the capital of the three delta classes and of the two vega classes, and the risk-weighted assets are 12.5 times it. The book without its hedges is worked class by class, and the difference is the benefit of the hedges. A class that the book does not name has no buckets and no capital, and a book of zero sensitivities has none. Each factor in the result carries what the book said, its weight and its weighted sensitivities, under a name that a person reads.

SA-CVA

Evidence, 7 tests
  • tests/kernel/sacva.test.ts
  • adds the capital of the three delta classes and of the two vega classes, and the two together, MAR50.42
  • is 12.5 times the capital in risk weighted assets, MAR50.1
  • has the capital of the book without its hedges as the unhedged capital, class by class, and the difference as the benefit of the hedges
  • has a class that the book does not name at zero, with no buckets
  • is zero for a book of zero sensitivities, and nothing is floored
  • names each factor the way a person reads it, for every risk
  • gives what the book said, the weight, and the weighted sensitivities of MAR50.51 and MAR50.52 for each factor

SC-12

Positions that name the same line are added before anything else, in the CVA and in the hedge. Positions that differ in the risk, the bucket, the factor or the name are not netted. The capital does not depend on the order of the positions, to the last digit when the amounts are whole. The factors of a bucket are listed in the order of the table, the buckets of a class by currency or by sector, and the credit lines by name and then tenor.

SA-CVA

Evidence, 4 tests
  • tests/kernel/sacva.test.ts
  • adds positions that name the same line before anything else, in the CVA and in the hedge
  • does not net lines that differ in the risk, the bucket, the factor or the name
  • does not depend on the order in which the positions come, to the last digit when the amounts are whole
  • lists the factors of a bucket in the order of the table, the buckets of a class by currency or by sector, and the lines of credit by name and then tenor

SC-13

A book that the rule cannot take is refused, and the message names the position, counting from one. A book has a reporting currency of three capital letters and from one to 200 positions, and every sensitivity is a finite number of at most 1,000,000,000,000 in size. A factor is one that the risk has in that bucket, and the message lists the ones it has. A credit spread has a sector of the table, an entity, a quality and a group, and the positions of one entity agree on all three. The checks of a position run in a fixed order, and so do the positions.

SA-CVA

Evidence, 9 tests
  • tests/kernel/sacva.test.ts
  • wants a reporting currency of three capital letters, and wants it before anything else
  • wants a position, and no more than 200, and counts before it looks at one
  • names the position that is wrong, counting from one
  • wants a sensitivity that is a finite number, of a size that is at most 10^12, for the CVA and for the hedge
  • wants the factor to be one that the risk has in that bucket, and lists the ones it has
  • wants a position that is not a credit spread to have a currency for a bucket, and no name, quality or group
  • wants a credit spread to have a sector of the table, a name, a quality and a group, in that order
  • wants the positions of one entity to agree on its sector, its quality and its group
  • looks at the checks of one position in order, and at the positions in order

SC-14

A second program that shares no code with the engine works the capital in exact fractions and takes each square root once. For 26 books that use every risk, with a bucket held on each side and one that is not held, the capital of every class, with the hedges and without, and the capital of the book agree with the engine to a relative error under 3e-15. The saved answers are what the program says now, so that nobody edited them by hand.

SA-CVA

Evidence, 3 tests
  • tests/kernel/sacva.test.ts
  • scripts/verify/sacva_oracle.py
  • tests/support/sacva-oracle.json
  • has books that use every risk, a clipped bucket on each side, and a bucket that is not clipped
  • gives the capital of every class, hedged and not, within 3e-15 of the exact arithmetic of a program that shares no code with it
  • has saved answers that are what the program says now, so that the file was not edited by hand

SC-15

MAR50 has no rule for where the capital comes from, and the product gives one, the Euler allocation. The part of a bucket is what the capital of its class changes by along the bucket, and the factors of a bucket share its part, the CVA and the hedge of each apart. The parts add up to the capital for every book of the second program. A hedge that offsets takes a negative part, a bucket that the others more than offset takes a negative part, and a bucket with no capital takes none. A minus zero never comes out.

SA-CVA

Evidence, 6 tests
  • tests/kernel/sacva.test.ts
  • adds up to the capital, for every book of the independent program
  • gives each bucket its part of the class, and the factors of a bucket the whole of the part of the bucket
  • is, for a bucket, what the capital changes by when the bucket is scaled, the Euler allocation: the derivative along the bucket
  • is negative for a hedge that offsets, and positive for the CVA that it offsets
  • is negative for a bucket that the others more than offset, and a factor of it that has no CVA gets no minus zero
  • is zero for a bucket whose capital is zero, and a minus zero never comes out

SC-16

Over generated books of up to 14 positions, the capital doubles when every sensitivity doubles and halves when they halve, to the last digit. It is the same with every sign reversed, and with the positions in another order when the amounts are whole. The capital of a class is a real number and not above the sum of its buckets. The capital of the book is delta plus vega, not below its largest class, and the risk-weighted assets are 12.5 times it. The shares add up to the capital, and the benefit of the hedges is never more than the capital without them.

SA-CVA

Evidence, 7 tests
  • tests/kernel/sacva.test.ts
  • doubles when every sensitivity doubles, and halves when it halves, to the last digit
  • is the same for a book with every sign reversed
  • is the same in any order of the positions when the amounts are whole
  • is not above the sum of the capital of the buckets of a class, because no correlation is above one
  • is not above the sum of its classes, and at least as large as the largest
  • has shares that add up to the capital
  • never has more hedge benefit than the unhedged capital

SC-17

The receipt of a calculation holds the rule, the book as the calculation took it, which is netted and in a fixed order, and what came out. It is the same for the same book in another order when its amounts are whole, and different when any input moves by one unit. It lists the lines by risk before the bucket, and never carries a minus zero, which would give another hash.

SA-CVA

Evidence, 4 tests
  • tests/kernel/sacva.test.ts
  • has the rule, the book as the calculation took it, which is netted and in a fixed order, and what came out
  • lists the lines by risk before the bucket, so that a currency that comes earlier in the alphabet does not come earlier in the list
  • is the same for the same book in another order when its amounts are whole, and different when any input moves by one unit
  • does not carry a minus zero, which would give a different hash

IC-08

The tables and rules are as the IAIS Level 2 text of 5 December 2024 prints them. Table 6 has the five life risks, symmetric, and only mortality and longevity offset each other, at minus 25 per cent. The four catastrophe scenarios are independent. Table 16 has seven rows, and each direction of the spread stress has the six by six table left when the other is taken out. Table 34 has life and non-life independent and every other pair at 25 per cent. Table 33 has the factors of operational risk, with growth above 20 per cent. The tax rules are those of L2-339 and L2-348 to L2-353, and the limits on resources those of L2-122, L2-127 and L2-129.

ICS

Evidence, 9 tests
  • tests/kernel/ics.test.ts
  • has the five life risks in the order of Table 6 of L2-143, with the correlations as printed
  • has a life table with ones on the diagonal, symmetric, in which only mortality and longevity offset each other
  • has the four catastrophe scenarios of L2-199, which are independent
  • has the seven rows of Table 16 of L2-203 as printed
  • has for each direction of the spread the six by six table that is left when the other direction is taken out of Table 16
  • has the five categories and Table 34 of L2-335 as printed, in which life and non-life are independent and every other pair is 25%
  • has the factors of Table 33 of L2-331 and the growth threshold of 20%
  • has the rules of the tax effect of L2-339 and L2-348 to L2-353
  • has the limits on capital resources of L2-122, L2-127 and L2-129, and the shares of the Tier 2 basket

IC-09

The life charge is the root of the form of Table 6, and a longevity charge under half the mortality charge lowers it below what mortality alone sets, which is what the negative entry means. The catastrophe charge is the root of the sum of the squares of the four scenarios. The market charge is read from Table 16 in the row of the larger of the two spread stresses, and the smaller has no effect. When the stresses are equal and not zero the text gives no direction, so the engine takes the larger of the two results and says that there was a tie. With no spread charge there is none.

ICS

Evidence, 8 tests
  • tests/kernel/ics.test.ts
  • gives a life charge that is the root of the form of Table 6
  • lets a longevity charge lower the life charge that mortality set, which is what the negative entry of Table 6 means
  • gives a catastrophe charge that is the root of the sum of the squares of the scenarios
  • gives a market charge from Table 16, with the spread in the row of its direction
  • counts the spread in the row of the larger of the two stresses, and the smaller has no effect
  • ignores the smaller of the two spread stresses as long as it stays the smaller
  • takes the larger of the two results when the stresses are equal, which the text leaves open, and says so
  • has no tie when there is no spread charge

IC-10

The operational charge of a line is the larger of its premium charge and its liability charge, plus the growth charge, with the charge on life business without risk added for the group, at the factors of Table 33. Premium counts as growth only above 120 per cent of the year before, at the factor of its line and on top of the larger charge, and at exactly 120 per cent or after a fall there is none. The engine says which of premium and liabilities decides, and takes the premium when they are equal. A group with no business has none. The charge is added after the aggregation and is never diversified.

ICS

Evidence, 6 tests
  • tests/kernel/ics.test.ts
  • is for each line the larger of the premium charge and the liability charge, with the growth charge and the charge of non-risk business
  • charges growth on the premium above 120% of the year before, at the factor of its line, and in addition to the larger charge
  • charges no growth at exactly 120% of the year before, and none when the premium fell
  • says which of the premium and the liabilities decides, and takes the premium when they are equal
  • is zero for a group with no business, and adds the three parts in the order of the formula
  • adds the operational charge after the aggregation, so that it is never diversified

IC-11

The five categories are aggregated with Table 34, so life and non-life, which are independent, add in quadrature, and five equal charges give the root of 9.5 times the square. The tax effect comes off the insurance risk charge, and the charge for the non-insurance entities is added after it with no tax effect of its own. A group with nothing has a requirement of zero. The undiversified sum is every charge and the operational charge, and two diversification figures, between the categories and within them, explain the rest. The sample group has the charges that the second program confirms.

ICS

Evidence, 6 tests
  • tests/kernel/ics.test.ts
  • aggregates the five categories with Table 34, and life and non-life, which are independent, add in quadrature
  • gives five equal charges the root of 9.5 times the square, since nine of the ten pairs are correlated at 25%
  • takes the tax effect off the insurance risk charge, and adds the non-insurance charge after it
  • is zero for a group with nothing, and says nothing of a division by zero
  • has an undiversified sum that is every charge and the operational charge, and two diversification figures that explain the rest
  • gives the charges of the sample group, which the independent program confirms below

IC-12

The group effective tax rate weights the rate of each entity by the earnings that it made in the previous three years. The example that the IAIS prints, three entities at 30, 25 and 20 per cent, gives 23.03 per cent. Each loss is set to zero in its own year and not against the sum of the three years. The rate of one entity is its own, and the unit of the earnings does not change the result. When no entity made a profit there is nothing to weight the rates by, and the engine refuses, as it does for an entity that is not one.

ICS

Evidence, 5 tests
  • tests/kernel/ics.test.ts
  • gives 23.03% for the example that the IAIS prints, from 30% * (500 + 700 + 0) + 25% * (1,000 + 0 + 900) + 20% * (2,000 + 500 + 1,500) over 7,100
  • sets each loss to zero in its own year, and does not set the sum of the three years to zero
  • is the rate of an entity that stands alone, and is not changed by the unit that the earnings are in
  • refuses when no entity made a profit, because there is nothing to weight the rates by
  • refuses an entity that is not one, with a message that names it

IC-13

Under the default rule the tax effect is 80 per cent of the notional effect, which is the requirement times the group effective tax rate. A supervisor can limit it by four components. Component a is the smaller of the share by liabilities of the notional effect and the carry-back capacity of each tax sub-group, summed, less 15 per cent. Component b is half of five years of earnings times the rate, and zero for a projected loss. Component c is a net deferred tax liability and d a net asset held to 15 per cent of the requirement, and a group has one of them. The sum a plus b plus c less d is held between zero and 80 per cent of the notional effect. The IAIS example gives 2,005.

ICS

Evidence, 11 tests
  • tests/kernel/ics.test.ts
  • is 80% of the notional effect, which is the requirement times the rate, under the default rule of L2-348
  • gives 2,005 for the example that the IAIS prints, with every component as printed
  • is held to 80% of the notional effect when the components are larger
  • is zero when a net deferred tax asset takes the sum of the components below zero
  • holds the net deferred tax asset to 15% of the requirement
  • has a net liability in c and a net asset in d, and never both
  • sets component b to zero when the group projects a net loss, whatever its earnings were
  • shares the notional effect by liabilities and counts, for each sub-group, the smaller of its share and its capacity
  • has no component a without sub-groups, or when none has a capacity
  • gives 80% of the requirement as the tax effect at a rate of one under the default rule, and none at a rate of zero
  • refuses a tax rule that is not one, with a message that says what is wrong

IC-14

Tier 1 Limited counts up to 10 per cent of the requirement, or 15 per cent when the part above 10 has a loss absorbency mechanism. What is above the limit moves to Tier 2, which counts up to 50 per cent. The Tier 2 basket is half of the pension fund asset, all of the deferred tax asset and a tenth of the software intangibles, held to 15 per cent. A mutual counts Tier 1 Limited up to 30 per cent, Non-Paid-Up up to 10 per cent, and Tier 1 Limited with Tier 2 up to 60 per cent. The limits are shares of the requirement after tax and with the non-insurance charge, so they rise and fall with it, and what does not count is exactly what is above them. The text defines no ICS ratio.

ICS

Evidence, 15 tests
  • tests/kernel/ics.test.ts
  • counts Tier 1 Limited up to 10% of the requirement, and up to 15% when what is above 10% has a loss absorbency mechanism
  • moves what is above the limit on Tier 1 Limited to Tier 2, where it meets the limit on Tier 2
  • counts Tier 2 up to 50% of the requirement
  • counts none of the Non-Paid-Up capital of a group that is not mutual
  • holds the Tier 2 basket to 15% of the requirement, with its three items at 50%, 100% and 10%
  • counts for a mutual group Tier 1 Limited up to 30%, Non-Paid-Up up to 10%, and the two with Tier 2 up to 60%
  • does not read a loss absorbency mechanism for a mutual group, whose limit is the same with or without one
  • leaves out of the total of a mutual group only what is above 60% for Tier 1 Limited and Tier 2 together
  • leaves out exactly what is above the limits, so that what counts and what does not make up what is held
  • has limits that rise and fall with the requirement, and nothing counts against a requirement of zero but Tier 1 Unlimited
  • has a cover that is the qualifying capital over the requirement, and is infinite for a requirement of zero
  • takes the limits from the requirement that the group has, after tax and with the non-insurance charge
  • has resources that count within their limits, and what counts and what does not count make up what is held
  • counts at least as much against a larger requirement, because every limit is a share of it
  • refuses resources that are not any, with a message that says what is wrong

IC-15

A charge below zero is refused with a message that names it and says that a charge is the fall in capital resources under its stress, so a stress that raises them has a charge of zero. A charge that is not finite, or is above 1,000,000,000,000 in size, is refused by name. A wrong exposure, non-insurance charge or tax rule is refused with a message that says what is wrong. The checks run in a fixed order, charges first, then exposures, the non-insurance charge, the tax rule and last the resources. A group that gives no resources gets no result for them, which is not resources of zero.

ICS

Evidence, 6 tests
  • tests/kernel/ics.test.ts
  • says which charge is below zero, and why that cannot be
  • says which charge is not a finite number, and which is above the size that the engine takes
  • says which exposure is wrong
  • says what is wrong with the non-insurance charge and with the tax rule
  • refuses resources through the whole engine, and takes none as nothing to count
  • looks at the charges first, then the exposures, then the non-insurance charge, then the tax rule, and last the resources

IC-16

The text has no rule for where the capital comes from. The product gives one, the Euler allocation through three levels. A risk takes its share inside its category, the category takes its share of Table 34, and the part of the risk is the product of the two. The parts add up to the insurance risk charge for every case of the second program. The operational charge is a part of its own, and non-life and credit have a line each. Each part is what the insurance risk charge changes by when its charge is scaled, which a numerical derivative confirms for eleven charges. A longevity charge under a quarter of the mortality charge takes a negative part.

ICS

Evidence, 7 tests
  • tests/kernel/ics.test.ts
  • adds up to the insurance risk charge, for every case of the independent program
  • gives each category its Euler share of Table 34, and the sub-risks of a category the whole of the share of the category
  • lists the parts in the order of the tables, with the operational charge last and the spread once
  • is, for a charge, what the insurance risk charge changes by when the charge is scaled: the derivative along it, through all three levels
  • is negative for a longevity charge that is below a quarter of the mortality charge, which offsets it
  • gives a zero charge a part of zero and never a minus zero, whatever sign its row of the table has
  • gives the operational charge as its own part, whole

IC-17

The text gives a spread charge for an up stress and for a down stress, and does not say which row of Table 16 the larger of the two uses. The engine reads the row of the direction that gave the larger. So a down stress that grows past the up stress turns the row, and the market charge can then fall, because equity is correlated at 75 per cent with the spread under the up stress and at nothing under the down stress. Only when the two are equal and not zero does the engine take the larger of the two results, and the result says so.

ICS

Evidence, 2 tests
  • tests/kernel/ics.test.ts
  • can lower the market charge when a down stress that is larger than the up stress turns the row of Table 16 from up to down
  • has a market charge that is the larger of the two readings in no case but the tie, so that the tie is the one place where the text is not followed to the letter

IC-18

A second program that shares no code with the engine works every case in exact fractions and takes each square root once, to 60 digits. For 50 cases that use both directions of the spread and a tie, every outcome of the tax rule, both lines of operational risk on both of their binds and every limit on capital resources, every figure agrees with the engine to a relative error under 3e-15, and the amounts left out, which are differences of sums, to 1e-14. The saved answers are what the program says now, so that nobody edited them by hand.

ICS

Evidence, 3 tests
  • tests/kernel/ics.test.ts
  • scripts/verify/ics_oracle.py
  • tests/support/ics-oracle.json
  • has cases that use both directions of the spread and a tie, every outcome of the tax rule, both lines of operational risk on both of their binds, and every limit on capital resources
  • gives every figure of every case within 3e-15 of the exact arithmetic of a program that shares no code with it, and the amounts left out, which are differences of sums, within 1e-14
  • has saved answers that are what the program says now, so that the file was not edited by hand

IC-19

Over generated groups, the requirement doubles when every amount doubles, to the last digit, through the tax rule and the limits. The tax effect never takes the requirement below a fifth of the insurance risk charge, and the parts add up to that charge. A larger charge never gives a smaller requirement, except in a pair that offsets and in the spread. Each category charge lies between its largest part and the sum of its parts. The group tax rate lies between the lowest and the highest rate of the entities that made a profit. The tax effect never falls when earnings, the deferred tax liability or carry-back capacity rise, and never rises with the asset.

ICS

Evidence, 7 tests
  • tests/kernel/ics.test.ts
  • doubles when every amount doubles, and halves when it halves, to the last digit, through the tax rule and the limits as well
  • has each category charge between its largest part and the sum of its parts, and the life charge no lower than the root of 15/16 of its largest part
  • has a requirement that the tax effect cannot take below a fifth of the insurance risk charge, and that is never above the charge and the non-insurance charge together
  • has parts that add up to the insurance risk charge, and a part for the operational charge that is the charge
  • never gives a smaller requirement for a larger charge that is not in a pair that offset, or in the spread
  • gives a group rate between the least and the greatest rate of the entities that made a profit, whatever unit the earnings are in
  • gives a tax effect that never falls when the earnings, the deferred tax liability or the carry-back capacity rise, and never rises with the asset

IC-20

The receipt of a calculation holds the rule, every number that went in and every number that came out, in a fixed order. It carries the tax rule with its sub-groups, and no resources as nothing. It is the same for the same input, and different when any input moves by one unit or any choice is turned over. It never carries a minus zero, which would give another hash.

ICS

Evidence, 4 tests
  • tests/kernel/ics.test.ts
  • has the rule, every number that went in and every number that came out, in a fixed order
  • carries the tax rule with its sub-groups, and no resources as nothing
  • is the same for the same input, and different when any input moves by one unit or any choice is turned over
  • does not carry a minus zero, which would give a different hash

SM-08

The tables and weights are those of the sketch calibration, which is illustrative and is not the calibration of ISDA. Every correlation table is symmetric with ones on its diagonal and no entry above one or below zero. The vertices of a rate fall by a tenth for each vertex between them to a floor of a fifth. Credit, equity and commodity buckets have the structure of the methodology with numbers of our own. Every bucket has a weight, a threshold and a label.

SIMM

Evidence, 12 tests
  • tests/kernel/simm.test.ts
  • has %s as a square table that is symmetric, has ones on its diagonal and has no entry above one or below zero
  • has the correlation of two vertices fall by a tenth for each vertex between them, to a floor of a fifth
  • has qualifying credit at a quarter between buckets, a tenth more for the same sector and a tenth more for the same quality
  • has equity at a tenth between buckets, a tenth more inside a group, five hundredths more in the same region and five more for an index
  • has commodity at eight hundredths between buckets, half more inside a group, twelve more inside a family, none for Other and a quarter for the indexes
  • has a weight, a threshold and a label for every bucket of every risk class
  • maps every risk type to one risk class and back
  • has the six sub-curves and the vertices of the methodology, and the two bucket rules of a rate
  • has the weights of rates by group and vertex
  • has the weights of the other risk classes by bucket
  • has the thresholds of every risk class in the calculation currency
  • puts every currency in a volatility group, a threshold group and an FX category

SM-09

Each risk class is worked by hand in the tests. A rate has its weight times its size. Two vertices that offset in part give the root of the form and keep their sum inside the range of K, and two with one sign are cut to K with the side named. Sub-curves correlate at 0.95. Currencies, issuers, names and commodities take the correlation of their rule, and the residual bucket of credit and of equity is added after the root.

SIMM

Evidence, 13 tests
  • tests/kernel/simm.test.ts
  • gives one rate its weight times its size, with the group of its currency and the vertex of its tenor
  • takes the root of the form of two vertices that offset in part, and keeps their sum, which is inside the range of K
  • cuts the sum of two vertices with the same sign to K, and says which side it cut
  • correlates two sub-curves at one vertex by 0.95, so that a hedge on another sub-curve leaves a margin
  • puts two currencies of one group together with 0.3, and takes each as its own bucket
  • correlates two vertices of one issuer by 0.9, and two issuers of one bucket by 0.4
  • correlates two buckets of qualifying credit by a quarter, and by a tenth more for each thing they share
  • adds the residual bucket after the root, and correlates its factors by one half whoever the issuer is
  • adds the residual bucket of equity after the root and correlates nothing inside it
  • gives non-qualifying credit its weights, 0.8 for a tranche, 0.3 between tranches, 0.5 between buckets and 0.5 in the residual
  • correlates two buckets of equity by the table, and takes the name of a bucket as the correlation inside it
  • gives one commodity its weight times its size, and no correlation to the bucket Other
  • correlates a regular and a high volatility currency by 0.15 and two high volatility currencies by 0.3

SM-10

The six risk classes of a product class are put together with the table, and the four product classes are added, so that one factor in two of them does not net. An empty risk class or product class has a margin of zero. The part of a factor that nets to exactly zero comes from the others that it correlates with. Amounts of ten digits and amounts of cents both work.

SIMM

Evidence, 7 tests
  • tests/kernel/simm.test.ts
  • puts the six risk classes of a product class together with the table of correlations
  • puts two risk classes together with the entry of the table, which is a tenth for rates and qualifying credit
  • adds the four product classes, which are not diversified against each other
  • keeps the product classes apart, so that one factor in two of them does not net
  • lets a risk class that is empty have a margin of zero, and a product class that is empty too
  • gives the share of a factor that nets to exactly zero, next to another that does not, from the others that it correlates with
  • works in ten digits and in cents

SM-11

Concentration is judged on the sum for a currency or an issuer and not on each vertex. Exposure at the threshold is not concentrated, and above it the factor is the root of exposure over threshold. For rates the ratio of the factors of two currencies lowers their correlation, and for the other classes the ratio of two names lowers theirs inside a bucket. A book of large names costs about a third more than its plain margin, which sets every factor to one.

SIMM

Evidence, 8 tests
  • tests/kernel/simm.test.ts
  • is one up to the threshold, and the root of the exposure over the threshold above it
  • adds a third to the margin of the portfolio of large names, in four risk classes, and none to that of the others
  • has plain, which is the margin with every concentration factor set to one, equal to the margin when no exposure is above its threshold
  • holds the sum of a currency against the threshold, and not each vertex
  • puts the ratio of the concentration factors of two currencies into the correlation between them, and not into the correlation inside one
  • gives two names above and below their threshold a ratio of 2 to 3 in their correlation of a fifth
  • takes the concentration factor of a short name from the size of its exposure, and one exactly at its threshold is not concentrated
  • holds the sum of an issuer over its vertices against the threshold, so that three vertices below it add to one above it

SM-12

A line that breaks a rule is refused, the first one, with a message that names it by its place and says what to do. Refused are a product class or risk type that is not one of those read, an amount that is not finite or is above 1,000,000,000,000, a name over 40 characters, a rate with no tenor or sub-curve, a bucket that does not exist, a trade in two product classes, a name in two buckets, no lines and more than 400.

SIMM

Evidence, 10 tests
  • tests/kernel/simm.test.ts
  • takes a valid line of every risk type
  • refuses a product class that is not one of the four, and a risk type that the engine does not read
  • refuses an amount that is not a finite number or is larger than the largest, and a name that is too long
  • refuses a rate that has no tenor, no sub-curve or a currency that is not three capital letters
  • refuses the sub-curves that only dollars have in another currency, and a bucket that is not the bucket of the currency
  • refuses a credit spread without a bucket or a vertex, or with one that does not exist
  • refuses an equity or a commodity without a bucket or with one that does not exist, and an FX rate that is not a currency
  • refuses a portfolio of no lines and a portfolio of too many, and names the line by its place
  • refuses a trade that is in two product classes, and a name that is in two buckets, naming both lines
  • refuses the first line that breaks a rule, and says why in words that a person who wrote the file can act on

SM-13

The part of each factor is its size times what one more unit of it costs, which is its coefficient. The parts of the factors add up to the margin for every portfolio of the tests and every case of the second program, and the same parts give those of trades, risk classes and product classes. A hedge has a negative part. With concentration the coefficient holds the factors where they are, so for one large name it is two thirds of the whole, and a difference quotient confirms it elsewhere.

SIMM

Evidence, 7 tests
  • tests/kernel/simm.test.ts
  • adds the parts of the factors of %s up to its margin, and the parts of its trades, its risk classes and its product classes too
  • adds the parts of the factors up to the margin in every case of the second program, to the last digits
  • gives a hedge a negative part, and a trade that has the factors of it a part that is the sum over its lines
  • has the part of a factor be its size times what one more unit of it costs, which is the coefficient
  • has the coefficient be what one more unit costs, for a portfolio with no concentration, to the digits of a central difference
  • has the coefficient be what one more unit costs with the concentration factors held where they are, so that for one name it is two thirds of the whole
  • is right in the cases where S is cut and the cut flips, and where a bucket is cut next to another that is not

SM-14

Each trade has the part of the margin that rests on it, in the order the trades first appear, and the lines with no trade count as one. Next to the part is what the margin falls by without the trade, and the two are not the same. A line of the calculation currency in FX has no part and is counted. A portfolio of one trade can be taken down to nothing, and nothing has a margin of zero.

SIMM

Evidence, 4 tests
  • tests/kernel/simm.test.ts
  • gives each trade its part, in the order that the trades first appear, and the lines that have no trade as one trade
  • gives a line of the calculation currency in FX a part of nothing, and counts it
  • gives, for each trade, what the margin falls by without it next to its part, and the two are not the same
  • takes a portfolio of one trade down to nothing, and takes the margin of nothing to be zero

SM-15

A second program in Python that shares no code with the engine works 92 cases in decimals of 60 digits and finds the part of each factor by a difference quotient. The cases take both sides of the cut of S, the residual buckets, every risk class and product class, concentration in each risk class and every rule of correlation. Every figure agrees with the engine to 3e-14, and the parts to 1e-9. The saved answers are what the program says now.

SIMM

Evidence, 4 tests
  • tests/kernel/simm.test.ts
  • scripts/verify/simm_oracle.py
  • tests/support/simm-oracle.json
  • has cases that take both sides of the cut of S, the residual buckets, every risk class, every product class, concentration in each risk class and every rule of correlation
  • gives every figure of every case within 3e-14 of the decimals of a program that shares no code with it, and the parts that rest on a difference quotient within 1e-9
  • has saved answers that are what the program says now, so that the file was not edited by hand
  • has the portfolios of the plate among its cases, with the answers that the samples carry

SM-16

Over generated portfolios the margin is zero or more, finite, and no more than the margin with no diversification, and the parts of the factors, the trades and the risk classes add up to it to a part in a hundred billion. It does not change when a line of nothing is added. It changes by less than a part in a trillion when every sign changes, when the order of the lines changes or when a line is split in two, and a book split among its product classes has the sum of their margins to the same part. It scales with the amounts when nothing is above its threshold.

SIMM

Evidence, 8 tests
  • tests/kernel/simm.test.ts
  • gives a margin that is zero or more, finite, and no more than the margin with no diversification
  • adds the parts of the factors, the trades and the risk classes up to the margin
  • does not change when every sign changes, because the margin has no direction
  • does not change when a line of nothing is added for a factor that was not there, and does not change when the order of the lines does
  • does not change when a line is split into two that add up to it
  • scales with the amounts when no exposure is above its threshold, so that the margin of twice the portfolio is twice the margin
  • is the sum of the margins of the product classes when the portfolio is split among them
  • has the coefficients that a difference quotient finds when the portfolio is below its thresholds

SM-17

Two portfolios are compared on their net factors, and the result gives the margin of each side, the difference and the classes that have a margin on either side. A line is valued at what ours falls by when that line alone is made like theirs, which is checked by running ours again, and the one that closes the most comes first. Each break is named as only ours, only theirs, a bucket, a sign, a scale of a hundred or ten thousand, or an amount. A difference of half a cent or less is not listed, and the result says so when the margins still differ.

SIMM

Evidence, 13 tests
  • tests/kernel/simm.test.ts
  • finds nothing in two portfolios that name the same factors with the same sizes, in another order and under other trade numbers
  • gives the margin of each side, the difference, the margins of the product classes and the risk classes that have a margin on either side
  • says that a line is only on our side, or only on theirs, and what the margin is when ours is made like theirs
  • says that a sign is the other way when the sizes are the same and the signs are not
  • says that a size is out by a hundred or a ten thousand when the sizes are in that ratio, from either side
  • says that a size is simply different when no pattern fits, and a bucket when a name is in another bucket on the other side
  • values each difference at what ours falls by when that line alone is made like theirs, which is checked by running ours again
  • puts the difference that closes the most first, and puts ties in the order of the names, whatever the order of the lines
  • does not list a difference of half a cent or less in a line, and says that the margins differ when the sum of such differences is more than half a cent
  • leaves out lines of the calculation currency in FX on both sides, and nets lines of one factor before it compares
  • refuses a side that breaks a rule, and names the line by the way that is given for that side
  • gives the three pairs of the plate the breaks that their notes say they have
  • is the margin of ours less the margin of theirs, whichever side it is on

SM-18

The receipt of a margin holds the calibration, the kind, the factors as the calculation took them and the figures that came out. It is the same for a copy of the lines and for a factor whose lines are written as one or as two, and another for any change to a line that the calculation reads. The trades are listed as they first appear, so the same lines in another order can give another receipt. It does not read what it does not use, and it never carries a minus zero. The receipt of a reconciliation holds both calculations and every difference, and is another when a figure on either side moves by one unit or the sides change places.

SIMM

Evidence, 7 tests
  • tests/kernel/simm.test.ts
  • names the calibration and the kind, the factors as the calculation took them, and the figures that came out
  • is the same for the same lines, for a copy of them, and for a factor whose lines are written as one or as two
  • lists the trades as they first appear, so that the same lines in another order give another receipt where the trades differ, and the same where they do not
  • is another for any change to a line that the calculation reads
  • does not read what it does not use, which is the bucket of a rate that the currency fixes, the bucket of an FX rate and the amount of a line of the calculation currency
  • has no minus zero, which would give another hash for the same figure
  • has a receipt that holds both calculations and every difference, and is another when a figure on either side moves by one unit or the sides change places

Proofs

Proofs you can run yourself

Each proved statement is written as an SMT-LIB file and decided by the Z3 solver. The solver then reads its own emitted text again, and two other solvers rerun the file. Every statement is also broken on purpose, and the solver has to find a counterexample.

The proofs are about real numbers. The limits below say what that does and does not cover.

Run a proof
# Any SMT-LIB 2 solver can run the file. Each check should answer unsat.
curl -O https://graphatlas.com/proofs/PR-01.smt2
z3 PR-01.smt2
cvc5 --nl-cov PR-01.smt2

# In the repository, regenerate every proof and compare it with what is published.
npm run prove:check
npm run parity

unsat is the answer you want. Each check assumes the statement is false. When the solver says no assignment of numbers can make that so, the statement is true for every input the file allows. Run cvc5 with the --nl-cov option. Its default method for real arithmetic gives up on a few of the files, and a solver that gives up has decided nothing.

Or take all of them.

One tar file holds the 38 proofs, what the solvers answered, a list of SHA-256 hashes and a script that checks both. All it needs is a hash tool. If z3 or cvc5 is installed, the script decides every proof again.

The name carries the first digits of a hash of the contents, so the file at this address never changes. Every response names the hash of the whole file, and you can ask for it in pieces.

File
graphatlas-evidence-91c860f4f012.tar
Size
408 kB, 408,064 bytes
SHA-256
3dc6ac59d155bfd401b96dd7d74d0638a00d45c57ee438d14f42e63ec9487c21
Holds
38 proofs, 3 result files, a readme, the hash list and the script.
Download the bundle, 408 kB
Check what you downloaded
# This page gives the hash. The file you get has to match it.
curl -O https://graphatlas.com/downloads/graphatlas-evidence-91c860f4f012.tar
shasum -a 256 graphatlas-evidence-91c860f4f012.tar   # sha256sum on Linux

# Unpack it. The script checks each hash.
# If z3 or cvc5 is installed, it decides each proof again.
tar -xf graphatlas-evidence-91c860f4f012.tar
sh graphatlas-evidence-91c860f4f012/verify.sh

Proved PR-01 PRIIPs Commission Delegated Regulation (EU) 2017/653, Annex II, Part 1, point 2

The MRM class is defined for every VEV, is between 1 and 7, never decreases as the VEV rises, and changes class exactly at the limits in the table.

8 checks, decided by 3 solvers. 2 broken variants refuted. Show the evidence Hide the evidence

What the solver was given mrmClass in src/kernel/priips.ts, built from MRM_TABLE with the exact binary value of each limit.

Verdicts, 8 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 8
Z3 5.3.3 (native) Reran the emitted file unsat × 8
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 8

Each check asks the solver to break the statement. unsat means it cannot.

Download PR-01.smt2 SHA-256 1ad76c0ffa81…8752e4c2

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • labels-swapped refuted at goal 2

    Classes 3 and 4 swap their labels.

    vev_a
    approximately 0.05
    vev_b
    approximately 0.12
  • limits-swapped refuted at goal 6

    The 12% and 20% limits swap places, so the limits no longer increase.

    vev_a
    approximately 0.12
    vev_b
    approximately 0.12
Read the file
; GraphAtlas proof PR-01
; Statement: The MRM class is defined for every VEV, is between 1 and 7, never decreases as the VEV ri …
; About: mrmClass in src/kernel/priips.ts, built from MRM_TABLE with the exact binary value of each li …
; Source: Commission Delegated Regulation (EU) 2017/653, Annex II, Part 1, point 2
; Expected: unsat for each of the 8 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun vev_b () Real)
(declare-fun vev_a () Real)
(assert (<= vev_a vev_b))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (< vev_a (/ 3602879701896397.0 18014398509481984.0)) 4 (ite (< vev_a (/ 5 …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (ite (< vev_a (/ 3602879701896397.0 18014398509481984.0)) 4 (ite (< vev_a (/ 5 …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (ite (< vev_a (/ 3602879701896397.0 18014398509481984.0)) 4 (ite (< vev_a (/ 5 …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
(assert (not (let ((a!1 (ite (< vev_a (/ 3602879701896397.0 18014398509481984.0)) 4 (ite (< vev_a (/ 5 …
(check-sat)
(pop 1)
; 24 more lines are in the file

Proved EN-01 Entropy validation NIST SP 800-90B, Section 4.4.1

The repetition count cutoff is the smallest integer C for which H times (C − 1) reaches the false positive exponent.

2 checks, decided by 3 solvers. 2 broken variants refuted. Show the evidence Hide the evidence

What the solver was given rctCutoff in src/kernel/entropy.ts, which computes 1 + ceil(a / H) exactly for the binary value of H, for every H in (0, 64] and every integer exponent a from 1 to 64. SP 800-90B chooses the rule so that a run of C equal samples from a source with min-entropy H has probability at most 1/2^a. The proof is about the integer rule, not about that probability argument.

Verdicts, 2 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 2
Z3 5.3.3 (native) Reran the emitted file unsat × 2
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 2

Each check asks the solver to break the statement. unsat means it cannot.

Download EN-01.smt2 SHA-256 76fd37607116…a1758a2a

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • floor refuted at goal 1

    Round down instead of up.

    alpha_exponent
    1
    min_entropy
    2/3
    other_candidate
    0
  • off-by-one refuted at goal 1

    Subtract one from the cutoff.

    alpha_exponent
    64
    min_entropy
    64
    other_candidate
    0
Read the file
; GraphAtlas proof EN-01
; Statement: The repetition count cutoff is the smallest integer C for which H times (C - 1) reaches t …
; About: rctCutoff in src/kernel/entropy.ts, which computes 1 + ceil(a / H) exactly for the binary val …
; Source: NIST SP 800-90B, Section 4.4.1
; Expected: unsat for each of the 2 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun alpha_exponent () Int)
(declare-fun min_entropy () Real)
(declare-fun other_candidate () Int)
(assert (>= alpha_exponent 1))
(assert (<= alpha_exponent 64))
(assert (> min_entropy 0.0))
(assert (<= min_entropy 64.0))
(assert (>= other_candidate 0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (to_int (- (/ (to_real alpha_exponent) min_entropy))))) (>= (* (to_real (- a!1 …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (to_int (- (/ (to_real alpha_exponent) min_entropy))))) (=> (>= (* (to_real ot …
(check-sat)
(pop 1)

Proved EN-02 Entropy validation NIST SP 800-90B, Section 4.4.1

The repetition count cutoff never rises when the claimed min-entropy rises.

1 check, decided by 3 solvers. 1 broken variant refuted. Show the evidence Hide the evidence

What the solver was given rctCutoff in src/kernel/entropy.ts, for every pair of claims 0 < H1 ≤ H2 ≤ 64.

Verdicts, 1 check

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 1
Z3 5.3.3 (native) Reran the emitted file unsat × 1
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 1

Each check asks the solver to break the statement. unsat means it cannot.

Download EN-02.smt2 SHA-256 8828c9242bc9…3333beb4

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • growing refuted at goal 1

    Add a term that grows with the entropy.

    alpha_exponent
    2
    entropy_high
    5
    entropy_low
    15/8
Read the file
; GraphAtlas proof EN-02
; Statement: The repetition count cutoff never rises when the claimed min-entropy rises.
; About: rctCutoff in src/kernel/entropy.ts, for every pair of claims 0 < H1 <= H2 <= 64.
; Source: NIST SP 800-90B, Section 4.4.1
; Expected: unsat for each of the 1 check below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun alpha_exponent () Int)
(declare-fun entropy_low () Real)
(declare-fun entropy_high () Real)
(assert (>= alpha_exponent 1))
(assert (<= alpha_exponent 64))
(assert (> entropy_low 0.0))
(assert (<= entropy_low entropy_high))
(assert (<= entropy_high 64.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (to_int (- (/ (to_real alpha_exponent) entropy_low)))) (a!2 (to_int (- (/ (to_ …
(check-sat)
(pop 1)

Proved WL-01 WLTP Regulation (EU) 2017/1151, Annex XXI, Sub-Annex 7, paragraph 3.2.3.2.4

For every vehicle inside the family, the interpolated CO2 lies between the CO2 of the low vehicle and the CO2 of the high vehicle.

3 checks, decided by 3 solvers. 2 broken variants refuted. Show the evidence Hide the evidence

What the solver was given interpolateCo2 in src/kernel/wltp.ts, as a statement about real numbers. The weight is defined by weight times (energy_high minus energy_low) equals (energy_individual minus energy_low), the quotient the code computes. The function counts a vehicle within a trillionth of the span of an end as inside and clamps to the interval, so rounding cannot leave it.

Verdicts, 3 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 3
Z3 5.3.3 (native) Reran the emitted file unsat × 3
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 3

Each check asks the solver to break the statement. unsat means it cannot.

Download WL-01.smt2 SHA-256 0ccb0e2fa63c…bd12a615

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • outside-family refuted at lemma 1

    Allow an individual vehicle with more energy demand than the high vehicle.

    energy_high
    0
    energy_individual
    1/2
    energy_low
    -1/2
    weight
    2
  • scaled-weight refuted at goal 1

    Multiply the weight by 1.1, as a unit slip would.

    co2_high
    0
    co2_low
    -1/11
    energy_high
    0
    energy_individual
    0
    energy_low
    -1/11
    weight
    1
Read the file
; GraphAtlas proof WL-01
; Statement: For every vehicle inside the family, the interpolated CO2 lies between the CO2 of the low …
; About: interpolateCo2 in src/kernel/wltp.ts, as a statement about real numbers. The weight is define …
; Source: Regulation (EU) 2017/1151, Annex XXI, Sub-Annex 7, paragraph 3.2.3.2.4
; Expected: unsat for each of the 3 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun energy_high () Real)
(declare-fun energy_low () Real)
(declare-fun energy_individual () Real)
(declare-fun weight () Real)
(declare-fun co2_high () Real)
(declare-fun co2_low () Real)
(assert (< energy_low energy_high))
(assert (>= energy_individual energy_low))
(assert (<= energy_individual (+ energy_high 0.0)))
(assert (= (* weight (- energy_high energy_low)) (- energy_individual energy_low)))

; Lemma 1, negated
(push 1)
(assert (not (and (>= weight 0.0) (<= weight 1.0))))
(check-sat)
(pop 1)
; Lemma 1 holds, so later checks may use it
(assert (and (>= weight 0.0) (<= weight 1.0)))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (>= (+ co2_low (* weight 1.0 (- co2_high co2_low))) co2_low)) (a!2 (<= (+ co2_ …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
; 3 more lines are in the file

Proved WL-02 WLTP Regulation (EU) 2017/1151, Annex XXI, Sub-Annex 7, paragraph 3.2.3.2.4

Inside the family, a vehicle that demands more energy never gets a lower interpolated CO2, provided the high vehicle emits at least as much as the low one.

1 check, decided by 3 solvers. 1 broken variant refuted. Show the evidence Hide the evidence

What the solver was given interpolateCo2 in src/kernel/wltp.ts, as a statement about real numbers, with the weight defined as in WL-01.

Verdicts, 1 check

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 1
Z3 5.3.3 (native) Reran the emitted file unsat × 1
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 1

Each check asks the solver to break the statement. unsat means it cannot.

Download WL-02.smt2 SHA-256 68b4873fab74…1e8eb7ae

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • unordered-endpoints refuted at goal 1

    Drop the assumption that the high vehicle emits at least as much.

    co2_high
    0
    co2_low
    1
    energy_first
    0
    energy_high
    1
    energy_low
    0
    energy_second
    1/2
    weight_first
    0
    weight_second
    1/2
Read the file
; GraphAtlas proof WL-02
; Statement: Inside the family, a vehicle that demands more energy never gets a lower interpolated CO2 …
; About: interpolateCo2 in src/kernel/wltp.ts, as a statement about real numbers, with the weight defi …
; Source: Regulation (EU) 2017/1151, Annex XXI, Sub-Annex 7, paragraph 3.2.3.2.4
; Expected: unsat for each of the 1 check below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun energy_high () Real)
(declare-fun energy_low () Real)
(declare-fun energy_first () Real)
(declare-fun energy_second () Real)
(declare-fun weight_first () Real)
(declare-fun weight_second () Real)
(declare-fun co2_high () Real)
(declare-fun co2_low () Real)
(assert (< energy_low energy_high))
(assert (>= energy_first energy_low))
(assert (<= energy_first energy_second))
(assert (<= energy_second energy_high))
(assert (= (* weight_first (- energy_high energy_low)) (- energy_first energy_low)))
(assert (= (* weight_second (- energy_high energy_low)) (- energy_second energy_low)))
(assert (<= co2_low co2_high))

; Goal 1, negated
(push 1)
(assert (not (<= (+ co2_low (* weight_first (- co2_high co2_low))) (+ co2_low (* weight_second (- co2_ …
(check-sat)
(pop 1)

Proved SI-01 Solvency II Directive 2009/138/EC, Article 104(1) and Annex IV, point 1

For any non-negative module charges, the basic SCR is never above the plain sum of the charges and never below the largest single charge.

6 checks, decided by 3 solvers. 2 broken variants refuted. Show the evidence Hide the evidence

What the solver was given The quadratic form behind aggregate in src/kernel/aggregate.ts with the matrix in BSCR_CORRELATION_TEXT, taken as exact decimals. The solver proves the form lies between the square of the largest charge and the square of the sum. The SCR is its square root, which is increasing.

Verdicts, 6 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 6
Z3 5.3.3 (native) Reran the emitted file unsat × 6
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 6

Each check asks the solver to break the statement. unsat means it cannot.

Download SI-01.smt2 SHA-256 bd03c84cd329…4cf4b53f

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • correlation-above-one refuted at goal 1

    Set the market and default correlation to 1.2.

    scr_default
    1
    scr_health
    0
    scr_life
    0
    scr_market
    1
    scr_nonlife
    0
  • negative-correlation refuted at goal 2

    Set the market and default correlation to -0.9.

    scr_default
    1
    scr_health
    0
    scr_life
    0
    scr_market
    2
    scr_nonlife
    0
Read the file
; GraphAtlas proof SI-01
; Statement: For any non-negative module charges, the basic SCR is never above the plain sum of the ch …
; About: The quadratic form behind aggregate in src/kernel/aggregate.ts with the matrix in BSCR_CORREL …
; Source: Directive 2009/138/EC, Article 104(1) and Annex IV, point 1
; Expected: unsat for each of the 6 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun scr_market () Real)
(declare-fun scr_default () Real)
(declare-fun scr_life () Real)
(declare-fun scr_health () Real)
(declare-fun scr_nonlife () Real)
(assert (>= scr_market 0.0))
(assert (>= scr_default 0.0))
(assert (>= scr_life 0.0))
(assert (>= scr_health 0.0))
(assert (>= scr_nonlife 0.0))

; Goal 1, negated
(push 1)
(assert (not (<= (+ 0.0 (* 1.0 scr_market scr_market) (* (* (/ 1.0 4.0) scr_market) scr_default) (* (* …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (>= (+ 0.0 (* 1.0 scr_market scr_market) (* (* (/ 1.0 4.0) scr_market) scr_default) (* (* …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (>= (+ 0.0 (* 1.0 scr_market scr_market) (* (* (/ 1.0 4.0) scr_market) scr_default) (* (* …
(check-sat)
; 19 more lines are in the file

Proved PQ-01 PQC NIST IR 8547, Section 3

When only the quantum computer sets the date, the latest start is the years until it arrives less the years to keep the data secure and the years to migrate. Nothing later keeps the data safe, and the use is late exactly when those two add up to more than the years until it arrives.

3 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given plan in src/kernel/pqc.ts for a use with no government date and nothing waiting for it, where the latest start is Z - X - Y and the exposure flag is X + Y > Z. X, Y and Z are whole numbers of years: X from 0 to 100, Y from 1 to 30 and Z from 1 to 100, the limits the function enforces. "Safe" means that the migration is over at least X years before the quantum computer arrives.

Verdicts, 3 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 3
Z3 5.3.3 (native) Reran the emitted file unsat × 3
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 3

Each check asks the solver to break the statement. unsat means it cannot.

Download PQ-01.smt2 SHA-256 ff53ac7ced3e…86b203e0

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • a-year-late refuted at goal 1

    Start one year after the latest start.

    years_to_keep
    0
    years_to_migrate
    1
    years_to_quantum
    1
  • a-year-early refuted at goal 2

    Start one year before the latest start, which is safe but not the latest.

    other_start
    0
    years_to_keep
    0
    years_to_migrate
    1
    years_to_quantum
    1
  • forgets-migration refuted at goal 1

    Leave out the years the migration takes.

    years_to_keep
    0
    years_to_migrate
    1
    years_to_quantum
    1
  • forgets-keeping refuted at goal 1

    Leave out the years the data must stay secure.

    years_to_keep
    1
    years_to_migrate
    1
    years_to_quantum
    1
Read the file
; GraphAtlas proof PQ-01
; Statement: When only the quantum computer sets the date, the latest start is the years until it arri …
; About: plan in src/kernel/pqc.ts for a use with no government date and nothing waiting for it, where …
; Source: NIST IR 8547, Section 3
; Expected: unsat for each of the 3 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun years_to_keep () Int)
(declare-fun years_to_migrate () Int)
(declare-fun years_to_quantum () Int)
(declare-fun other_start () Int)
(assert (>= years_to_keep 0))
(assert (<= years_to_keep 100))
(assert (>= years_to_migrate 1))
(assert (<= years_to_migrate 30))
(assert (>= years_to_quantum 1))
(assert (<= years_to_quantum 100))

; Goal 1, negated
(push 1)
(assert (not (<= (+ (- (- years_to_quantum years_to_keep) years_to_migrate) years_to_migrate years_to_ …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (=> (<= (+ other_start years_to_migrate years_to_keep) years_to_quantum) (<= other_start  …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (= (> (+ years_to_keep years_to_migrate) years_to_quantum) (< (- (- years_to_quantum year …
(check-sat)
; 1 more lines are in the file

Proved PQ-02 PQC EU coordinated implementation roadmap for post-quantum cryptography, version 1.1, Section 5

A use is at least medium risk under the EU roadmap exactly when it protects confidentiality or takes more than eight years to migrate. It is high risk exactly when it has a high impact and either protects confidentiality for ten years or more or takes more than eight years to migrate.

3 checks, decided by 3 solvers. 6 broken variants refuted. Show the evidence Hide the evidence

What the solver was given euRisk in src/kernel/pqc.ts, built from the thresholds in RULES.eu. The statement uses the numbers of the roadmap, 10 and 8, written out in the goals and not read from the code, so a change to the thresholds in the code fails this proof. The years to keep a use secure run from 0 to 100 and the years to migrate from 1 to 30, the limits the plan enforces. Confidentiality is the purpose of key establishment and of encryption.

Verdicts, 3 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 3
Z3 5.3.3 (native) Reran the emitted file unsat × 3
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 3

Each check asks the solver to break the statement. unsat means it cannot.

Download PQ-02.smt2 SHA-256 ec9686100854…b6cc1993

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • keep-threshold-9 refuted at goal 3

    Count nine years of confidentiality as long.

    confidential
    true
    high_impact
    true
    years_to_keep
    9
    years_to_migrate
    1
  • keep-threshold-11 refuted at goal 3

    Count only eleven years or more of confidentiality as long.

    confidential
    true
    high_impact
    true
    years_to_keep
    10
    years_to_migrate
    1
  • migrate-threshold-7 refuted at goal 2

    Count a migration of more than seven years as long.

    confidential
    false
    years_to_keep
    0
    years_to_migrate
    8
  • migrate-threshold-9 refuted at goal 2

    Count a migration of more than nine years as long.

    confidential
    false
    years_to_keep
    0
    years_to_migrate
    9
  • every-use-confidential refuted at goal 2

    Treat a signature as if it protected confidentiality.

    confidential
    false
    years_to_keep
    0
    years_to_migrate
    1
  • ignores-impact refuted at goal 3

    Leave out the test for a high impact.

    confidential
    true
    high_impact
    false
    years_to_keep
    0
    years_to_migrate
    9
Read the file
; GraphAtlas proof PQ-02
; Statement: A use is at least medium risk under the EU roadmap exactly when it protects confidentiali …
; About: euRisk in src/kernel/pqc.ts, built from the thresholds in RULES.eu. The statement uses the nu …
; Source: EU coordinated implementation roadmap for post-quantum cryptography, version 1.1, Section 5
; Expected: unsat for each of the 3 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun years_to_keep () Int)
(declare-fun years_to_migrate () Int)
(declare-fun confidential () Bool)
(declare-fun high_impact () Bool)
(assert (>= years_to_keep 0))
(assert (<= years_to_keep 100))
(assert (>= years_to_migrate 1))
(assert (<= years_to_migrate 30))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (>= (ite confidential (ite (>= 1 2) 1 2) 1) 3))) (let ((a!2 (ite a!1 (ite conf …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (>= (ite confidential (ite (>= 1 2) 1 2) 1) 3))) (let ((a!2 (ite a!1 (ite conf …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (>= (ite confidential (ite (>= 1 2) 1 2) 1) 3))) (let ((a!2 (ite a!1 (ite conf …
(check-sat)
(pop 1)

Proved PQ-03 PQC The planning rule of this product, Latest finish, the backward pass of critical path scheduling

A use that others wait for finishes no later than it would alone and no later than any of them can start, and no later finish does both. It starts strictly earlier than each of them, so a use that is late makes every use it waits for late too.

8 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given The backward pass in plan in src/kernel/pqc.ts, for one use and two uses that wait for it. The pass takes the earliest of the use’s own finish and the latest start of each dependent, and the latest start of a dependent is its finish less the years its migration takes, which is at least one. The dependents are taken as already settled, which the pass guarantees by walking the order backwards and which the check of every plan confirms by a second method (PQ-04). A third dependent adds nothing, because the earliest of three is the earliest of the earliest of two and the third.

Verdicts, 8 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 8
Z3 5.3.3 (native) Reran the emitted file unsat × 8
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 8

Each check asks the solver to break the statement. unsat means it cannot.

Download PQ-03.smt2 SHA-256 fc3bcdb027c5…0effdb2c

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • latest-instead-of-earliest refuted at goal 1

    Take the latest of the dates instead of the earliest.

    finish_first_dependent
    0
    finish_second_dependent
    0
    other_finish
    0
    own_finish
    -2
    years_to_migrate
    1
    years_to_migrate_first_dependent
    1
    years_to_migrate_second_dependent
    1
  • ignores-own-date refuted at goal 1

    Leave out the date the use has on its own.

    finish_first_dependent
    0
    finish_second_dependent
    0
    other_finish
    0
    own_finish
    -2
    years_to_migrate
    1
    years_to_migrate_first_dependent
    1
    years_to_migrate_second_dependent
    1
  • finish-not-start refuted at goal 2

    Compare with the finish of the first dependent, not with its latest start.

    finish_first_dependent
    0
    finish_second_dependent
    0
    other_finish
    0
    own_finish
    0
    years_to_migrate
    1
    years_to_migrate_first_dependent
    2
    years_to_migrate_second_dependent
    1
  • first-dependent-only refuted at goal 3

    Look at the first dependent only.

    finish_first_dependent
    0
    finish_second_dependent
    0
    other_finish
    0
    own_finish
    0
    years_to_migrate
    1
    years_to_migrate_first_dependent
    1
    years_to_migrate_second_dependent
    2
Read the file
; GraphAtlas proof PQ-03
; Statement: A use that others wait for finishes no later than it would alone and no later than any of …
; About: The backward pass in plan in src/kernel/pqc.ts, for one use and two uses that wait for it. Th …
; Source: The planning rule of this product, Latest finish, the backward pass of critical path schedul …
; Expected: unsat for each of the 8 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun own_finish () Int)
(declare-fun finish_first_dependent () Int)
(declare-fun finish_second_dependent () Int)
(declare-fun other_finish () Int)
(declare-fun years_to_migrate () Int)
(declare-fun years_to_migrate_first_dependent () Int)
(declare-fun years_to_migrate_second_dependent () Int)
(assert (>= own_finish (- 200)))
(assert (<= own_finish 200))
(assert (>= finish_first_dependent (- 200)))
(assert (<= finish_first_dependent 200))
(assert (>= finish_second_dependent (- 200)))
(assert (<= finish_second_dependent 200))
(assert (>= other_finish (- 200)))
(assert (<= other_finish 200))
(assert (>= years_to_migrate 1))
(assert (<= years_to_migrate 30))
(assert (>= years_to_migrate_first_dependent 1))
(assert (<= years_to_migrate_first_dependent 30))
(assert (>= years_to_migrate_second_dependent 1))
(assert (<= years_to_migrate_second_dependent 30))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (<= own_finish (- finish_first_dependent years_to_migrate_first_dependent …
(check-sat)
(pop 1)
; 42 more lines are in the file

Proved AE-01 AERMOD 40 CFR Part 50, Appendix N and Appendix T, Table 1 of each

For every number of days with data in a year, from 1 to 366, the rank that Table 1 of Appendix N gives for the 98th percentile is the smallest whole number that is at least 2 per cent of the days, and the rank that Table 1 of Appendix T gives for the 99th percentile is the smallest whole number that is at least 1 per cent of them. Every count of days has a rank, and more days never lower it.

8 checks, decided by 3 solvers. 5 broken variants refuted. Show the evidence Hide the evidence

What the solver was given rankFor in src/kernel/aermod.ts with the tables RANK_98 and RANK_99 as they are shipped. The rank of a count is the rank of the first row whose range holds it, as the code finds it. The statement is that the rank r satisfies r × 50 ≥ days and (r − 1) × 50 < days for the 98th percentile, and the same with 100 for the 99th. That is to say that r is the days divided by 50, or by 100, and rounded up.

Verdicts, 8 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 8
Z3 5.3.3 (native) Reran the emitted file unsat × 8
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 8

Each check asks the solver to break the statement. unsat means it cannot.

Download AE-01.smt2 SHA-256 76dfa33edb31…775202cf

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • first-row-one-day-long refuted at goal 3

    Let the first row of the 98th percentile end at day 51 instead of day 50.

    days_with_data
    51
    more_days_with_data
    51
  • rounds-down refuted at goal 4

    Take the days over 50 rounded down, plus one, so that exactly 50 days has the second rank.

    days_with_data
    150
    more_days_with_data
    150
  • a-gap refuted at goal 1

    Leave out the row for ranks of 4, so that 151 to 200 days has no rank.

    days_with_data
    151
    more_days_with_data
    151
  • the-99th-for-the-98th refuted at goal 3

    Use the table of the 99th percentile where the 98th is meant.

    days_with_data
    101
    more_days_with_data
    101
  • last-row-one-day-short refuted at goal 2

    End the last row of the 99th percentile at day 365, so that a leap year has no rank.

    days_with_data
    366
    more_days_with_data
    366
Read the file
; GraphAtlas proof AE-01
; Statement: For every number of days with data in a year, from 1 to 366, the rank that Table 1 of App …
; About: rankFor in src/kernel/aermod.ts with the tables RANK_98 and RANK_99 as they are shipped. The  …
; Source: 40 CFR Part 50, Appendix N and Appendix T, Table 1 of each
; Expected: unsat for each of the 8 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun days_with_data () Int)
(declare-fun more_days_with_data () Int)
(assert (>= days_with_data 1))
(assert (<= days_with_data 366))
(assert (>= more_days_with_data days_with_data))
(assert (<= more_days_with_data 366))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (and (>= days_with_data 301) (<= days_with_data 350)) 7 (ite (and (>= day …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (ite (and (>= days_with_data 201) (<= days_with_data 300)) 3 (ite (and (>= day …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (ite (and (>= days_with_data 301) (<= days_with_data 350)) 7 (ite (and (>= day …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
; 27 more lines are in the file

Proved AE-02 AERMOD Handbook on Atmospheric Diffusion (Hanna, Briggs and Hosker, 1982), Table 4.5, formulas recommended by Briggs for open country

In every stability class both spreads of the plume grow with the distance downwind, from 100 m to 10 km. At every distance the spread of a more stable class is smaller than that of the class before it, both across the wind and upward.

22 checks, decided by 3 solvers. 5 broken variants refuted. Show the evidence Hide the evidence

What the solver was given sigmaY and sigmaZ in src/kernel/aermod.ts, built from the rows of SPREAD_Y and SPREAD_Z as they are shipped. The spread across the wind is a x over the square root of 1 + b x. The spread upward is a x, or a x over the square root of 1 + b x, or a x over 1 + b x, by class. Each is written as the equation that a positive spread satisfies, so that the proof needs no square root, and the coefficients are the decimals of Table 4.5 of the Handbook. The distance is a real number from 100 to 10,000 metres, the range in which the functions accept one.

Verdicts, 22 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 22
Z3 5.3.3 (native) Reran the emitted file unsat × 22
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 22

Each check asks the solver to break the statement. unsat means it cannot.

Download AE-02.smt2 SHA-256 751cab0c52d3…489445cd

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • denominator-squared refuted at goal 10

    Square the denominator of the upward spread of class E, which makes the spread fall again beyond about 3 km.

    distance
    3333
    farther_distance
    3334
    up_E_far
    approximately 25
    up_E_near
    approximately 25
  • square-on-the-distance refuted at goal 12

    Put the square on the distance in the denominator of class F, so that the spread peaks near 100 m and then falls.

    distance
    201/2
    farther_distance
    101
    up_F_far
    approximately 0.398
    up_F_near
    approximately 0.399
  • across-wind-square-on-the-distance refuted at goal 3

    Put the same square on the distance in the spread across the wind of class B.

    across_B_far
    approximately 7.999604
    across_B_near
    approximately 7.9999
    distance
    201/2
    farther_distance
    101
  • class-d-too-wide refuted at goal 18

    Raise the coefficient of the upward spread of class D from 0.06 to 0.09, which makes it wider than class C near the stack.

    distance
    101
    farther_distance
    102
    up_C
    approximately 7.999608
    up_D
    approximately 8.470946
  • e-and-f-swapped-across refuted at goal 21

    Swap the coefficients across the wind of classes E and F.

    across_E
    approximately 4.019751
    across_F
    approximately 6.029627
    distance
    101
    farther_distance
    102
Read the file
; GraphAtlas proof AE-02
; Statement: In every stability class both spreads of the plume grow with the distance downwind, from  …
; About: sigmaY and sigmaZ in src/kernel/aermod.ts, built from the rows of SPREAD_Y and SPREAD_Z as th …
; Source: Handbook on Atmospheric Diffusion (Hanna, Briggs and Hosker, 1982), Table 4.5, formulas reco …
; Expected: unsat for each of the 22 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun distance () Real)
(declare-fun farther_distance () Real)
(declare-fun across_A_far () Real)
(declare-fun across_A_near () Real)
(declare-fun up_A_far () Real)
(declare-fun up_A_near () Real)
(declare-fun across_B_far () Real)
(declare-fun across_B_near () Real)
(declare-fun up_B_far () Real)
(declare-fun up_B_near () Real)
(declare-fun across_C_far () Real)
(declare-fun across_C_near () Real)
(declare-fun up_C_far () Real)
(declare-fun up_C_near () Real)
(declare-fun across_D_far () Real)
(declare-fun across_D_near () Real)
(declare-fun up_D_far () Real)
(declare-fun up_D_near () Real)
(declare-fun across_E_far () Real)
(declare-fun across_E_near () Real)
(declare-fun up_E_far () Real)
(declare-fun up_E_near () Real)
(declare-fun across_F_far () Real)
(declare-fun across_F_near () Real)
(declare-fun up_F_far () Real)
(declare-fun up_F_near () Real)
(declare-fun across_B () Real)
; 146 more lines are in the file

Proved AE-03 AERMOD 40 CFR Part 50, Appendix N and Appendix T, Appendix N section 3.0(b) and (c), Appendix T section 2(c) and section 4.1

A day read as a monitor network keeps it is never above the same day read as a model takes it. It is below it by less than 0.2 for a mean of 24 hours and by less than 0.1 for the highest hour. The network cuts each hour off at a tenth and then cuts the mean of those off at a tenth again.

4 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given dayAsMonitor and dayAsModel in src/kernel/aermod.ts for the 24 hours of one day. The hourly values are real numbers from 0 to 10,000. A monitor keeps each hour as a whole number of tenths, the greatest whole number not above ten times the hour, and keeps the day as the whole number of tenths that is not above the mean of those. A model takes the mean of the hours, or the highest hour, as it is. The statement compares the two in tenths.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download AE-03.smt2 SHA-256 3823cd366716…4d7f4180

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • rounds-the-hours refuted at goal 1

    Round each hour to the nearest tenth where the appendices cut it off, so that a day can be read higher than the model reads it.

    hour_9
    47/20

    23 other variables are 0.

  • a-tenth-lost refuted at goal 2

    Lose one more tenth from the mean of the day, which makes it fall more than 0.2 short.

    hour_8
    1/8
    hour_9
    91/40

    22 other variables are 0.

  • divides-by-23 refuted at goal 1

    Divide the hours by 23 instead of 24.

    hour_9
    47/10

    23 other variables are 0.

Read the file
; GraphAtlas proof AE-03
; Statement: A day read as a monitor network keeps it is never above the same day read as a model take …
; About: dayAsMonitor and dayAsModel in src/kernel/aermod.ts for the 24 hours of one day. The hourly v …
; Source: 40 CFR Part 50, Appendix N and Appendix T, Appendix N section 3.0(b) and (c), Appendix T sec …
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun hour_0 () Real)
(declare-fun hour_1 () Real)
(declare-fun hour_2 () Real)
(declare-fun hour_3 () Real)
(declare-fun hour_4 () Real)
(declare-fun hour_5 () Real)
(declare-fun hour_6 () Real)
(declare-fun hour_7 () Real)
(declare-fun hour_8 () Real)
(declare-fun hour_9 () Real)
(declare-fun hour_10 () Real)
(declare-fun hour_11 () Real)
(declare-fun hour_12 () Real)
(declare-fun hour_13 () Real)
(declare-fun hour_14 () Real)
(declare-fun hour_15 () Real)
(declare-fun hour_16 () Real)
(declare-fun hour_17 () Real)
(declare-fun hour_18 () Real)
(declare-fun hour_19 () Real)
(declare-fun hour_20 () Real)
(declare-fun hour_21 () Real)
(declare-fun hour_22 () Real)
(declare-fun hour_23 () Real)
(assert (and (>= hour_0 0.0) (<= hour_0 10000.0)))
(assert (and (>= hour_1 0.0) (<= hour_1 10000.0)))
(assert (and (>= hour_2 0.0) (<= hour_2 10000.0)))
; 45 more lines are in the file

Proved AE-04 AERMOD 40 CFR Part 50, Appendix K, Section 1.0(b), the definition of an exceedance

A daily value of PM10 that a monitor keeps in tenths is an exceedance of a level exactly when it is at least 5 below the next multiple of 10 above the level, so for the level of 150 it is an exceedance from 155.0 on. A day from 150.1 to 154.9 is above the level and is not counted, and every day that is counted is above the level.

4 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given exceedanceEdge in src/kernel/aermod.ts. Appendix K counts a day when its value, rounded to the nearest 10 with a value that ends in 5 or more going up, is above the level. The day is a whole number of tenths t, so the rounded value is 10 times the whole number part of (t + 50) divided by 100. A level is 10 k + u for u from 0 to 9, and the statement holds for every such level. The code gives 1550 tenths for the level of the PM10 standard, and the proof uses that number.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download AE-04.smt2 SHA-256 19fa728de214…74136a56

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • rounds-half-down refuted at goal 1

    Round a value that ends in 5 down, so that a day of 155.0 is not counted.

    daily_value_in_tenths
    50
    units_in_level
    0
    whole_tens_in_level
    0
  • cuts-off-instead-of-rounding refuted at goal 1

    Cut the day off at a multiple of 10 where the appendix rounds it, so that a day is counted only from 160.

    daily_value_in_tenths
    50
    units_in_level
    0
    whole_tens_in_level
    0
  • at-the-level-counts refuted at goal 1

    Count a rounded day that equals the level as well as one above it.

    daily_value_in_tenths
    0
    units_in_level
    0
    whole_tens_in_level
    0
  • compares-unrounded refuted at goal 1

    Compare the day with the level without rounding it first, which is how a model is compared.

    daily_value_in_tenths
    1
    units_in_level
    0
    whole_tens_in_level
    0
Read the file
; GraphAtlas proof AE-04
; Statement: A daily value of PM10 that a monitor keeps in tenths is an exceedance of a level exactly  …
; About: exceedanceEdge in src/kernel/aermod.ts. Appendix K counts a day when its value, rounded to th …
; Source: 40 CFR Part 50, Appendix K, Section 1.0(b), the definition of an exceedance
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun daily_value_in_tenths () Int)
(declare-fun whole_tens_in_level () Int)
(declare-fun units_in_level () Int)
(assert (>= daily_value_in_tenths 0))
(assert (<= daily_value_in_tenths 100000))
(assert (>= whole_tens_in_level 0))
(assert (<= whole_tens_in_level 1000))
(assert (>= units_in_level 0))
(assert (<= units_in_level 9))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (> (* (div (+ daily_value_in_tenths 50) 100) 10) (+ (* whole_tens_in_level 10) …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (> (* (div (+ daily_value_in_tenths 50) 100) 10) 150))) (= a!1 (>= daily_value …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (> (* (div (+ daily_value_in_tenths 50) 100) 10) 150))) (=> (and (> daily_valu …
(check-sat)
(pop 1)
; 6 more lines are in the file

Proved AE-05 AERMOD 40 CFR Part 50, Appendices N, T and K, Appendix N section 4.3, Appendix T section 4.1(c), Appendix K section 2.1(b)

A design value that is the mean of three values and is rounded half up as Appendices N and T say is at most the level exactly when the three add up to at most 1064 tenths for the 24-hour PM2.5 level of 35, which holds for values kept in whole tenths, and at most 2264 for the 1-hour SO2 level of 75 ppb. The annual mean is at most 9.0 exactly when the three annual means, which need not be whole tenths, add up to less than 27.15. For PM10 the design value is at most 1.0 exactly when the three yearly counts of days add up to at most 3.

4 checks, decided by 3 solvers. 2 broken variants refuted. Show the evidence Hide the evidence

What the solver was given roundExact applied to a mean of three values, and the comparison with the level in designRun. When the three values are kept in whole tenths and add up to t tenths, their mean is t over 30, and rounding it half up to p places is the whole number part of (2 t 10^p + 30) divided by 60, in units of 10^-p. For the annual form each year is the mean of four quarterly means, so the three add up to any real number a, and the mean a over 3 rounds half up to a tenth. The level and the places of each form are those of FORMS. For PM10 the mean of three counts, c over 3, is rounded half up to a tenth, which is the whole number part of (20 c + 3) divided by 6 in tenths.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download AE-05.smt2 SHA-256 b5774f521a9d…f436f782

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • rounds-down refuted at goal 1

    Cut the design value off where the appendix rounds it half up.

    three_annual_means_added_in_tenths
    0
    three_values_added_in_tenths
    1065
    three_yearly_counts_added
    0
  • compares-unrounded refuted at goal 1

    Compare the mean with the level before rounding it, which is how a model is compared.

    three_annual_means_added_in_tenths
    0
    three_values_added_in_tenths
    1051
    three_yearly_counts_added
    0
Read the file
; GraphAtlas proof AE-05
; Statement: A design value that is the mean of three values and is rounded half up as Appendices N an …
; About: roundExact applied to a mean of three values, and the comparison with the level in designRun. …
; Source: 40 CFR Part 50, Appendices N, T and K, Appendix N section 4.3, Appendix T section 4.1(c), Ap …
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun three_values_added_in_tenths () Int)
(declare-fun three_annual_means_added_in_tenths () Real)
(declare-fun three_yearly_counts_added () Int)
(assert (>= three_values_added_in_tenths 0))
(assert (<= three_values_added_in_tenths 60000))
(assert (>= three_annual_means_added_in_tenths 0.0))
(assert (<= three_annual_means_added_in_tenths 60000.0))
(assert (>= three_yearly_counts_added 0))
(assert (<= three_yearly_counts_added 1100))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (<= (div (+ (* three_values_added_in_tenths 2) 30) 60) 35))) (= a!1 (<= three_ …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (<= (div (+ (* three_values_added_in_tenths 2) 30) 60) 75))) (= a!1 (<= three_ …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (<= (to_int (+ (/ three_annual_means_added_in_tenths 3.0) (/ 1.0 2.0))) 90)))  …
(check-sat)
(pop 1)
; 6 more lines are in the file

Proved RS-01 Reserving and ESG Mack (1993), ASTIN Bulletin 23(2), pages 213 to 225, The estimator of the development factors

For positive amounts, the development factor of a year is the mean of the ratios from that year to the next, weighted by the amounts of the first of the two. So it is not below the smallest of those ratios and not above the largest, and it is their common value when they are all alike.

4 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given developmentFactors in src/kernel/reserving.ts, which divides the total of the later amounts by the total of the earlier ones, over the origin years that have both. Three origin years stand for any number of them. A ratio is a later amount over the earlier amount of the same origin year, so the later amount is the earlier amount times the ratio. Each quotient is written as the number whose product with its divisor is the dividend, which for a divisor above zero is the same number.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-01.smt2 SHA-256 a1ad129abe09…d5ed0475

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • unweighted-mean refuted at goal 1

    Average the three ratios without weights.

    earlier_1
    1
    earlier_2
    1/2
    earlier_3
    1
    factor
    4/3
    ratio_1
    1
    ratio_2
    1
    ratio_3
    2
  • weights-are-the-later-amounts refuted at goal 1

    Weigh each ratio by its later amount, which is a mean of the wrong thing.

    earlier_1
    1
    earlier_2
    1
    earlier_3
    1
    factor
    9/10
    ratio_1
    1
    ratio_2
    1
    ratio_3
    1/2
  • youngest-year-in-the-divisor refuted at goal 1

    Divide by the earlier amounts of all three origin years but add only the later amounts of two, as if the youngest year had no later amount.

    earlier_1
    1
    earlier_2
    1
    earlier_3
    1
    factor
    2/3
    ratio_1
    1
    ratio_2
    1
    ratio_3
    1
  • sum-of-the-ratios refuted at goal 1

    Add the ratios instead of averaging them.

    earlier_1
    1
    earlier_2
    1
    earlier_3
    1
    factor
    3
    ratio_1
    1
    ratio_2
    1
    ratio_3
    1
Read the file
; GraphAtlas proof RS-01
; Statement: For positive amounts, the development factor of a year is the mean of the ratios from tha …
; About: developmentFactors in src/kernel/reserving.ts, which divides the total of the later amounts b …
; Source: Mack (1993), ASTIN Bulletin 23(2), pages 213 to 225, The estimator of the development factors
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun earlier_1 () Real)
(declare-fun earlier_2 () Real)
(declare-fun earlier_3 () Real)
(declare-fun ratio_1 () Real)
(declare-fun ratio_2 () Real)
(declare-fun ratio_3 () Real)
(declare-fun factor () Real)
(assert (> earlier_1 0.0))
(assert (> earlier_2 0.0))
(assert (> earlier_3 0.0))
(assert (> ratio_1 0.0))
(assert (> ratio_2 0.0))
(assert (> ratio_3 0.0))
(assert (= (* factor (+ earlier_1 earlier_2 earlier_3)) (+ (* earlier_1 ratio_1) (* earlier_2 ratio_2) …

; Goal 1, negated
(push 1)
(assert (not (= (* factor (+ earlier_1 earlier_2 earlier_3)) (+ (* earlier_1 ratio_1) (* earlier_2 rat …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (or (>= factor ratio_1) (>= factor ratio_2) (>= factor ratio_3))))
(check-sat)
(pop 1)

; 11 more lines are in the file

Proved RS-02 Reserving and ESG Mack (1993), ASTIN Bulletin 23(2), pages 213 to 225, The chain ladder projection

In a triangle of four origin years, what the chain ladder expects to be paid in the three calendar years to come adds up to the reserve, which is the ultimate less the latest amount of each origin year. The first year pays the next factor of every open origin year, and when no factor is below one, no payment is below zero.

3 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given chainLadder in src/kernel/reserving.ts, for four origin years. The payment of a calendar year is, for each origin year that has not finished, the rise from one development year to the next. The latest amounts l1 to l3 of the three open origin years and the factors f0 to f2 are any positive numbers.

Verdicts, 3 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 3
Z3 5.3.3 (native) Reran the emitted file unsat × 3
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 3

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-02.smt2 SHA-256 fdb98ff0a1f6…5243ae4f

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • running-total-not-rise refuted at goal 1

    Report for each calendar year what the open origin years have gained since their latest amount, not what they gained in that year.

    factor_0
    1/2
    factor_1
    1
    factor_2
    1
    latest_1
    1
    latest_2
    1
    latest_3
    1
  • oldest-open-year-skipped refuted at goal 1

    Leave origin year 2 out of the first calendar year.

    factor_0
    1
    factor_1
    1
    factor_2
    1/2
    latest_1
    1
    latest_2
    1
    latest_3
    1
  • last-calendar-year-missing refuted at goal 1

    Stop after two calendar years, so the youngest origin year is never paid in full.

    factor_0
    1
    factor_1
    1
    factor_2
    1/2
    latest_1
    1
    latest_2
    1
    latest_3
    1
  • factor-one-late refuted at goal 1

    Pay origin year 4 its second factor in the first calendar year, as if its factors were taken a year too late.

    factor_0
    1
    factor_1
    1/2
    factor_2
    1
    latest_1
    1
    latest_2
    1
    latest_3
    1
Read the file
; GraphAtlas proof RS-02
; Statement: In a triangle of four origin years, what the chain ladder expects to be paid in the three …
; About: chainLadder in src/kernel/reserving.ts, for four origin years. The payment of a calendar year …
; Source: Mack (1993), ASTIN Bulletin 23(2), pages 213 to 225, The chain ladder projection
; Expected: unsat for each of the 3 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun latest_1 () Real)
(declare-fun latest_2 () Real)
(declare-fun latest_3 () Real)
(declare-fun factor_0 () Real)
(declare-fun factor_1 () Real)
(declare-fun factor_2 () Real)
(assert (> latest_1 0.0))
(assert (> latest_2 0.0))
(assert (> latest_3 0.0))
(assert (> factor_0 0.0))
(assert (> factor_1 0.0))
(assert (> factor_2 0.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (- (* (* (* latest_3 factor_0) factor_1) factor_2) (* (* latest_3 factor_0) fa …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (= (+ (- (* latest_1 factor_2) latest_1) (- (* latest_2 factor_1) latest_2) (- (* latest_ …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
; 3 more lines are in the file

Proved RS-03 Reserving and ESG Mack (1993), ASTIN Bulletin 23(2), pages 213 to 225, The estimator of the variance of the last development year

The variance that the formula of Mack gives to the last development year, which rests on a single ratio, is never below zero and never above either of the two estimates before it. It is the continuation of their decline when they do not rise, the earlier of the two when they rise, and nothing when the earlier is nothing.

6 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given mack in src/kernel/reserving.ts, at the line that sets the last variance from the two before it. The earlier variance a and the later variance b are any two numbers that are not below zero. The continuation of their decline is b × b / a.

Verdicts, 6 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 6
Z3 5.3.3 (native) Reran the emitted file unsat × 6
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 6

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-03.smt2 SHA-256 77919763ad40…3719d26b

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • no-limit refuted at goal 2

    Take the continuation of the decline without holding it to the two estimates, so a rising variance rises further.

    earlier_variance
    1/2
    later_variance
    1
  • mean-of-the-two refuted at goal 2

    Take the mean of the two estimates.

    earlier_variance
    0
    later_variance
    2
  • later-estimate-repeated refuted at goal 2

    Repeat the later estimate.

    earlier_variance
    0
    later_variance
    1
  • no-guard-for-nothing refuted at goal 1

    Divide by the earlier variance without asking whether it is nothing.

    earlier_variance
    0
    later_variance
    0
Read the file
; GraphAtlas proof RS-03
; Statement: The variance that the formula of Mack gives to the last development year, which rests on  …
; About: mack in src/kernel/reserving.ts, at the line that sets the last variance from the two before  …
; Source: Mack (1993), ASTIN Bulletin 23(2), pages 213 to 225, The estimator of the variance of the la …
; Expected: unsat for each of the 6 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun earlier_variance () Real)
(declare-fun later_variance () Real)
(assert (>= earlier_variance 0.0))
(assert (>= later_variance 0.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (= earlier_variance (to_real 0)) 0.0 (/ (* later_variance later_variance) …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (ite (= earlier_variance (to_real 0)) 0.0 (/ (* later_variance later_variance) …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (ite (= earlier_variance (to_real 0)) 0.0 (/ (* later_variance later_variance) …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
(assert (not (let ((a!1 (ite (= earlier_variance (to_real 0)) 0.0 (/ (* later_variance later_variance) …
(check-sat)
; 13 more lines are in the file

Proved RS-04 Reserving and ESG EIOPA-BoS-26-198, technical documentation of May 2026, Annex C, paragraph C.2.2

The ultimate forward rate of a year is the rate of the year before, or that rate plus 15 basis points, or that rate less 15 basis points. It rises exactly when the rate before the limit is at least 15 basis points above the rate of the year before, and falls exactly when it is at least 15 basis points below. It never ends farther from the rate before the limit than it began, and a higher rate before the limit never gives a lower ultimate rate.

5 checks, decided by 3 solvers. 5 broken variants refuted. Show the evidence Hide the evidence

What the solver was given limitUfr in src/kernel/curve.ts. A rate is a whole number of millionths, which is how the code compares two rates, so 15 basis points is 1500 of them and a step is that many.

Verdicts, 5 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 5
Z3 5.3.3 (native) Reran the emitted file unsat × 5
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 5

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-04.smt2 SHA-256 1aa1f75ab314…fea46f68

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • strict-comparison refuted at goal 2

    Move only when the rate before the limit is more than a step away, so that a rate exactly a step away leaves the rate where it was.

    a_higher_ufr_before_the_limit
    0
    previous_ufr
    -1500
    ufr_before_the_limit
    0
  • follows-inside-the-band refuted at goal 1

    Take the rate before the limit when it is within a step of the year before, instead of staying.

    a_higher_ufr_before_the_limit
    0
    previous_ufr
    0
    ufr_before_the_limit
    -1
  • step-of-thirty refuted at goal 1

    Limit the move to 30 basis points.

    a_higher_ufr_before_the_limit
    0
    previous_ufr
    0
    ufr_before_the_limit
    -3000
  • wrong-direction refuted at goal 2

    Move down when the rate before the limit is above, and up when it is below.

    a_higher_ufr_before_the_limit
    0
    previous_ufr
    0
    ufr_before_the_limit
    -1500
  • jumps-to-the-unlimited-rate refuted at goal 1

    Take the rate before the limit whenever it is a step or more away.

    a_higher_ufr_before_the_limit
    0
    previous_ufr
    0
    ufr_before_the_limit
    -1501
Read the file
; GraphAtlas proof RS-04
; Statement: The ultimate forward rate of a year is the rate of the year before, or that rate plus 15  …
; About: limitUfr in src/kernel/curve.ts. A rate is a whole number of millionths, which is how the cod …
; Source: EIOPA-BoS-26-198, technical documentation of May 2026, Annex C, paragraph C.2.2
; Expected: unsat for each of the 5 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun ufr_before_the_limit () Int)
(declare-fun a_higher_ufr_before_the_limit () Int)
(declare-fun previous_ufr () Int)
(assert (>= a_higher_ufr_before_the_limit ufr_before_the_limit))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (>= ufr_before_the_limit (+ previous_ufr 1500)) (+ previous_ufr 1500) (it …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (ite (>= ufr_before_the_limit (+ previous_ufr 1500)) (+ previous_ufr 1500) (it …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (ite (>= ufr_before_the_limit (+ previous_ufr 1500)) (+ previous_ufr 1500) (it …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
(assert (not (let ((a!1 (ite (>= ufr_before_the_limit (+ previous_ufr 1500)) (+ previous_ufr 1500) (it …
(check-sat)
; 7 more lines are in the file

Proved RS-05 Reserving and ESG EIOPA-BoS-26-198, technical documentation of May 2026, Paragraph 8.5.5

Beyond the first smoothing point, the weight of the last liquid forward rate, which is (1 − e^(−a×h)) over a×h, is above zero and not above one. It is not below 1 − a×h/2, and a×h times it is not above one.

4 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given convergenceWeight in src/kernel/curve.ts, with a the convergence parameter and h the horizon in years, both above zero. The solver is told three facts about e^(−a×h), each true for a positive a×h: it is above 0 and below 1, it is at least 1 − a×h, and it is at most 1 − a×h + (a×h)²/2. It is given no more than these. The quotient is written as the number whose product with its divisor is the dividend, which for a divisor above zero is the same number.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-05.smt2 SHA-256 1c3cff96bf80…f5f5cdc8

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • weight-without-the-horizon refuted at goal 2

    Divide by a alone, so that the weight passes one for a long horizon.

    alpha
    1/2
    alpha_times_horizon
    1
    exp_of_minus_alpha_horizon
    1/4
    horizon
    2
    weight_of_llfr
    3/2
  • weight-with-a-sum refuted at goal 3

    Divide by a plus h where the formula has a times h.

    alpha
    1
    alpha_times_horizon
    1
    exp_of_minus_alpha_horizon
    1/4
    horizon
    1
    weight_of_llfr
    3/8
  • weight-of-the-exponential refuted at goal 2

    Take the exponential itself over a times h, which is the weight of the wrong end.

    alpha
    1
    alpha_times_horizon
    1/2
    exp_of_minus_alpha_horizon
    9/16
    horizon
    1/2
    weight_of_llfr
    9/8
Read the file
; GraphAtlas proof RS-05
; Statement: Beyond the first smoothing point, the weight of the last liquid forward rate, which is (1 …
; About: convergenceWeight in src/kernel/curve.ts, with a the convergence parameter and h the horizon  …
; Source: EIOPA-BoS-26-198, technical documentation of May 2026, Paragraph 8.5.5
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun alpha () Real)
(declare-fun horizon () Real)
(declare-fun alpha_times_horizon () Real)
(declare-fun exp_of_minus_alpha_horizon () Real)
(declare-fun weight_of_llfr () Real)
(assert (> alpha 0.0))
(assert (> horizon 0.0))
(assert (= alpha_times_horizon (* alpha horizon)))
(assert (> exp_of_minus_alpha_horizon 0.0))
(assert (< exp_of_minus_alpha_horizon 1.0))
(assert (>= exp_of_minus_alpha_horizon (- 1.0 alpha_times_horizon)))
(assert (<= exp_of_minus_alpha_horizon (+ (- 1.0 alpha_times_horizon) (* (/ 1.0 2.0) alpha_times_horiz …
(assert (= (* weight_of_llfr alpha horizon) (- 1.0 exp_of_minus_alpha_horizon)))

; Goal 1, negated
(push 1)
(assert (not (> weight_of_llfr 0.0)))
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (<= weight_of_llfr 1.0)))
(check-sat)
(pop 1)

; Goal 3, negated
; 10 more lines are in the file

Proved RS-06 Reserving and ESG EIOPA-BoS-26-198, technical documentation of May 2026, Paragraphs 8.5.5 and 8.5.6

Beyond the first smoothing point, the forward rate of each horizon lies between the last liquid forward rate and the ultimate forward rate. Its distance from the first is at most a×h/2 of the distance between the two, and its distance from the second is at most 1/(a×h) of it.

4 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given forwardFromFsp and extrapolate in src/kernel/curve.ts, with a the convergence parameter and h the horizon in years. The weight of the last liquid forward rate is given the four facts that the previous proof shows of it, and no more. The ultimate rate is written as the last liquid rate plus the distance between the two, which is a number of its own. Any pair of rates is such a pair.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-06.smt2 SHA-256 2e94f136cffb…addf1251

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • weights-swapped refuted at goal 3

    Give the weight to the ultimate forward rate, so that the forward rate starts at the ultimate rate and runs to the last liquid one.

    alpha_times_horizon
    2/3
    forward_rate
    0
    llfr
    4/9
    ufr_less_llfr
    -2/3
    weight_of_llfr
    2/3
  • weight-on-both refuted at goal 1

    Give the weight to the last liquid rate, and then the same weight to the ultimate rate, so that the two weights do not add to one.

    alpha_times_horizon
    3/2
    forward_rate
    7/2
    llfr
    3
    ufr_less_llfr
    -1
    weight_of_llfr
    1/2
  • no-ultimate-rate refuted at goal 1

    Leave out the part of the ultimate rate, so that the forward rate is the weight times the last liquid rate.

    alpha_times_horizon
    3/2
    forward_rate
    -1/2
    llfr
    -1
    ufr_less_llfr
    -1
    weight_of_llfr
    1/2
Read the file
; GraphAtlas proof RS-06
; Statement: Beyond the first smoothing point, the forward rate of each horizon lies between the last  …
; About: forwardFromFsp and extrapolate in src/kernel/curve.ts, with a the convergence parameter and h …
; Source: EIOPA-BoS-26-198, technical documentation of May 2026, Paragraphs 8.5.5 and 8.5.6
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun alpha_times_horizon () Real)
(declare-fun weight_of_llfr () Real)
(declare-fun llfr () Real)
(declare-fun ufr_less_llfr () Real)
(declare-fun forward_rate () Real)
(assert (> alpha_times_horizon 0.0))
(assert (> weight_of_llfr 0.0))
(assert (<= weight_of_llfr 1.0))
(assert (>= weight_of_llfr (- 1.0 (* (/ 1.0 2.0) alpha_times_horizon))))
(assert (<= (* weight_of_llfr alpha_times_horizon) 1.0))
(assert (let ((a!1 (+ (* (+ llfr ufr_less_llfr) (- 1.0 weight_of_llfr)) (* llfr (- 1.0 (- 1.0 weight_o …

; Goal 1, negated
(push 1)
(assert (not (>= (* (- forward_rate llfr) ufr_less_llfr) 0.0)))
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (>= (* (- (+ llfr ufr_less_llfr) forward_rate) ufr_less_llfr) 0.0)))
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (<= (* (- forward_rate llfr) ufr_less_llfr) (* (/ 1.0 2.0) alpha_times_horizon ufr_less_l …
; 8 more lines are in the file

Proved RS-07 Reserving and ESG EIOPA-BoS-26-198, technical documentation of May 2026, Paragraph 8.5.7

Beyond the first smoothing point, the zero rate of each horizon lies between the zero rate at the point and the forward rate of that horizon. It is nearer to the one that covers more years, which is the forward rate when the horizon is longer than the point and the zero rate at the point when it is shorter.

4 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given extrapolate in src/kernel/curve.ts, with the horizon and the point in years, both above zero. The zero rate is the total of the zero rate at the point times the point and the forward rate times the horizon, divided by the years of both. The quotient is written as the number whose product with its divisor is the dividend, which for a divisor above zero is the same number.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-07.smt2 SHA-256 8fed2a306647…a307f9e7

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • weights-swapped refuted at goal 3

    Weigh the zero rate at the point by the horizon and the forward rate by the point.

    first_smoothing_point
    3/4
    forward_rate
    0
    horizon
    3/2
    zero_rate
    -1
    zero_rate_at_the_point
    -3/2
  • divides-by-the-horizon refuted at goal 1

    Divide by the horizon alone, so that the two weights add up to more than one.

    first_smoothing_point
    1/8
    forward_rate
    0
    horizon
    7/64
    zero_rate
    -1/4
    zero_rate_at_the_point
    -7/32
  • zero-rate-is-the-forward-rate refuted at goal 4

    Take the forward rate as the zero rate, and forget the years before the point.

    first_smoothing_point
    1/4
    forward_rate
    0
    horizon
    1/4
    zero_rate
    0
    zero_rate_at_the_point
    -1/4
Read the file
; GraphAtlas proof RS-07
; Statement: Beyond the first smoothing point, the zero rate of each horizon lies between the zero rat …
; About: extrapolate in src/kernel/curve.ts, with the horizon and the point in years, both above zero. …
; Source: EIOPA-BoS-26-198, technical documentation of May 2026, Paragraph 8.5.7
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun horizon () Real)
(declare-fun first_smoothing_point () Real)
(declare-fun forward_rate () Real)
(declare-fun zero_rate_at_the_point () Real)
(declare-fun zero_rate () Real)
(assert (> horizon 0.0))
(assert (> first_smoothing_point 0.0))
(assert (= (* zero_rate (+ first_smoothing_point horizon)) (+ (* first_smoothing_point zero_rate_at_th …

; Goal 1, negated
(push 1)
(assert (not (or (>= zero_rate zero_rate_at_the_point) (>= zero_rate forward_rate))))
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (or (<= zero_rate zero_rate_at_the_point) (<= zero_rate forward_rate))))
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (<= (ite (>= (- zero_rate forward_rate) 0.0) (- zero_rate forward_rate) (- (-  …
(check-sat)
(pop 1)

; 5 more lines are in the file

Proved RS-08 Reserving and ESG EIOPA-BoS-26-198, technical documentation of May 2026, Annex C, paragraph C.3.6

The expected real rate is rounded to a whole number of five basis points, upwards when it is below the rounded rate of the year before and downwards otherwise. The rounded rate is less than five basis points from the unrounded one, a rate that is already a whole number of five basis points stays as it is, and a higher unrounded rate never gives a lower rounded one.

6 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given roundRealRate in src/kernel/curve.ts. A rate is a whole number of millionths, so five basis points is 500 of them. The rate of the year before is itself a whole number of five basis points. Rounding up gives the least multiple of five basis points that is not below the rate, and rounding down gives the greatest that is not above it.

Verdicts, 6 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 6
Z3 5.3.3 (native) Reran the emitted file unsat × 6
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 6

Each check asks the solver to break the statement. unsat means it cannot.

Download RS-08.smt2 SHA-256 88c3e8ee90c1…d213705c

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • always-down refuted at goal 3

    Round down whatever the year before was.

    a_higher_unrounded_real_rate
    0
    previous_rounded_rate
    0
    steps_down
    -1
    steps_down_of_the_higher
    0
    steps_up
    0
    steps_up_of_the_higher
    0
    unrounded_real_rate
    -499
  • direction-swapped refuted at goal 3

    Round down when the rate is below the year before, and up when it is not.

    a_higher_unrounded_real_rate
    0
    previous_rounded_rate
    0
    steps_down
    -1
    steps_down_of_the_higher
    0
    steps_up
    0
    steps_up_of_the_higher
    0
    unrounded_real_rate
    -499
  • to-the-nearest refuted at goal 3

    Round to the nearest five basis points, a half upwards.

    a_higher_unrounded_real_rate
    0
    nearest_steps
    -1
    nearest_steps_of_the_higher
    0
    previous_rounded_rate
    0
    unrounded_real_rate
    -499
  • ten-basis-points refuted at goal 2

    Round to a whole number of ten basis points, in the right direction.

    a_higher_unrounded_real_rate
    0
    previous_rounded_rate
    0
    steps_down
    -1
    steps_down_of_the_higher
    0
    steps_up
    0
    steps_up_of_the_higher
    0
    unrounded_real_rate
    -500
Read the file
; GraphAtlas proof RS-08
; Statement: The expected real rate is rounded to a whole number of five basis points, upwards when it …
; About: roundRealRate in src/kernel/curve.ts. A rate is a whole number of millionths, so five basis p …
; Source: EIOPA-BoS-26-198, technical documentation of May 2026, Annex C, paragraph C.3.6
; Expected: unsat for each of the 6 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun unrounded_real_rate () Int)
(declare-fun a_higher_unrounded_real_rate () Int)
(declare-fun previous_rounded_rate () Int)
(declare-fun steps_up () Int)
(declare-fun steps_down () Int)
(declare-fun steps_up_of_the_higher () Int)
(declare-fun steps_down_of_the_higher () Int)
(assert (>= a_higher_unrounded_real_rate unrounded_real_rate))
(assert (= (mod previous_rounded_rate 500) 0))
(assert (<= unrounded_real_rate (* steps_up 500)))
(assert (> unrounded_real_rate (* (- steps_up 1) 500)))
(assert (>= unrounded_real_rate (* steps_down 500)))
(assert (< unrounded_real_rate (* (+ steps_down 1) 500)))
(assert (<= a_higher_unrounded_real_rate (* steps_up_of_the_higher 500)))
(assert (> a_higher_unrounded_real_rate (* (- steps_up_of_the_higher 1) 500)))
(assert (>= a_higher_unrounded_real_rate (* steps_down_of_the_higher 500)))
(assert (< a_higher_unrounded_real_rate (* (+ steps_down_of_the_higher 1) 500)))

; Goal 1, negated
(push 1)
(assert (not (= (mod (ite (< unrounded_real_rate previous_rounded_rate) (* steps_up 500) (* steps_down …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (- (ite (< unrounded_real_rate previous_rounded_rate) (* steps_up 500) (* step …
; 26 more lines are in the file

Proved SC-01 SA-CVA Basel Framework, MAR50, MAR50.53(1)

When the hedges of a bucket offset every one of its risk factors in the same proportion, the quantity under the root of its capital is (1 − ratio)² × Q + R × ratio² × N, where Q is the form of the CVA weighted sensitivities through the correlation matrix, N is the sum of their squares and R is the hedging disallowance of 0.01. No ratio takes it below R × Q × N / (Q + R × N), the ratio Q / (Q + R × N) reaches that value, and so the capital of a bucket with a position is never zero.

3 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluateBucket in src/kernel/sacva.ts, with the hedging disallowance HEDGING_DISALLOWANCE_TEXT as an exact decimal. The net weighted sensitivity of a factor is the CVA one less the hedge, and with a hedge of ratio times the CVA one it is (1 − ratio) times it. The first two terms of MAR50.53(1) then give (1 − ratio)² Q and the third gives R × ratio² × N. The proof multiplies the quantity by Q + R × N so that it needs no division, and the key step is that the difference from R × Q × N is the square ((1 − ratio) × Q − R × ratio × N)².

Verdicts, 3 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 3
Z3 5.3.3 (native) Reran the emitted file unsat × 3
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 3

Each check asks the solver to break the statement. unsat means it cannot.

Download SC-01.smt2 SHA-256 1c53f8541863…5f1b8903

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • no-disallowance refuted at goal 3

    Set the hedging disallowance to zero, so that a hedge of the whole exposure leaves nothing to hold capital against.

    cva_form
    1
    cva_squares
    1
    hedge_ratio
    1
  • hedge-term-not-squared refuted at goal 1

    Take the third term as R × ratio × N, which is linear in the ratio, instead of R × ratio² × N.

    cva_form
    1
    cva_squares
    301
    hedge_ratio
    -1/2
  • disallowance-on-the-net refuted at goal 1

    Charge the disallowance on the net weighted sensitivities and not on the hedges, which is what a hedge that is as large as the exposure would then escape.

    cva_form
    1
    cva_squares
    1
    hedge_ratio
    1
  • floor-twice-too-high refuted at goal 1

    Claim a floor of twice R × Q × N / (Q + R × N), which the best ratio does not reach.

    cva_form
    1
    cva_squares
    200
    hedge_ratio
    0
Read the file
; GraphAtlas proof SC-01
; Statement: When the hedges of a bucket offset every one of its risk factors in the same proportion,  …
; About: evaluateBucket in src/kernel/sacva.ts, with the hedging disallowance HEDGING_DISALLOWANCE_TEX …
; Source: Basel Framework, MAR50, MAR50.53(1)
; Expected: unsat for each of the 3 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun cva_form () Real)
(declare-fun cva_squares () Real)
(declare-fun hedge_ratio () Real)
(assert (> cva_form 0.0))
(assert (> cva_squares 0.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (* (+ cva_form (* (/ 1.0 100.0) cva_squares)) (+ (* (- 1.0 hedge_ratio) (- 1.0 …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (- 1.0 (/ cva_form (+ cva_form (* (/ 1.0 100.0) cva_squares))))) (a!2 (* (/ 1. …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (> (+ (* (- 1.0 hedge_ratio) (- 1.0 hedge_ratio) cva_form) (* (/ 1.0 100.0) hedge_ratio h …
(check-sat)
(pop 1)

Proved SC-02 SA-CVA Basel Framework, MAR50, MAR50.52 and MAR50.53(1)

With the hedges of the previous statement, a ratio of hedging above zero and below 2 × Q / (Q + R × N) lowers the quantity under the root of the capital of a bucket, that ratio leaves it where it was with no hedge, and a ratio above it or below zero raises it. With the disallowance of 0.01 and a single factor, a hedge of more than 198 per cent of the exposure costs more capital than no hedge.

4 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluateBucket in src/kernel/sacva.ts for hedges in one proportion of the CVA sensitivities. The quantity under the root less its value with no hedge is ratio × ((Q + R × N) × ratio − 2 × Q), so its sign is that of the ratio times the sign of the ratio less 2 × Q / (Q + R × N). For one factor Q and N are equal and the edge is 2 / (1 + R), which is 1.98 for the disallowance of 0.01.

Verdicts, 4 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 4
Z3 5.3.3 (native) Reran the emitted file unsat × 4
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 4

Each check asks the solver to break the statement. unsat means it cannot.

Download SC-02.smt2 SHA-256 b37c05807eed…c8ac3d02

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • edge-at-the-best-ratio refuted at goal 2

    Take the best ratio Q / (Q + R × N) as the point beyond which hedging costs more than none, in place of twice that.

    cva_form
    1
    cva_squares
    1
  • disallowance-on-the-net refuted at goal 2

    Charge the disallowance on the net weighted sensitivities and not on the hedges, so that the quantity is (1 − ratio)² × (Q + R × N) and a hedge no longer costs capital of its own.

    cva_form
    1
    cva_squares
    1
  • edge-from-the-wrong-sum refuted at goal 2

    Take the edge as 2 × Q / (Q + N), with no disallowance in it.

    cva_form
    1
    cva_squares
    1
Read the file
; GraphAtlas proof SC-02
; Statement: With the hedges of the previous statement, a ratio of hedging above zero and below 2 x Q  …
; About: evaluateBucket in src/kernel/sacva.ts for hedges in one proportion of the CVA sensitivities.  …
; Source: Basel Framework, MAR50, MAR50.52 and MAR50.53(1)
; Expected: unsat for each of the 4 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun cva_form () Real)
(declare-fun cva_squares () Real)
(declare-fun hedge_ratio () Real)
(assert (> cva_form 0.0))
(assert (> cva_squares 0.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (< hedge_ratio (/ (* 2.0 cva_form) (+ cva_form (* (/ 1.0 100.0) cva_squares))) …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (- 1.0 (/ (* 2.0 cva_form) (+ cva_form (* (/ 1.0 100.0) cva_squares))))) (a!2  …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (> hedge_ratio (/ (* 2.0 cva_form) (+ cva_form (* (/ 1.0 100.0) cva_squares))) …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
(assert (not (let ((a!1 (> (+ (* (- 1.0 hedge_ratio) (- 1.0 hedge_ratio) cva_form) (* (/ 1.0 100.0) he …
; 2 more lines are in the file

Proved SC-03 SA-CVA Basel Framework, MAR50, MAR50.53(1)

In an interest rate bucket of six factors, the share that rests on the CVA sensitivity of each factor, which is the CVA weighted sensitivity times the matching entry of the correlation matrix times the net weighted sensitivities, and the share that rests on its hedge, which is the weighted hedge times R times itself less that entry, add up to the quantity under the root, whatever the sensitivities are. Divided by the capital, the shares add up to it.

1 check, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluateBucket in src/kernel/sacva.ts and the shares that sacva derives from it, with the correlation matrix IR_CORRELATION_TEXT of Table 4 as exact decimals and the hedging disallowance as an exact decimal. The statement is an identity, and the solver proves that the two sides are one polynomial.

Verdicts, 1 check

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 1
Z3 5.3.3 (native) Reran the emitted file unsat × 1
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 1

Each check asks the solver to break the statement. unsat means it cannot.

Download SC-03.smt2 SHA-256 6afca10b0d57…420c7f6c

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • no-disallowance-in-the-hedge-share refuted at goal 1

    Leave R times the hedge out of the share of a hedge, so that the share is minus the hedge times the matching entry.

    hedge_6
    1

    11 other variables are 0.

  • hedge-share-with-the-wrong-sign refuted at goal 1

    Give the share of a hedge the sign of the entry and not the opposite.

    hedge_6
    -1

    11 other variables are 0.

  • matrix-of-the-shares-differs refuted at goal 1

    Take the shares from a matrix in which the correlation of the one-year and the two-year factor is 0.95, while the capital uses the matrix of Table 4.

    hedge_1
    3
    hedge_2
    -1

    10 other variables are 0.

Read the file
; GraphAtlas proof SC-03
; Statement: In an interest rate bucket of six factors, the share that rests on the CVA sensitivity of …
; About: evaluateBucket in src/kernel/sacva.ts and the shares that sacva derives from it, with the cor …
; Source: Basel Framework, MAR50, MAR50.53(1)
; Expected: unsat for each of the 1 check below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun hedge_6 () Real)
(declare-fun hedge_5 () Real)
(declare-fun hedge_4 () Real)
(declare-fun hedge_3 () Real)
(declare-fun hedge_2 () Real)
(declare-fun hedge_1 () Real)
(declare-fun cva_6 () Real)
(declare-fun cva_5 () Real)
(declare-fun cva_4 () Real)
(declare-fun cva_3 () Real)
(declare-fun cva_2 () Real)
(declare-fun cva_1 () Real)

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (+ 0.0 (* 1.0 (- cva_1 hedge_1)) (* (/ 91.0 100.0) (- cva_2 hedge_2)) (* (/ 18 …
(check-sat)
(pop 1)

Proved SC-04 SA-CVA Basel Framework, MAR50, MAR50.53(2)

For three buckets that each have the same correlation of 0.5 with every other, or of 0.6, and whose sums of weighted sensitivities are cut to the range of their capital, the quantity under the root of the capital of a class is never below zero and never above the square of the sum of the bucket capitals. The capital of the class is then a real number, and the diversification it gives never lifts it above the plain sum of the buckets.

17 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluateClass in src/kernel/sacva.ts with the cross-bucket correlations IR_GAMMA_TEXT and FX_GAMMA_TEXT, which are 0.5 and 0.6 for every pair. The cut of S to the range of K is what MAR50.53(2) prescribes. Without it neither bound holds, and with it the proof needs only the squares and products of S and K that the lemmas bound. The solver checks three buckets. For more of them the same lemmas and the same sums apply bucket by bucket, and the certified statement SC-05 covers the seven buckets of credit spread risk.

Verdicts, 17 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 17
Z3 5.3.3 (native) Reran the emitted file unsat × 17
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 17

Each check asks the solver to break the statement. unsat means it cannot.

Download SC-04.smt2 SHA-256 79fffdcbebd7…1547cc20

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • sum-not-cut refuted at lemma 1

    Leave the sums of weighted sensitivities as they are, with no cut to the range of the bucket capital.

    k_1
    0
    k_2
    0
    k_3
    0
    s_1
    -1
  • correlation-above-one refuted at goal 1

    Use a correlation of 1.2 between the buckets, which a correlation cannot be.

    k_1
    0
    k_2
    17/16
    k_3
    9/8
    s_1
    0
    s_2
    -1
    s_3
    1
  • correlation-below-the-least-possible refuted at goal 1

    Use a correlation of −0.9 between three buckets, below the −0.5 that three can all have.

    k_1
    1
    k_2
    1
    k_3
    1
    s_1
    -1/2
    s_2
    -1
    s_3
    -7/8
Read the file
; GraphAtlas proof SC-04
; Statement: For three buckets that each have the same correlation of 0.5 with every other, or of 0.6, …
; About: evaluateClass in src/kernel/sacva.ts with the cross-bucket correlations IR_GAMMA_TEXT and FX_ …
; Source: Basel Framework, MAR50, MAR50.53(2)
; Expected: unsat for each of the 17 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun k_1 () Real)
(declare-fun k_2 () Real)
(declare-fun k_3 () Real)
(declare-fun s_1 () Real)
(declare-fun s_2 () Real)
(declare-fun s_3 () Real)
(assert (>= k_1 0.0))
(assert (>= k_2 0.0))
(assert (>= k_3 0.0))
(assert (>= s_1 (- k_1)))
(assert (<= s_1 k_1))
(assert (>= s_2 (- k_2)))
(assert (<= s_2 k_2))
(assert (>= s_3 (- k_3)))
(assert (<= s_3 k_3))

; Lemma 1, negated
(push 1)
(assert (not (<= (* s_1 s_1) (* k_1 k_1))))
(check-sat)
(pop 1)
; Lemma 1 holds, so later checks may use it
(assert (<= (* s_1 s_1) (* k_1 k_1)))

; Lemma 2, negated
(push 1)
(assert (not (<= (* s_2 s_2) (* k_2 k_2))))
; 116 more lines are in the file

Proved IC-01 ICS IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-143

For any five charges of the life risks that are not below zero, the quantity under the root of the life charge, which is the form of Table 6 of the Level 2 text, is at least 15/16 of the square of each charge and at most the square of their sum. So the life charge is never below the root of 15/16, which is 96.8 per cent, of its largest charge, and never above the sum of the charges. The floor is reached with a mortality charge of 4 and a longevity charge of 1, so that no higher floor can be proved.

24 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given icsRequirement in src/kernel/ics.ts, through aggregate in src/kernel/aggregate.ts, with LIFE_CORRELATION_TEXT as exact decimals. Table 6 has one entry below zero, minus 25 per cent between mortality and longevity, and every other entry is between 0 and 1. The key steps are that 16 × L² − 8 × M × L + M² is the square of M − 4 × L, which gives M² + L² − M × L / 2 at least 15/16 of M², and the square of 4 × M − L, which gives the same for L². The products of two charges are not below zero, so every other term only adds. The lemmas state the squares and the products and the solver adds them up.

Verdicts, 24 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 24
Z3 5.3.3 (native) Reran the emitted file unsat × 24
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 24

Each check asks the solver to break the statement. unsat means it cannot.

Download IC-01.smt2 SHA-256 0571cb747edc…86323888

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • longevity-sign-flipped refuted at goal 7

    Give mortality and longevity a correlation of plus 25 per cent in place of minus 25, so that the form never falls below the square of the largest charge and the floor is not reached.

    expense_charge
    0
    lapse_charge
    0
    longevity_charge
    0
    morbidity_charge
    0
    mortality_charge
    0
  • longevity-offset-too-strong refuted at goal 1

    Give mortality and longevity a correlation of minus 50 per cent, which takes the form below 15/16 of the square of the largest charge.

    expense_charge
    0
    lapse_charge
    0
    longevity_charge
    1
    morbidity_charge
    0
    mortality_charge
    2
  • floor-of-one refuted at goal 1

    Claim that the form is never below the square of the largest charge, which a longevity charge of a quarter of the mortality charge refutes.

    expense_charge
    0
    lapse_charge
    0
    longevity_charge
    1
    morbidity_charge
    0
    mortality_charge
    3
  • correlation-above-one refuted at goal 6

    Give lapse and expense a correlation of 1.2, which a correlation cannot be, so that the form is above the square of the sum.

    expense_charge
    1
    lapse_charge
    1
    longevity_charge
    0
    morbidity_charge
    0
    mortality_charge
    0
Read the file
; GraphAtlas proof IC-01
; Statement: For any five charges of the life risks that are not below zero, the quantity under the ro …
; About: icsRequirement in src/kernel/ics.ts, through aggregate in src/kernel/aggregate.ts, with LIFE_ …
; Source: IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-143
; Expected: unsat for each of the 24 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun mortality_charge () Real)
(declare-fun longevity_charge () Real)
(declare-fun morbidity_charge () Real)
(declare-fun lapse_charge () Real)
(declare-fun expense_charge () Real)
(assert (>= mortality_charge 0.0))
(assert (>= longevity_charge 0.0))
(assert (>= morbidity_charge 0.0))
(assert (>= lapse_charge 0.0))
(assert (>= expense_charge 0.0))

; Lemma 1, negated
(push 1)
(assert (not (>= (* mortality_charge mortality_charge) 0.0)))
(check-sat)
(pop 1)
; Lemma 1 holds, so later checks may use it
(assert (>= (* mortality_charge mortality_charge) 0.0))

; Lemma 2, negated
(push 1)
(assert (not (>= (* longevity_charge longevity_charge) 0.0)))
(check-sat)
(pop 1)
; Lemma 2 holds, so later checks may use it
(assert (>= (* longevity_charge longevity_charge) 0.0))

; 161 more lines are in the file

Proved IC-02 ICS IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-143

With a mortality charge M above zero and a longevity charge L, and nothing else in the life risks, the quantity under the root of the life charge is M² + L² − M × L / 2. It is below M² for any L above zero and below M / 2, it equals M² at M / 2, and it is above M² beyond. It is lowest at L = M / 4, where it is 15/16 of M². A longevity charge of a quarter of the mortality charge therefore lowers the life charge by 3.2 per cent, and a larger one lowers the requirement too, as long as it is below half.

5 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given icsRequirement in src/kernel/ics.ts, through aggregate in src/kernel/aggregate.ts, with LIFE_CORRELATION_TEXT as exact decimals and the charges of morbidity, lapse and expense at zero. The form is M² + L² + 2 × rho × M × L with rho the entry of Table 6 between mortality and longevity, which is −0.25. The difference from M² is L × (L − M / 2), whose sign is that of L less M / 2.

Verdicts, 5 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 5
Z3 5.3.3 (native) Reran the emitted file unsat × 5
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 5

Each check asks the solver to break the statement. unsat means it cannot.

Download IC-02.smt2 SHA-256 c785f94ab801…38554955

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • longevity-sign-flipped refuted at goal 1

    Give mortality and longevity a correlation of plus 25 per cent, so that no longevity charge lowers the form.

    longevity_charge
    1
    mortality_charge
    3
  • no-correlation refuted at goal 1

    Give mortality and longevity a correlation of zero, so that the form is the sum of the squares.

    longevity_charge
    1
    mortality_charge
    3
  • offset-of-one-eighth refuted at goal 1

    Give mortality and longevity a correlation of minus 12.5 per cent, which moves the point where the form comes back to M² from M / 2 to M / 4.

    longevity_charge
    1
    mortality_charge
    3
  • offset-of-one-half refuted at goal 2

    Give mortality and longevity a correlation of minus 50 per cent, which moves the lowest point and takes the form below 15/16 of M².

    longevity_charge
    1
    mortality_charge
    2
Read the file
; GraphAtlas proof IC-02
; Statement: With a mortality charge M above zero and a longevity charge L, and nothing else in the li …
; About: icsRequirement in src/kernel/ics.ts, through aggregate in src/kernel/aggregate.ts, with LIFE_ …
; Source: IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-143
; Expected: unsat for each of the 5 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun mortality_charge () Real)
(declare-fun longevity_charge () Real)
(assert (> mortality_charge 0.0))
(assert (>= longevity_charge 0.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (* 0.0 (+ (+ 0.0 (* (/ 1.0 4.0) mortality_charge)) (* 0.0 longevity_charge) (* …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (* 0.0 (+ (+ 0.0 (* (/ 1.0 4.0) mortality_charge)) (* 0.0 longevity_charge) (* …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (* 0.0 (+ (+ 0.0 (* (/ 1.0 4.0) mortality_charge)) (* 0.0 longevity_charge) (* …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
(assert (not (let ((a!1 (* 0.0 (+ (+ 0.0 (* (/ 1.0 4.0) mortality_charge)) (* 0.0 longevity_charge) (* …
(check-sat)
; 7 more lines are in the file

Proved IC-03 ICS IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-203 and L2-335

For charges that are not below zero, the quantity under the root of the market charge, in the row of Table 16 for an upward spread stress and in the row for a downward one, and the quantity under the root of the top level of Table 34, are each at least the sum of the squares of the charges and at most the square of their sum. So each aggregate is at least the root of the sum of the squares, which is what no correlation at all gives, and at most the sum of the charges. The charge of a category is real, and diversification never lifts it above the plain sum.

31 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given icsRequirement in src/kernel/ics.ts, through aggregate in src/kernel/aggregate.ts, with the two six by six tables that marketTableText gives and TOP_CORRELATION_TEXT as exact decimals. The two tables are the entries of Table 16 for six risks, with the downward stress taken out and with the upward stress taken out. Every entry of the three tables is between 0 and 1, so that each term of the form differs from the plain one by a product of two charges times a number between 0 and 2, and the products are not below zero. The solver checks the two limits for each table.

Verdicts, 31 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 31
Z3 5.3.3 (native) Reran the emitted file unsat × 31
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 31

Each check asks the solver to break the statement. unsat means it cannot.

Download IC-03.smt2 SHA-256 32a5c0da2122…46fa1288

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • correlation-above-one refuted at goal 2

    Give equity and the upward spread stress a correlation of 1.2, which a correlation cannot be, so that the form is above the square of the sum.

    equity_charge
    1
    spread_charge
    1

    9 other variables are 0.

  • negative-correlation-between-life-and-non-life refuted at goal 5

    Give life and non-life a correlation of minus 25 per cent in the top level, so that the form is below the sum of the squares.

    life_charge
    1
    non_life_charge
    1

    9 other variables are 0.

  • negative-correlation-in-the-downward-row refuted at goal 3

    Give the downward stress and the currency charge a correlation of minus 30 per cent, so that the form is below the sum of the squares.

    currency_charge
    1
    spread_charge
    1

    9 other variables are 0.

Read the file
; GraphAtlas proof IC-03
; Statement: For charges that are not below zero, the quantity under the root of the market charge, in …
; About: icsRequirement in src/kernel/ics.ts, through aggregate in src/kernel/aggregate.ts, with the t …
; Source: IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-203 and L2-335
; Expected: unsat for each of the 31 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun interest_rate_charge () Real)
(declare-fun spread_charge () Real)
(declare-fun equity_charge () Real)
(declare-fun real_estate_charge () Real)
(declare-fun currency_charge () Real)
(declare-fun concentration_charge () Real)
(declare-fun life_charge () Real)
(declare-fun non_life_charge () Real)
(declare-fun catastrophe_charge () Real)
(declare-fun market_charge () Real)
(declare-fun credit_charge () Real)
(assert (>= interest_rate_charge 0.0))
(assert (>= spread_charge 0.0))
(assert (>= equity_charge 0.0))
(assert (>= real_estate_charge 0.0))
(assert (>= currency_charge 0.0))
(assert (>= concentration_charge 0.0))
(assert (>= life_charge 0.0))
(assert (>= non_life_charge 0.0))
(assert (>= catastrophe_charge 0.0))
(assert (>= market_charge 0.0))
(assert (>= credit_charge 0.0))

; Lemma 1, negated
(push 1)
(assert (not (>= (* interest_rate_charge spread_charge) 0.0)))
(check-sat)
; 231 more lines are in the file

Proved IC-04 ICS IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-335 and L1-141

Before the operational charge, a life, catastrophe or market risk has the part of the insurance risk charge that is its share inside its category, c × (R × c) / A, times the weighted charge of the category over the aggregate. Non-life and credit take their own charge times that factor. The parts add up to the aggregate. The terms c × (R × c) of each table add up to the square of the charge of their category, and the terms of Table 34 add up to the square of the aggregate. Terms that add up to the square of a number add up to it when divided by it. A factor times shares that add up to a charge adds up to the factor times it.

7 checks, decided by 3 solvers. 5 broken variants refuted. Show the evidence Hide the evidence

What the solver was given icsRequirement in src/kernel/ics.ts, with the shares of aggregate in src/kernel/aggregate.ts and the factor that icsRequirement takes as the weighted charge of the category over the total at the top. The tables are exact decimals. The four identities are polynomial identities, and the solver proves that the two sides of each are one polynomial. The three steps are stated for free numbers, with no table in them, so that a solver has little to hold at once, and the identities show that the numbers of the engine are such numbers. The third step is that a weight over the aggregate times a charge is the charge times the weight over the aggregate, which is how the factor of a category times its charge is its share at the top. A charge of zero has parts of zero, which the tests show. The downward table of Table 16 has the same identity, and the tests cover it with the second program.

Verdicts, 7 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 7
Z3 5.3.3 (native) Reran the emitted file unsat × 7
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 7

Each check asks the solver to break the statement. unsat means it cannot.

Download IC-04.smt2 SHA-256 dc17dfd57162…16c5b8ba

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • other-table-for-life refuted at goal 1

    Take the terms inside life from a table in which mortality and longevity are correlated at plus 25 per cent, while the life charge uses Table 6, so that the terms no longer add up to the square of the charge.

    expense_charge
    0
    lapse_charge
    0
    longevity_charge
    -1
    morbidity_charge
    0
    mortality_charge
    -1
  • other-table-for-market refuted at goal 3

    Take the terms inside the market charge from the table of the downward spread stress, while the charge uses the one of the upward stress.

    currency_charge
    0
    equity_charge
    0
    real_estate_charge
    -1
    spread_charge
    2
  • shares-over-something-else refuted at goal 5

    Divide the terms of a category by something other than its charge, so that the shares do not add up to the charge.

    category_charge
    approximately 0.999022
    other_divisor
    0
    term_1
    0
    term_2
    0
    term_3
    0
    term_4
    0
    term_5
    0
    term_6
    approximately 0.998046
  • factor-of-the-wrong-category refuted at goal 4

    Give each category the weighted charge of the next row of Table 34, so that the factors times the charges do not add up to the aggregate.

    catastrophe_charge
    0
    credit_charge
    0
    life_charge
    0
    market_charge
    0
    non_life_charge
    1
  • no-top-factor refuted at goal 6

    Give each risk its share inside its category and leave out the factor that the top level gives to the category, so that the parts add up to the charge of the category and not to the factor times it.

    factor
    0
    own_charge
    -1
    share_1
    0
    share_2
    0
    share_3
    0
    share_4
    0
    share_5
    0
    share_6
    -1
Read the file
; GraphAtlas proof IC-04
; Statement: Before the operational charge, a life, catastrophe or market risk has the part of the ins …
; About: icsRequirement in src/kernel/ics.ts, with the shares of aggregate in src/kernel/aggregate.ts  …
; Source: IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-335 and L1-141
; Expected: unsat for each of the 7 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun expense_charge () Real)
(declare-fun lapse_charge () Real)
(declare-fun morbidity_charge () Real)
(declare-fun longevity_charge () Real)
(declare-fun mortality_charge () Real)
(declare-fun credit_and_surety_charge () Real)
(declare-fun pandemic_charge () Real)
(declare-fun terrorism_charge () Real)
(declare-fun natural_charge () Real)
(declare-fun concentration_charge () Real)
(declare-fun currency_charge () Real)
(declare-fun real_estate_charge () Real)
(declare-fun equity_charge () Real)
(declare-fun spread_charge () Real)
(declare-fun interest_rate_charge () Real)
(declare-fun credit_charge () Real)
(declare-fun market_charge () Real)
(declare-fun catastrophe_charge () Real)
(declare-fun non_life_charge () Real)
(declare-fun life_charge () Real)
(declare-fun category_charge () Real)
(declare-fun term_6 () Real)
(declare-fun term_5 () Real)
(declare-fun term_4 () Real)
(declare-fun term_3 () Real)
(declare-fun term_2 () Real)
(declare-fun term_1 () Real)
; 53 more lines are in the file

Proved IC-05 ICS IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-347 to L2-353

The tax effect taken off the insurance risk charge lies between zero and 80 per cent of the notional effect, which is the requirement times the group effective tax rate, so at least a fifth of the requirement is left. The carry-back component is at most 85 per cent of the notional effect. The net deferred tax asset is at most 15 per cent of the requirement and is never held against a net liability. An asset can only lower what is used, and a sum of components between nothing and the cap is what is used. It holds for any notional effect up to the requirement and any three sub-groups, capacity, earnings and deferred taxes.

10 checks, decided by 3 solvers. 6 broken variants refuted. Show the evidence Hide the evidence

What the solver was given taxEffect in src/kernel/ics.ts for the limited rule of L2-349, with the constants UTILISATION_TEXT, CARRY_BACK_TEXT, FUTURE_INCOME_TEXT and DTA_CAP_TEXT as exact decimals. The notional effect is the requirement times the rate, and the proof takes it as any number from zero up to the requirement, which that product always is for a rate from 0 to 1, because a solver divides more easily by a number than by a product. Each sub-group has the share of it that its liabilities are of the total, the capacity counted for it is the smaller of the share and its carry-back capacity, and the used amount is the sum of the components held between zero and the cap. The default rule uses the cap itself. The proof has three sub-groups, and the same shares add up to the notional effect for any number.

Verdicts, 10 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 10
Z3 5.3.3 (native) Reran the emitted file unsat × 10
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 10

Each check asks the solver to break the statement. unsat means it cannot.

Download IC-05.smt2 SHA-256 9e8fecddcac6…dd6661e9

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • cap-at-the-notional-effect refuted at goal 2

    Let the whole of the notional tax effect be used and not 80 per cent of it.

    liabilities_3
    1
    liability
    9
    notional_tax_effect
    10
    projected_loss
    false
    requirement
    10
    total_liabilities
    1

    8 other variables are 0.

  • no-floor refuted at goal 1

    Leave out the floor of zero, so that a net deferred tax asset that is larger than the other components gives a negative tax effect, which raises the requirement.

    asset
    20/37
    liabilities_3
    40/37
    projected_loss
    false
    requirement
    approximately 3.603604
    total_liabilities
    40/37

    9 other variables are 0.

  • sub-groups-not-shared refuted at lemma 1

    Allocate the whole notional effect to every sub-group and not the share that its liabilities are of the total.

    liabilities_3
    1/2
    notional_tax_effect
    1/2
    requirement
    1/2
    total_liabilities
    1/2

    9 other variables are 0.

  • asset-not-limited refuted at goal 5

    Let the net deferred tax asset be as large as the asset less the liability, with no limit of 15 per cent of the requirement.

    asset
    approximately 1
    liabilities_3
    1
    requirement
    approximately 0.000002
    total_liabilities
    1

    9 other variables are 0.

  • no-deduction-on-the-carry-back refuted at goal 4

    Count the carry-back capacity in full and not less 15 per cent.

    capacity_3
    20/3
    liabilities_3
    1
    notional_tax_effect
    20/3
    requirement
    20/3
    total_liabilities
    1

    8 other variables are 0.

  • liability-and-asset-swapped refuted at goal 6

    Take the net liability as the asset less the liability, so that the same difference is both a liability and an asset.

    asset
    1
    liabilities_3
    1
    requirement
    20/3
    total_liabilities
    1

    9 other variables are 0.

Read the file
; GraphAtlas proof IC-05
; Statement: The tax effect taken off the insurance risk charge lies between zero and 80 per cent of t …
; About: taxEffect in src/kernel/ics.ts for the limited rule of L2-349, with the constants UTILISATION …
; Source: IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-347 to L2-353
; Expected: unsat for each of the 10 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun requirement () Real)
(declare-fun tax_rate () Real)
(declare-fun liabilities_1 () Real)
(declare-fun liabilities_2 () Real)
(declare-fun liabilities_3 () Real)
(declare-fun total_liabilities () Real)
(declare-fun notional_tax_effect () Real)
(declare-fun capacity_1 () Real)
(declare-fun capacity_2 () Real)
(declare-fun capacity_3 () Real)
(declare-fun earnings () Real)
(declare-fun liability () Real)
(declare-fun asset () Real)
(declare-fun projected_loss () Bool)
(assert (>= requirement 0.0))
(assert (>= tax_rate 0.0))
(assert (<= tax_rate 1.0))
(assert (>= liabilities_1 0.0))
(assert (>= liabilities_2 0.0))
(assert (>= liabilities_3 0.0))
(assert (= total_liabilities (+ 0.0 liabilities_1 liabilities_2 liabilities_3)))
(assert (> total_liabilities 0.0))
(assert (>= notional_tax_effect 0.0))
(assert (<= notional_tax_effect requirement))
(assert (>= capacity_1 0.0))
(assert (>= capacity_2 0.0))
(assert (>= capacity_3 0.0))
; 67 more lines are in the file

Proved IC-06 ICS IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-122, L2-127 and L2-129

For any capital resources and any requirement, what counts and what is left out add up to what is held, for a group that is not mutual and for a mutual. For a group that is not mutual, Tier 1 Limited counts up to 15 per cent of the requirement, Tier 2 up to 50 per cent and the basket up to 15 per cent, and none of the Non-Paid-Up capital counts. For a mutual, Tier 1 Limited counts up to 30 per cent, Non-Paid-Up up to 10 per cent, and Tier 1 Limited and Tier 2 together up to 60 per cent. What Tier 1 Limited has over its limit moves to Tier 2. What is left out is not below zero and what counts is not above what is held.

20 checks, decided by 3 solvers. 7 broken variants refuted. Show the evidence Hide the evidence

What the solver was given qualifyingResources in src/kernel/ics.ts, with LIMIT_TEXT and BASKET_SHARE_TEXT as exact decimals. The basket enters as the sum of its three items at their shares, which are 50, 100 and 10 per cent. The group that is not mutual counts the smaller of Tier 1 Limited, 10 per cent of the requirement and what has a loss absorbency mechanism, and 15 per cent of the requirement. The mutual counts the smaller of Tier 1 Limited and 30 per cent, and its combined limit is 60 per cent less the Tier 1 Limited that counts. The excess of Tier 1 Limited, the basket that counts, the Non-Paid-Up that counts and Tier 2 make the pool that the Tier 2 limit applies to.

Verdicts, 20 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 20
Z3 5.3.3 (native) Reran the emitted file unsat × 20
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 20

Each check asks the solver to break the statement. unsat means it cannot.

Download IC-06.smt2 SHA-256 76c7b0fe70ac…f140ab65

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • no-fifteen-per-cent-cap refuted at goal 3

    Count Tier 1 Limited up to 10 per cent of the requirement and what has a loss absorbency mechanism, with no cap of 15 per cent.

    tier_1_limited
    1/2
    tier_1_limited_with_mechanism
    1/2

    7 other variables are 0.

  • excess-not-moved refuted at goal 1

    Leave what Tier 1 Limited has over its limit out of Tier 2, and out of the amount left out too.

    tier_1_limited
    1/2

    8 other variables are 0.

  • non-paid-up-counts-for-everyone refuted at goal 9

    Count Non-Paid-Up capital up to 10 per cent of the requirement for a group that is not mutual.

    non_paid_up
    1/2
    requirement
    5

    7 other variables are 0.

  • combined-limit-not-reduced refuted at goal 8

    Take the combined limit of a mutual as 60 per cent for Tier 2 alone, and not 60 per cent less the Tier 1 Limited that counts.

    requirement
    5/12
    tier_1_limited
    1/2

    7 other variables are 0.

  • excluded-forgets-the-pool refuted at goal 1

    Leave what is above the Tier 2 limit out of the amount that is left out, for a group that is not mutual.

    tier_2
    1/2

    8 other variables are 0.

  • software-counts-in-full refuted at goal 18

    Count the software intangibles of the basket in full and not at a tenth.

    software_intangibles
    1/2

    8 other variables are 0.

  • basket-limit-of-thirty-per-cent refuted at goal 5

    Let the basket count up to 30 per cent of the requirement.

    requirement
    20/3
    software_intangibles
    20

    7 other variables are 0.

Read the file
; GraphAtlas proof IC-06
; Statement: For any capital resources and any requirement, what counts and what is left out add up to …
; About: qualifyingResources in src/kernel/ics.ts, with LIMIT_TEXT and BASKET_SHARE_TEXT as exact deci …
; Source: IAIS Insurance Capital Standard, Level 2 text of 5 December 2024, L2-122, L2-127 and L2-129
; Expected: unsat for each of the 20 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun requirement () Real)
(declare-fun tier_1_unlimited () Real)
(declare-fun tier_1_limited () Real)
(declare-fun tier_1_limited_with_mechanism () Real)
(declare-fun tier_2 () Real)
(declare-fun non_paid_up () Real)
(declare-fun pension_fund_asset () Real)
(declare-fun deferred_tax_asset_item () Real)
(declare-fun software_intangibles () Real)
(assert (>= requirement 0.0))
(assert (>= tier_1_unlimited 0.0))
(assert (>= tier_1_limited 0.0))
(assert (>= tier_1_limited_with_mechanism 0.0))
(assert (<= tier_1_limited_with_mechanism tier_1_limited))
(assert (>= tier_2 0.0))
(assert (>= non_paid_up 0.0))
(assert (>= pension_fund_asset 0.0))
(assert (>= deferred_tax_asset_item 0.0))
(assert (>= software_intangibles 0.0))

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (<= tier_1_limited (+ (* (/ 1.0 10.0) requirement) tier_1_limited_with_me …
(check-sat)
(pop 1)

; Goal 2, negated
; 112 more lines are in the file

Proved SM-01 SIMM ISDA SIMM Methodology, version 2.8+2512, paragraph 6

For margins of the six risk classes that are not below zero, the quantity under the root of the margin of a product class is at least the sum of the squares of the margins and at most the square of their sum. So the margin is at least the root of the sum of squares, which is what independent risk classes give, and at most the sum of the six margins.

17 checks, decided by 3 solvers. 3 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluate in src/kernel/simm.ts, through aggregate in src/kernel/aggregate.ts, with PSI_TEXT as exact decimals. Every entry of the table is between 0 and 1, so each term of the form differs from the plain one by a product of two margins times a number between 0 and 2, and the products are not below zero. The lemmas state the products and the solver adds them up.

Verdicts, 17 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 17
Z3 5.3.3 (native) Reran the emitted file unsat × 17
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 17

Each check asks the solver to break the statement. unsat means it cannot.

Download SM-01.smt2 SHA-256 cc160054fb49…ef4a6b1c

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • correlation-above-one refuted at goal 2

    Give non-qualifying credit and equity a correlation of 1.2, which a correlation cannot be, so that the form is above the square of the sum.

    commodity_margin
    0
    credit_non_qualifying_margin
    1
    credit_qualifying_margin
    0
    equity_margin
    1
    fx_margin
    0
    interest_rate_margin
    0
  • negative-correlation refuted at goal 1

    Give equity and commodity a correlation of minus 20 per cent, so that the form is below the sum of the squares.

    commodity_margin
    1
    credit_non_qualifying_margin
    0
    credit_qualifying_margin
    0
    equity_margin
    1
    fx_margin
    0
    interest_rate_margin
    0
  • fx-fully-correlated-and-more refuted at goal 2

    Give FX and interest rate a correlation of 1.01, which takes the form above the square of the sum.

    commodity_margin
    0
    credit_non_qualifying_margin
    0
    credit_qualifying_margin
    0
    equity_margin
    0
    fx_margin
    1
    interest_rate_margin
    1
Read the file
; GraphAtlas proof SM-01
; Statement: For margins of the six risk classes that are not below zero, the quantity under the root  …
; About: evaluate in src/kernel/simm.ts, through aggregate in src/kernel/aggregate.ts, with PSI_TEXT a …
; Source: ISDA SIMM Methodology, version 2.8+2512, paragraph 6
; Expected: unsat for each of the 17 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun interest_rate_margin () Real)
(declare-fun credit_qualifying_margin () Real)
(declare-fun credit_non_qualifying_margin () Real)
(declare-fun equity_margin () Real)
(declare-fun commodity_margin () Real)
(declare-fun fx_margin () Real)
(assert (>= interest_rate_margin 0.0))
(assert (>= credit_qualifying_margin 0.0))
(assert (>= credit_non_qualifying_margin 0.0))
(assert (>= equity_margin 0.0))
(assert (>= commodity_margin 0.0))
(assert (>= fx_margin 0.0))

; Lemma 1, negated
(push 1)
(assert (not (>= (* interest_rate_margin credit_qualifying_margin) 0.0)))
(check-sat)
(pop 1)
; Lemma 1 holds, so later checks may use it
(assert (>= (* interest_rate_margin credit_qualifying_margin) 0.0))

; Lemma 2, negated
(push 1)
(assert (not (>= (* interest_rate_margin credit_non_qualifying_margin) 0.0)))
(check-sat)
(pop 1)
; Lemma 2 holds, so later checks may use it
; 117 more lines are in the file

Proved SM-02 SIMM ISDA SIMM Methodology, version 2.8+2512, paragraphs 7(b) and 8(b)

The concentration factor is never below one and is one up to the threshold. Above it, its square times the threshold is the exposure, so the margin of a lone factor grows with the exposure to the power 3/2. It rises with the exposure, so more exposure never lowers a weighted sensitivity, and it depends only on the exposure over the threshold, so the unit of both does not matter.

6 checks, decided by 3 solvers. 5 broken variants refuted. Show the evidence Hide the evidence

What the solver was given concentrationFactor in src/kernel/simm.ts, which is the larger of 1 and the root of the absolute exposure over the threshold. The proof takes the absolute exposure as a number x from zero up, the threshold as a number above zero, and the root as a number r from zero up with r² × threshold = x, so it states the root by its square. The weighted exposure of a lone factor is its weight times the factor times the exposure.

Verdicts, 6 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 6
Z3 5.3.3 (native) Reran the emitted file unsat × 6
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 6

Each check asks the solver to break the statement. unsat means it cannot.

Download SM-02.smt2 SHA-256 83430825b623…e21eeb34

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • floor-of-half refuted at goal 1

    Floor the factor at one half and not at one, so that an exposure far below the threshold has a factor below one and its weighted sensitivity is lowered.

    exposure
    0
    root
    0
    threshold
    1
  • smaller-not-larger refuted at goal 1

    Take the smaller of 1 and the root, so that the factor is never above one and large exposures are not concentrated at all.

    exposure
    0
    root
    0
    threshold
    1
  • no-root refuted at goal 3

    Use the exposure over the threshold and not its root, so that the factor grows as fast as the exposure.

    exposure
    4
    root
    2
    threshold
    1
  • floor-of-two refuted at goal 2

    Floor the factor at two, so that exposures below the threshold are concentrated.

    exposure
    0
    root
    0
    threshold
    1
  • root-of-a-multiple refuted at goal 3

    Take the root of the exposure over twice the threshold, so that the square of the factor times the threshold is no longer the exposure.

    exposure
    2
    root
    1
    threshold
    1
Read the file
; GraphAtlas proof SM-02
; Statement: The concentration factor is never below one and is one up to the threshold. Above it, its …
; About: concentrationFactor in src/kernel/simm.ts, which is the larger of 1 and the root of the absol …
; Source: ISDA SIMM Methodology, version 2.8+2512, paragraphs 7(b) and 8(b)
; Expected: unsat for each of the 6 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun root () Real)
(declare-fun exposure () Real)
(declare-fun threshold () Real)
(declare-fun weight () Real)
(declare-fun larger_root () Real)
(declare-fun larger_exposure () Real)
(declare-fun scaled_root () Real)
(declare-fun unit () Real)

; Goal 1, negated
(push 1)
(assert (not (=> (and (>= exposure 0.0) (> threshold 0.0) (>= root 0.0) (= (* root root threshold) exp …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (=> (and (>= exposure 0.0) (> threshold 0.0) (>= root 0.0) (= (* root root threshold) exp …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (= (* (ite (>= 1.0 root) 1.0 root) (ite (>= 1.0 root) 1.0 root) threshold) exp …
(check-sat)
(pop 1)

; 17 more lines are in the file

Proved SM-03 SIMM ISDA SIMM Methodology, version 2.8+2512, paragraphs 7(c) and 8(c)

In a bucket, the parts that rest on the factors add up to K² + S × C, where K² is the quantity under the root of the bucket margin, S is the clipped sum of the weighted sensitivities and C is what the other buckets put in the cross term. It holds when the sum is inside the clip, above it or below it, or when K is zero, and for any number of factors, because each step of the sum keeps the invariant.

8 checks, decided by 3 solvers. 9 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluate and evaluateBucket in src/kernel/simm.ts. The part of the margin that rests on a factor is ws × (u + C × d) times a factor that is the same for the whole bucket, where d is 1 inside the clip, plus or minus u over K outside it, and 0 when K is zero. The proof states the invariant of the loop over the factors for each case, with A the sum of ws × u so far and B the sum of ws, and the solver checks that one more factor keeps it. When the loop ends A is K², because K is the root of it, and B decides the case. No table is in the proof, because u can be anything, which is what the positive definite correlation matrix is certified for separately.

Verdicts, 8 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 8
Z3 5.3.3 (native) Reran the emitted file unsat × 8
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 8

Each check asks the solver to break the statement. unsat means it cannot.

Download SM-03.smt2 SHA-256 7ff53f7fb294…a788bbf2

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • cross-term-without-direction refuted at goal 2

    Give every factor the same share of the cross term when the sum is above the clip, and not the share u over K, so that the parts no longer add up.

    cross
    -1
    k
    1
    k_inverse
    1
    products_so_far
    0
    shares_so_far
    0
    weighted_row
    0
    weighted_sensitivity
    -1
  • direction-not-divided-by-k refuted at goal 2

    Use u and not u over K for the direction above the clip, so that it has the wrong size by a factor K.

    cross
    -1
    k
    1/2
    k_inverse
    2
    products_so_far
    0
    shares_so_far
    0
    weighted_row
    -1
    weighted_sensitivity
    -1
  • below-with-the-sign-of-above refuted at goal 3

    Give the direction below the clip the sign that it has above it, so that the cross term is allocated against the clipped sum.

    cross
    -1
    k
    1
    k_inverse
    1
    products_so_far
    0
    shares_so_far
    0
    weighted_row
    -1
    weighted_sensitivity
    -1
  • above-not-clipped refuted at goal 6

    Use the sum itself for S above the clip, so that S is larger than K and the parts do not add up to K² + S × C.

    cross
    -1
    k
    1
    k_inverse
    1
    products_so_far
    1
    shares_so_far
    0
    weights_so_far
    2
  • cross-term-twice-inside refuted at goal 1

    Count the cross term twice for each factor when the sum is inside the clip.

    cross
    -1
    k
    0
    products_so_far
    0
    shares_so_far
    0
    weighted_sensitivity
    -1
    weights_so_far
    0
  • direction-of-one-when-k-is-zero refuted at goal 4

    Give each factor a direction of one when K is zero and the sum is not, where the engine gives it nothing.

    cross
    -1
    k
    0
    products_so_far
    0
    shares_so_far
    0
    weighted_row
    0
    weighted_sensitivity
    -1
  • below-not-clipped refuted at goal 7

    Use the sum itself for S below the clip, so that S is beyond minus K and the parts do not add up to K² + S × C.

    cross
    1
    k
    1
    k_inverse
    1
    products_so_far
    1
    shares_so_far
    0
    weights_so_far
    -2
  • inside-clipped-to-k refuted at goal 5

    Use K for S when the sum is inside the clip, so that S is not the sum.

    cross
    -1
    k
    1/2
    products_so_far
    1/4
    shares_so_far
    0
    weights_so_far
    1/4
  • sum-used-when-k-is-zero refuted at goal 8

    Use the sum for S when K is zero, where the clip makes S zero.

    cross
    1
    k
    0
    products_so_far
    0
    shares_so_far
    0
    weights_so_far
    1
Read the file
; GraphAtlas proof SM-03
; Statement: In a bucket, the parts that rest on the factors add up to K^2 + S x C, where K^2 is the q …
; About: evaluate and evaluateBucket in src/kernel/simm.ts. The part of the margin that rests on a fac …
; Source: ISDA SIMM Methodology, version 2.8+2512, paragraphs 7(c) and 8(c)
; Expected: unsat for each of the 8 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun weighted_sensitivity () Real)
(declare-fun weights_so_far () Real)
(declare-fun cross () Real)
(declare-fun weighted_row () Real)
(declare-fun products_so_far () Real)
(declare-fun shares_so_far () Real)
(declare-fun k () Real)
(declare-fun k_inverse () Real)

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (and (>= k 0.0) (= shares_so_far (+ products_so_far (* cross weights_so_far))) …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (and (> k 0.0) (= (* k k_inverse) (to_real 1)) (= shares_so_far (+ products_so …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (and (> k 0.0) (= (* k k_inverse) (to_real 1)) (= shares_so_far (- products_so …
(check-sat)
(pop 1)

; 29 more lines are in the file

Proved SM-04 SIMM ISDA SIMM Methodology, version 2.8+2512, paragraphs 6, 7(d) and 8(d)

The parts of a product class add up to its margin. In a risk class, the parts of the regular buckets add up to the quantity under the root over the root, which is the core margin, and the residual bucket gives its own margin. The parts of the six risk classes, each the margin times the weighted margin over the total, add up to the total, which is the Euler identity of the table between risk classes.

6 checks, decided by 3 solvers. 5 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluate in src/kernel/simm.ts. A bucket that is not residual has the derivative own = 1 over the core margin and the residual bucket has own = 1 over its K, and a risk class has the factor scale = weighted margin over the total of its product class. Steps one and two say that the parts of the buckets, each K² + S × C by SM-03 times own, add up to the core margin and to the residual margin. Step three adds them in a risk class. Step four is the identity of the table PSI_TEXT as exact decimals, and steps five and six are the loop over the six risk classes, which keeps the sum of the parts equal to the inverse of the total times the sum of the products. Division is written as a multiplication by an inverse that has the inverse times the number equal to 1.

Verdicts, 6 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 6
Z3 5.3.3 (native) Reran the emitted file unsat × 6
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 6

Each check asks the solver to break the statement. unsat means it cannot.

Download SM-04.smt2 SHA-256 f4fbde6e3487…792978b7

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • derivative-of-half refuted at goal 1

    Take the derivative of the margin of a risk class as 1 over twice the core margin, so that the parts add up to half of it.

    core
    1
    own
    1/2
    radicand
    1
  • residual-over-the-core refuted at goal 2

    Take the derivative of the residual bucket as 1 over the core margin of the other buckets, and not 1 over its own margin.

    core
    1
    k
    1/2
    own_residual
    1
    q
    1/4
  • margin-without-the-residual refuted at goal 3

    Leave the residual margin out of the margin of the risk class, so that the parts add up to more than the margin.

    core
    0
    delta
    0
    k
    1
    own
    0
    own_residual
    1
    q
    1
    radicand
    0
    scale
    1
  • weighted-from-another-table refuted at goal 4

    Take the weighted margins from a table in which interest rate and equity are correlated at 0.2 and the quantity under the root from the shipped one, so that the terms do not add up to it.

    commodity_margin
    0
    credit_non_qualifying_margin
    0
    credit_qualifying_margin
    0
    equity_margin
    1
    fx_margin
    0
    interest_rate_margin
    1
  • factor-over-the-undiversified-sum refuted at goal 6

    Divide the weighted margins by the sum of the margins and not by the total of the product class, so that the parts add up to less than the total.

    inverse_of_total
    1/2
    parts_so_far
    1/2
    products_so_far
    1
    total
    1
    undiversified
    2
Read the file
; GraphAtlas proof SM-04
; Statement: The parts of a product class add up to its margin. In a risk class, the parts of the regu …
; About: evaluate in src/kernel/simm.ts. A bucket that is not residual has the derivative own = 1 over …
; Source: ISDA SIMM Methodology, version 2.8+2512, paragraphs 6, 7(d) and 8(d)
; Expected: unsat for each of the 6 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun core () Real)
(declare-fun radicand () Real)
(declare-fun own () Real)
(declare-fun k () Real)
(declare-fun q () Real)
(declare-fun own_residual () Real)
(declare-fun delta () Real)
(declare-fun scale () Real)
(declare-fun fx_margin () Real)
(declare-fun commodity_margin () Real)
(declare-fun equity_margin () Real)
(declare-fun credit_non_qualifying_margin () Real)
(declare-fun credit_qualifying_margin () Real)
(declare-fun interest_rate_margin () Real)
(declare-fun margin () Real)
(declare-fun weighted_margin () Real)
(declare-fun products_so_far () Real)
(declare-fun inverse_of_total () Real)
(declare-fun parts_so_far () Real)
(declare-fun total () Real)
(declare-fun undiversified () Real)

; Goal 1, negated
(push 1)
(assert (not (=> (and (> core 0.0) (= (* own core) (to_real 1)) (= radicand (* core core))) (= (* own  …
(check-sat)
(pop 1)
; 30 more lines are in the file

Proved SM-05 SIMM ISDA SIMM Methodology, version 2.8+2512, paragraph 7(d)

For three buckets with the cross-bucket correlation of 3/10, any clipped sums within their K and any ratios of the concentration factors between 0 and 1, the quantity under the root of a risk class is at most the square of the sum of the bucket margins and at least 2/5 of the sum of their squares. So the cross-bucket aggregation never adds to the plain sum, the quantity is never below zero, and the floor in the engine is not reached.

23 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluateRisk in src/kernel/simm.ts, with IR_GAMMA_TEXT as an exact decimal. The quantity under the root is the sum of the K² plus twice the sum, over the three pairs of buckets, of gamma times the ratio of the concentration factors times the product of the two clipped sums. The ratio is between 0 and 1 because it is a smaller over a larger, and each clipped sum is within K. The lemmas bound each product, and the solver adds them up. Four buckets or more are not in the proof, and the tests check that the quantity is never below zero for random books with many.

Verdicts, 23 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 23
Z3 5.3.3 (native) Reran the emitted file unsat × 23
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 23

Each check asks the solver to break the statement. unsat means it cannot.

Download SM-05.smt2 SHA-256 314a103245bd…a5f13468

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • gamma-of-six-tenths refuted at goal 2

    Give two buckets a correlation of 6/10, so that three buckets with opposite clipped sums put less than 2/5 of the sum of the squares under the root.

    k_1
    1
    k_2
    1
    k_3
    1
    ratio_13
    31/32
    ratio_23
    approximately 0.992188
    s_1
    7/8
    s_2
    7/8
    s_3
    -7/8

    1 other variable is 0.

  • gamma-above-one refuted at goal 1

    Give two buckets a correlation of 1.2, which a correlation cannot be, so that the quantity is above the square of the sum.

    k_2
    1
    k_3
    1
    ratio_23
    63/64
    s_2
    31/32
    s_3
    7/8

    4 other variables are 0.

  • ratio-above-one refuted at goal 1

    Let the ratio of the concentration factors be as large as 4, which a smaller over a larger cannot be, so that the cross term is larger than it can be.

    k_2
    1
    k_3
    1
    ratio_23
    63/16
    s_2
    31/32
    s_3
    7/8

    4 other variables are 0.

  • clip-twice-as-wide refuted at goal 1

    Let the clipped sum be as far from zero as twice K, so that the cross term is larger than the margins allow.

    k_2
    1
    k_3
    1
    ratio_23
    63/64
    s_2
    31/16
    s_3
    7/4

    4 other variables are 0.

Read the file
; GraphAtlas proof SM-05
; Statement: For three buckets with the cross-bucket correlation of 3/10, any clipped sums within thei …
; About: evaluateRisk in src/kernel/simm.ts, with IR_GAMMA_TEXT as an exact decimal. The quantity unde …
; Source: ISDA SIMM Methodology, version 2.8+2512, paragraph 7(d)
; Expected: unsat for each of the 23 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun k_1 () Real)
(declare-fun k_2 () Real)
(declare-fun k_3 () Real)
(declare-fun s_1 () Real)
(declare-fun s_2 () Real)
(declare-fun s_3 () Real)
(declare-fun ratio_12 () Real)
(declare-fun ratio_13 () Real)
(declare-fun ratio_23 () Real)
(assert (>= k_1 0.0))
(assert (>= k_2 0.0))
(assert (>= k_3 0.0))
(assert (and (>= s_1 (* (- 1.0) k_1)) (<= s_1 (* 1.0 k_1))))
(assert (and (>= s_2 (* (- 1.0) k_2)) (<= s_2 (* 1.0 k_2))))
(assert (and (>= s_3 (* (- 1.0) k_3)) (<= s_3 (* 1.0 k_3))))
(assert (and (>= ratio_12 0.0) (<= ratio_12 1.0)))
(assert (and (>= ratio_13 0.0) (<= ratio_13 1.0)))
(assert (and (>= ratio_23 0.0) (<= ratio_23 1.0)))

; Lemma 1, negated
(push 1)
(assert (not (<= (* s_1 s_2) (* 1.0 1.0 k_1 k_2))))
(check-sat)
(pop 1)
; Lemma 1 holds, so later checks may use it
(assert (<= (* s_1 s_2) (* 1.0 1.0 k_1 k_2)))

; 171 more lines are in the file

Proved SM-06 SIMM ISDA SIMM Methodology, version 2.8+2512, paragraphs 7(c) and 8(c)

The clipped sum of a bucket is never beyond K and has the sign of the sum. It is the sum inside the clip and K with the sign of the sum outside it. It rises with the sum, and a book with every sign changed has the clipped sum with its sign changed, so that the margin does not depend on which side of the market the book is on.

7 checks, decided by 3 solvers. 4 broken variants refuted. Show the evidence Hide the evidence

What the solver was given evaluateBucket in src/kernel/simm.ts, where S is the larger of minus K and the smaller of the sum of the weighted sensitivities and K. The quantity under the root is the same for a book and for its mirror image, because each K² is a form of the weighted sensitivities, which does not change with their sign, and each product of two clipped sums does not either, so the margin of a book and of its mirror image are the same.

Verdicts, 7 checks

Solver Answer
Z3 5.3.3.0 (WebAssembly) Wrote the file and checked it first unsat × 7
Z3 5.3.3 (native) Reran the emitted file unsat × 7
cvc5 1.4.2 (native, nl-cov) Reran the emitted file unsat × 7

Each check asks the solver to break the statement. unsat means it cannot.

Download SM-06.smt2 SHA-256 87a1b1c69745…f0bc48ec

Broken on purpose

A proof that cannot fail proves nothing. Each variant below changes the rule slightly and must be refuted.

  • clip-twice-as-wide refuted at goal 1

    Clip at twice K and not at K, so that the clipped sum can be beyond K.

    k
    1/2
    sum
    -1
  • lower-bound-of-half refuted at goal 3

    Clip from below at minus half of K, so that a sum between minus K and minus half of K is not left as it is, and a book and its mirror image differ.

    k
    1/4
    sum
    -1/4
  • bounds-the-wrong-way-round refuted at goal 2

    Take the smaller of the upper bound and the larger of the sum and the lower bound, which is the clip with the bounds swapped, so that the clipped sum is minus K whatever the sum.

    k
    1/4
    sum
    1/4
  • no-upper-clip refuted at goal 1

    Leave out the clip from above, so that a sum above K is not clipped.

    k
    approximately 0.000001
    sum
    approximately 1.000001
Read the file
; GraphAtlas proof SM-06
; Statement: The clipped sum of a bucket is never beyond K and has the sign of the sum. It is the sum  …
; About: evaluateBucket in src/kernel/simm.ts, where S is the larger of minus K and the smaller of the …
; Source: ISDA SIMM Methodology, version 2.8+2512, paragraphs 7(c) and 8(c)
; Expected: unsat for each of the 7 checks below.
; Check with any SMT-LIB 2 solver, for example: z3 this-file.smt2

(declare-fun k () Real)
(declare-fun sum () Real)
(declare-fun other_sum () Real)

; Goal 1, negated
(push 1)
(assert (not (let ((a!1 (ite (>= (- k) (ite (<= sum k) sum k)) (- k) (ite (<= sum k) sum k)))) (=> (>= …
(check-sat)
(pop 1)

; Goal 2, negated
(push 1)
(assert (not (let ((a!1 (ite (>= (- k) (ite (<= sum k) sum k)) (- k) (ite (<= sum k) sum k)))) (=> (>= …
(check-sat)
(pop 1)

; Goal 3, negated
(push 1)
(assert (not (let ((a!1 (ite (>= (- k) (ite (<= sum k) sum k)) (- k) (ite (<= sum k) sum k)))) (=> (an …
(check-sat)
(pop 1)

; Goal 4, negated
(push 1)
(assert (not (let ((a!1 (ite (>= (- k) (ite (<= sum k) sum k)) (- k) (ite (<= sum k) sum k)))) (=> (an …
(check-sat)
(pop 1)
; 18 more lines are in the file

Sources

Compared with the text

A rule is only as good as its reading of the source. Here is each document we read, the edition, the passages, when, and what we did not check.

  1. Read and matched

    Set by
    Basel Committee on Banking Supervision
    Edition
    January 2019 text, standard d457
    Checked

    Basel Framework, MAR21: Standardised approach, sensitivities-based method

    Passages
    MAR21.4 (3) to (5), MAR21.6, MAR21.7, MAR21.42 and Table 1, MAR21.46 and Table 2 with footnote 13, MAR21.50
    What we did
    Compared the GIRR delta risk weights, the correlation formula and every entry of the published correlation table with the engine, and reproduced the worked example in the footnote. Followed the aggregation rule, including the floor at zero and the clipped fallback.
    Not checked
    Later amendments and consolidations. The other risk classes, vega, curvature, the default risk charge and the residual risk add-on.
  2. Read and matched

    Set by
    European Parliament and Council
    Edition
    As made, 2009
    Checked

    Directive 2009/138/EC, Solvency II

    Passages
    Articles 103, 104, 105, 107 and 108, and Annex IV point 1
    What we did
    Compared the basic SCR correlation matrix with Annex IV, and the way modules combine into the basic SCR, operational risk and the loss-absorbing adjustment with Articles 103 to 108.
    Not checked
    Amendments after the text as made. Delegated Regulation (EU) 2015/35, which sets the calibration of each module.
  3. Read and matched

    Set by
    European Commission
    Edition
    As made, 2016
    Checked

    Commission Delegated Regulation (EU) 2017/653, PRIIPs key information documents

    Passages
    Annex II, Part 1, points 2 and 11 to 13: the class limits, the return of a period, the Cornish-Fisher expansion and the value at risk equivalent volatility
    What we did
    Compared the class limits and the value at risk equivalent formula with the engine. Found a class 7 boundary that the first draft had on the wrong side, and fixed it.
    Not checked
    Amendments after the text as made. The performance scenarios, the costs and the summary risk indicator for products with a credit risk measure.
    Statements
    PRIIPs PR-01PR-02PR-03
  4. Read and matched

    Set by
    National Institute of Standards and Technology
    Edition
    January 2018
    Checked

    NIST Special Publication 800-90B, Recommendation for the entropy sources used for random bit generation

    Passages
    Sections 3.1.1, 4.2, 4.3, 4.4, 4.4.1, 4.4.2, 6.1, 6.2 and 6.3.1, and Table 2
    What we did
    Reproduced the repetition count cutoff, every entry of the adaptive proportion cutoff table and the worked most common value estimate. Checked the cutoffs against exact integer arithmetic for whole bit claims of one to eight bits. They agree except at an exact tie with the alarm rate, where rounding can put a cutoff one above. Followed the way each test counts, the window sizes, the alarm rate that the text uses and the length of the start-up test. The worked example prints its upper bound as 0.6895 and then as 0.6822. The estimate it prints, 0.5363, follows from 0.6895, and so does the engine. Read what the text says the continuous tests are for, and how it takes the smallest of several estimators, for the essay on a counter that passes the health tests.
    Not checked
    Later revisions. The other estimators in section 6.3, the restart tests and the conditioning component.
  5. Read and matched

    Set by
    European Commission, in the copy that legislation.gov.uk keeps
    Edition
    As made, 1 June 2017. Later amendments were not read.
    Checked

    Commission Regulation (EU) 2017/1151, Annex XXI, the Worldwide harmonised Light vehicles Test Procedure

    Passages
    Sub-Annex 1: paragraphs 3.3.2 and 3.4 and Tables A1/7, A1/9, A1/11, A1/12 and A1/13. Sub-Annex 4: paragraph 4.2.2.1 and Table A4/1. Sub-Annex 6: paragraph 1.2.3.2. Sub-Annex 7: paragraphs 3.2.3.2.2.4, 3.2.3.2.3, 3.2.3.2.4 and 5, and Table A7/1.
    What we did
    Took the speed trace of the class 3b cycle from its four tables with a script and reproduced every checksum of Table A1/13. Encoded the energy demand of paragraph 5, the road load of an individual vehicle with the least squares refit of vehicle L, the interpolation of paragraph 3.2.3.2.4, the class values for C1 tyres, the CO2 range and its extension of 3 g/km. The extension ends "valid only within the absolute boundaries of the interpolation range". The engine reads that as a limit on the length of the extended line. That reading is ours. The regulation has no worked example of the whole method to compare.
    Not checked
    Later amendments. Vehicles of other classes, hybrid and electric vehicles, road load matrix families, vehicle M, and the measurement of road load itself. The coefficients and the CO2 of the illustrative family come from no test.
  6. Read and matched

    Set by
    National Institute of Standards and Technology
    Edition
    Published 13 August 2024
    Checked

    FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard

    Passages
    Algorithms 13, 14, 16 and 17, and Tables 2 and 3
    What we did
    Derived the length of the encapsulation key, the decapsulation key, the ciphertext and the shared secret of each of the three parameter sets from k, du and dv, as the algorithms write them, and compared each with Table 3. Compared the parameters with Table 2.
    Not checked
    The algorithms themselves. Nothing here encapsulates or decapsulates, so no test vector was run. Errata and revisions after the text of August 2024.
    Statements
    PQC PQ-05PQ-09
  7. Read and matched

    Set by
    National Institute of Standards and Technology
    Edition
    Published 13 August 2024
    Checked

    FIPS 204, Module-Lattice-Based Digital Signature Standard

    Passages
    Algorithms 22, 24 and 26, and Tables 1 and 2
    What we did
    Derived the length of the public key, the private key and the signature of each of the three parameter sets from k, l, eta, d, lambda, gamma1 and omega, with bitlen as the standard defines it, and compared each with Table 2. Compared the parameters with Table 1.
    Not checked
    The algorithms themselves. Nothing here signs or verifies. The pre-hash variant, which has the same sizes. Errata and revisions after the text of August 2024.
    Statements
    PQC PQ-05PQ-09
  8. Read and matched

    Set by
    National Institute of Standards and Technology
    Edition
    Published 13 August 2024
    Checked

    FIPS 205, Stateless Hash-Based Digital Signature Standard

    Passages
    Equations 5.1 to 5.4, section 3.1 on key checks, Algorithm 20, and Table 2 of section 11
    What we did
    Derived the length of a signature, from n, h, d, a and k and the WOTS+ length of the equations, and the length of a public key and a private key, for each of the six rows of Table 2, and compared the public key and signature sizes with the table. Compared the parameters with the table. Checked the WOTS+ length against repeated multiplication for every n from 1 to 64 and every Winternitz parameter from 1 to 8.
    Not checked
    The algorithms themselves. Nothing here signs or verifies. The SHAKE sets, which share each row of the table with the SHA2 set of the same name and are not listed apart. The pre-hash variant. Errata and revisions after the text of August 2024.
    Statements
    PQC PQ-05PQ-09
  9. Read and matched

    Set by
    Internet Engineering Task Force
    Edition
    August 2026
    Checked

    RFC 10024, Post-Quantum Traditional (PQ/T) Hybrid Key Agreement Mechanisms for TLS 1.3

    Passages
    Sections 4.1 to 4.3, on the client share, the server share and the shared secret
    What we did
    Derived both shares of each of the three hybrid groups from the size of the curve value and the size of the ML-KEM key or ciphertext, and compared them with the sizes that the text writes: 1216 and 1120 bytes, 1249 and 1153, and 1665 and 1665.
    Not checked
    How the two secrets are joined, what the key schedule does with them, the security considerations and the registry entries. The engine needs only the sizes.
    Statements
    PQC PQ-05PQ-09
  10. Read and matched

    Set by
    National Institute of Standards and Technology
    Edition
    Final, October 2026
    Checked

    NIST IR 8547, Transition to Post-Quantum Cryptography Standards

    Passages
    Section 3 on Mosca’s theorem, the opening of section 4 on the dates for the most sensitive systems, Tables 2 and 4 on the quantum-vulnerable algorithms, and section 4.1.3 on the symmetric ones
    What we did
    Took the inequality X + Y > Z, the end of 2030 for key establishment and of 2031 for signatures that the report gives for the most sensitive systems, and the deprecation after 2030 and disallowance after 2035, and compared each with the engine. Checked that every public-key family of Tables 2 and 4 is marked as broken by a quantum computer, and that no symmetric algorithm or hash function is.
    Not checked
    The Executive Order and the OMB memorandum that the report cites for the dates of 2030 and 2031, of which only what NIST says they require was read. The use cases of section 3.1, and the application-specific guidance. Revisions after October 2026.
    Statements
    PQC PQ-01PQ-06PQ-07
  11. Read and matched

    Set by
    NIS Cooperation Group, PQC workstream, as published by the European Commission
    Edition
    Version 1.1, 11 June 2025
    Checked

    A Coordinated Implementation Roadmap for the Transition to Post-Quantum Cryptography, Part 1

    Passages
    Sections 4.1 and 4.2 on the timeline and its milestones, and section 5 on estimating the quantum risk
    What we did
    Compared the end of 2030 for high-risk use cases and the end of 2035 for the rest with the engine. Compared the four rules of section 5, with their thresholds of ten years of confidentiality and of eight years of migration, at both sides of each boundary.
    Not checked
    Anything outside Part 1. The steps for Member States in sections 6 and 7. The roadmap is written for Member States and calls its classification very rough, so applying its dates to the uses of one organisation is our reading and not the roadmap’s.
    Statements
    PQC PQ-02PQ-06
  12. Read and matched

    Set by
    National Cyber Security Centre
    Edition
    The guidance page as it stood on 30 October 2026
    Checked

    Timelines for migration to post-quantum cryptography

    Passages
    The key milestones of the executive summary, and the section Timelines for PQC migration
    What we did
    Compared the end of 2031, for the early and highest-priority migration, and the end of 2035, for all systems, with the engine.
    Not checked
    The rest of the page, with its sector guidance and its notes on how mature the technology is. The NCSC does not say which systems are highest priority, so the engine treats a use of high impact as one. That is our reading.
    Statements
    PQC PQ-06
  13. Read and matched

    Set by
    U.S. Environmental Protection Agency
    Edition
    The Code of Federal Regulations as the Legal Information Institute printed it on 30 October 2026
    Checked

    40 CFR Part 50, National Primary and Secondary Ambient Air Quality Standards

    Passages
    Sections 50.6, 50.17 and 50.20 for the levels. Appendix K, sections 1.0, 2.1, 3.1 and 3.2 with Examples 1 to 3. Appendix N, sections 3.0, 4.3, 4.4 and 4.5 with Table 1. Appendix T, sections 2 and 4.1 with Table 1.
    What we did
    Compared the four levels and their forms with the engine. Compared the two rank tables, the cutting off of hourly and daily values, the rounding of a design value, the annual mean of quarterly means and the counting of PM10 exceedances with the engine. Reproduced the three worked examples of Appendix K, including the ties that they round up.
    Not checked
    The tests of data completeness in each appendix, the treatment of exceptional events, the choice of monitors, the secondary standards and the other pollutants. Revisions after 30 October 2026.
  14. Read and matched

    Set by
    U.S. Environmental Protection Agency
    Edition
    The revision of 29 November 2024 (89 FR 95034). The text of the Legal Information Institute on 30 October 2026 has the same words in the passages read.
    Checked

    Guideline on Air Quality Models, 40 CFR Part 51, Appendix W

    Passages
    Sections 9.1 (d) and 9.2.2 (a), (b) and (c)
    What we did
    Compared the way a modelled value is added to a background and set against the level, with no rounding of the modelled value, with the engine. Compared the sentence that the three years of a monitor design value do not set the years of a modelled record.
    Not checked
    The modelling guidance on the EPA SCRAM site, to which section 9.2.2 sends the reader for how to combine modelled and background values for each form. Averaging all five modelled years is our reading of section 9.1 (d), and not a sentence of the Appendix. The preferred model, which the engine does not contain.
    Statements
    AERMOD AE-19AE-20
  15. Read and matched

    Set by
    U.S. Department of Energy, Technical Information Center
    Edition
    DOE/TIC-11223, 1982
    Checked

    Handbook on Atmospheric Diffusion, by Hanna, Briggs and Hosker

    Passages
    Table 4.1, the key to the stability classes. Table 4.5, the open-country formulas of Briggs. Table 4.6 and equation 4.9, the wind profile. Equation 4.1, the concentration at the ground. Equations 2.19 and 2.25, the final rise.
    What we did
    Compared every coefficient of the open-country rows, the powers of the wind profile, the key to the classes and the two limits of the rise with the engine. Worked equation 4.1 and the maximum in every class again in a separate program, and set its numbers beside the engine, which agrees to at least eleven digits.
    Not checked
    The formulas for towns, for terrain and for building downwash. The temperature gradient of 0.02 kelvin per metre that the engine uses for class E, which is the usual textbook figure and was not looked up. Work after 1982 that practice has taken up since.
  16. Read and matched

    Set by
    U.S. Environmental Protection Agency, Office of State Air Partnerships
    Edition
    EPA-454/B-26-003, July 2026, for AERMOD version 26135
    Checked

    AERMOD Model Formulation

    Passages
    Section 5.6.1 and equation 91, the rise of the direct plume. Section 5.5.2 and equation 88, the spread that the rise adds.
    What we did
    Compared the form of the rise, with its entrainment parameter of 0.6 and its momentum and buoyancy fluxes, with the engine. Read equation 88, which is 0.4 times the rise over the square root of 2, and found that the engine uses the rise over 3.5 from the SCREEN3 guide, which is about one per cent more. The engine keeps the SCREEN3 form and the page says so.
    Not checked
    Everything else in the document. AERMOD scales its plume by the boundary layer, splits a convective plume in three, and has terrain and building downwash. None of that is in the engine. The product runs the EPA program for it.
    Statements
    AERMOD AE-08
  17. Read and matched

    Set by
    U.S. Environmental Protection Agency, Office of Air Quality Planning and Standards
    Edition
    EPA-454/B-95-004, September 1995
    Checked

    SCREEN3 Model User’s Guide

    Passages
    Equations 5, 7 and 8, the fluxes and the spread that the rise adds, and the potential temperature gradient of 0.035 kelvin per metre for class F
    What we did
    Compared the buoyancy and momentum fluxes, the rise divided by 3.5 as the spread that rise adds, and the gradient for class F with the engine.
    Not checked
    The screening procedure itself, which is not in the engine. The gradient for class E, which the guide does not give.
    Statements
    AERMOD AE-08AE-10
  18. Read and matched

    Set by
    The authors of the ChainLadder package, on the Comprehensive R Archive Network
    Edition
    The version of 18 February 2026
    Checked

    ChainLadder: Claims reserving with R, the vignette of the ChainLadder package

    Passages
    The sections on the basic idea of the chain ladder and on the Mack chain ladder, which print the RAA triangle with its nine development factors, its full square and the table by origin year with the totals. The multivariate section, which prints the triangle of Taylor and Ashe with its latest amount, ultimate and reserve for each origin year.
    What we did
    Compared the nine development factors, the full square to the unit, and the ultimate and the reserve of each origin year of the RAA triangle with the engine. Compared the standard error of Mack for each origin year to the tenth and for the whole reserve to the hundredth, which is 26,909.01, next to the ultimate of 213,122.23 and the reserve of 52,135.23. Compared the latest amount, ultimate and reserve of each origin year of Taylor and Ashe, and the three totals, to the unit.
    Not checked
    The paper of Mack (1993), which the proofs cite for the form of the formula, was not opened. What was compared is what the vignette prints, which is the formula of the paper as the package applies it with its option for the last variance that follows Mack. The vignette prints no standard error of Mack for Taylor and Ashe, so none is claimed for it. The tail factor, the choice of averages and weights, the methods other than Mack, and the other triangles of the vignette are not in the engine.
  19. Read and matched

    Set by
    European Insurance and Occupational Pensions Authority
    Edition
    EIOPA-BoS-25-471, October 2025
    Checked

    RFR Technical Documentation: the methodology to derive EIOPA’s risk-free interest rate term structures

    Passages
    Section 9 on the Smith-Wilson extrapolation, with paragraphs 9.4 to 9.14 on the fit and on the search for the convergence parameter. Annex D, the numerical illustration on pages 119 to 121 with its cash flow matrix, the vector Q b and Table 29.
    What we did
    Compared the form of the Wilson function, the system that fixes the curve, the search for the lowest convergence parameter of six decimals that brings the forward rate within one basis point of the ultimate rate at the convergence point, and the floor of 0.05. Reproduced the illustration from its twenty swap rates, with the vector Q b to three decimals and all 242 numbers of Table 29 to the fifth decimal. Found that the table was made with the root of the gap, 0.12376048, which the page prints as 0.123760, and that the rule of six decimals gives 0.123761. The engine follows the rule and says so.
    Not checked
    The rest of the document, among them the rules for choosing the instruments and the last liquid point, the credit risk adjustment, the volatility adjustment, the matching adjustment and the symmetric adjustment. The engine builds a curve from the rates that it is given and does not read what EIOPA publishes. This edition is replaced by the one of May 2026 from 30 January 2027.
  20. Read and matched

    Set by
    European Insurance and Occupational Pensions Authority
    Edition
    EIOPA-BoS-26/198, May 2026, 115 pages
    Checked

    RFR Technical Documentation: the methodology to derive EIOPA’s risk-free interest rate term structures

    Passages
    Paragraph 8.1.5 and Table 4 on the convergence parameter and its phasing in. Paragraphs 8.5.5 to 8.5.8 on the forward rate and the zero rate beyond the first smoothing point. Annex C, paragraphs C.2.2, C.3.6 and C.4.1, on the ultimate forward rate. Annex D, paragraphs D.1 to D.9, on the bootstrapping of swap rates and of zero coupon rates.
    What we did
    Compared the weight B(a, h) = (1 − e^(−ah)) / (ah), the forward rate as the ultimate rate plus the weight times the way back to the last liquid forward rate, the last liquid forward rate as a weighted mean of the forwards from the first smoothing point, and the zero rate as the mean of the zero rate at the point and the forward, weighted by the years that each covers. Compared the convergence parameters of 11 per cent and, for the Swedish krona, 40 per cent, and every row of the phasing in. Compared the step of 15 basis points of the ultimate forward rate, the rounding of the expected real rate to five basis points in the direction of paragraph C.3.6, and the four buckets of expected inflation. Compared the constant forward assumption and the equations of the bootstrap.
    Not checked
    The rest of the document, and every rate that EIOPA publishes. The engine runs the bootstrap on rates that it is given and gives the same weight to every forward after the first smoothing point unless it is given notionals. It does not choose the first smoothing point from the share of bonds, does not read the inflation targets or the real rates of Annex C from any source, and does not apply the adjustments that the document goes on to describe.
  21. Read and matched

    Set by
    European Parliament and Council
    Edition
    Of 27 November 2024, in the Official Journal of 8 January 2025
    Checked

    Directive (EU) 2025/2, amending the Solvency II Directive

    Passages
    Article 4(1), on the day from which the measures apply. Article 77a of Directive 2009/138/EC as this directive replaces it, paragraphs 1 and 2, on the extrapolation, the floor of 77.5 per cent on the ultimate forward rate and the phasing in.
    What we did
    Compared the day of 30 January 2027, from which the engine applies the closed form, and the floor that the ultimate forward rate must weigh at least 77.5 per cent 40 years past the first smoothing point, which every convergence parameter in force meets. Compared the linear phasing in at the start of each calendar year, which ends on 1 January 2032, with the table that EIOPA prints.
    Not checked
    The rest of the directive. The approval that a supervisor gives to the phasing in, and the disclosure that comes with it. The first smoothing point of any currency but the euro, and the percentage of outstanding bonds that sets it. The delegated regulation that goes with the directive.
  22. Read and matched

    Set by
    Basel Committee on Banking Supervision
    Edition
    July 2020, standard d507, 31 pages
    Checked

    Targeted revisions to the credit valuation adjustment risk framework

    Passages
    The overview of the revisions, on the multiplier and on the cuts in the risk weights. In the annex, MAR50.1, MAR50.40 to MAR50.43, MAR50.45, MAR50.51 to MAR50.65 and Tables 3 to 7.
    What we did
    Compared the factor of 12.5, the multiplier of 1 that replaced 1.25, the capital as the sum of the delta and the vega capital, the weighted and the net weighted sensitivity, the capital of a bucket with the hedging disallowance of 0.01, and the capital of a class with the sum of each bucket held between minus and plus its own capital. Compared every risk weight, every correlation and every correlation across buckets of the interest rate, FX and counterparty credit spread classes, entry by entry, with the paragraphs MAR50.54 to MAR50.65 and Tables 3 to 7. The text is a tracked-changes text, in which the old and the new figure of a change run together, so each changed figure was read as the new one and checked against the cuts that the overview announces, 30 per cent for interest rates and 50 per cent for FX.
    Not checked
    The rest of MAR50, among them the basic approach, the scope of covered transactions, the rules for exposure models and for eligible hedges, and the classes of reference credit spread, equity and commodity risk with the index buckets. The text has no worked example, so no result is compared with a published number. The engine takes sensitivities as they come and does not compute them. Later changes to the consolidated Basel Framework, and the local rules that apply the standard, are not read and may differ.
  23. Read and matched

    Set by
    International Association of Insurance Supervisors
    Edition
    Adopted 5 December 2024, 166 pages. The file that was read is a later upload of the same text, and its text is the same on every page as the file at this address.
    Checked

    Insurance Capital Standard, Level 1 and Level 2 texts

    Passages
    L1-72, L1-84 and L1-141. L2-122, L2-127 to L2-129, L2-143 with Table 6, L2-199, L2-203 with Table 16, L2-329 to L2-334 with Table 33, L2-335 with Table 34, L2-339, and L2-347 to L2-353.
    What we did
    Compared Table 6 for the five life risks, the four catastrophe scenarios as independent, the seven rows of Table 16 and Table 34 for the five categories, entry by entry, with the engine. Compared the factors and exposures of Table 33, the growth threshold of 20 per cent and the order of L1-141, which adds the operational charge after the aggregation. Compared the tax effect, with its default of 80 per cent, its four components, the deduction of 15 per cent from the carry-back, the cap of 15 per cent on the asset, the share of the notional effect by consolidated GAAP insurance liabilities, and half of five years of earnings for component b, which is zero for a projected loss. Compared the limits on Tier 1 Limited, Tier 2 and the basket with its three items, the limits for a mutual, and the move of what is above the limit on Tier 1 Limited to Tier 2. Found that Table 16 is not a correlation matrix as a whole, because its two spread rows are 100 per cent correlated and differ in their correlation with equity and real estate. The engine counts the spread in one row and has an exact certificate for each of the two six by six tables that remain.
    Not checked
    The valuation and the stress behind each charge, which the engine takes as inputs. The credit for management actions, and its cap in L1-84, which the engine does not model. The charge for the non-insurance entities, which is an input. The text does not say which row of Table 16 the larger spread stress uses, so the engine reads the row of the larger stress and takes the larger of the two results when they are equal. That is a reading and not a quotation. The text defines no ICS ratio, so the cover that the plate shows is the product’s own. The eligibility of each instrument as capital, the deductions from Tier 1, and any change after this text.
  24. Read and matched

    Set by
    International Association of Insurance Supervisors
    Edition
    Published 27 June 2025, 36 pages. The IAIS says that it is to be read with the Level 1 and Level 2 texts.
    Checked

    Technical note, Explanatory text and examples on ICS

    Passages
    Section 6.1, the example of the group effective tax rate, and section 6.3, the example of the utilisable tax effect on the insurance capital requirement.
    What we did
    Worked the group effective tax rate of section 6.1 again from three insurance entities at 30, 25 and 20 per cent, with each loss set to zero in its own year and the banking entity left out, and got the 23.03 per cent that the note prints. Worked the tax effect of section 6.3 again for an insurance capital requirement of 10,000 at a rate of 30 per cent with its four tax sub-groups, and got the 340 of carry-back, the 1,215 of future income, the 450 of net deferred tax liability, the 0 of net deferred tax asset and the 2,005 that the note prints. The notional effect of 3,000 and the cap of 2,400 agree too.
    Not checked
    The rest of the note, which has no other example that the engine could be held to. The requirement of 7,995 that is left after the tax effect is the engine’s own subtraction, and the note does not print it. The note takes the capital requirement of 10,000 as given and says nothing of what it is made of, so the plate puts all of it in one mortality charge.
    Statements
    ICS IC-12IC-13
  25. Structure only

    Set by
    International Swaps and Derivatives Association
    Edition
    Version 2.8+2512.2 of 13 May 2026, effective 11 July 2026. The text carries a copyright and patent notice, so no table of it is reproduced here.
    Checked

    ISDA SIMM Methodology, version 2.8 calibrated to December 2025

    Passages
    Paragraphs 5 to 8, on the risk classes, the product classes and the steps of the delta margin. Paragraphs 14 to 19 and the tables of buckets in sections E to H, for the risk factors and how many buckets each class has. Paragraphs 32 and 66 to 69, on the buckets of rates and of FX. Section J, on how the thresholds are given, and paragraph 88, for the shape of the correlation between risk classes.
    What we did
    Compared the steps of the delta margin with the engine. The net sensitivity of each risk factor and its weight. The concentration factor as the larger of one and the root of the exposure over the threshold, where the exposure is the sum over a currency for rates, the sum over an issuer whatever the tenor for credit, and the sensitivity itself for equity, commodity and FX. The margin of a bucket with its cross terms, in which every class but rates scales the correlation of two factors by the smaller concentration factor over the larger. The sum of a bucket cut to the range of its margin. The margin across buckets, in which rates scale the correlation of two currencies in the same way and the residual bucket is added after the root and not aggregated. The margin of a product class over the six risk classes with one table, and the total as the sum of the four. Compared the structure of the risk factors, which is twelve tenors for rates, five vertices for credit, twelve buckets and a residual for qualifying credit and for equity, two and a residual for non-qualifying credit, seventeen buckets for commodity, and one bucket for FX that has no risk factor for the calculation currency. The text prints its numbers, and none of them was compared, because the engine does not carry them.
    Not checked
    Every number of the calibration, which are the risk weights, the correlations, the thresholds and the groups of currencies. ISDA licenses them, the engine has numbers of its own that are illustrative, and every receipt names them as sketch-1. So the margin of the plate is not a SIMM margin and must not be compared with one. Vega, curvature and base correlation risk, which paragraph 5 adds to the delta margin, the add-ons and scales of the Annex, the Schedule, inflation and cross-currency basis risk, the payment currency of a credit spread and the treatment of indexes, funds and ETFs. The engine refuses a line that asks for any of them. The SIMM Governance Framework and its procedures for remediation. Later versions and the calibration of each half year.
  26. Structure only

    Set by
    International Swaps and Derivatives Association
    Edition
    1 February 2017. Later editions exist. The text carries the same copyright and patent notice.
    Checked

    ISDA SIMM Methodology: Risk Data Standards, version 1.36

    Passages
    Section 2.1, on the format of a file and its columns, and sections 2.2 to 2.7, on what each risk type puts in the five keys and in the amount.
    What we did
    Compared the columns that the plate reads, which are the trade, the product class, the risk type, the qualifier, the bucket, Label1, Label2 and AmountUSD, with the file that the standard describes. Compared what each of the six delta risk types puts in them, which is a currency for rates and FX, a representative ISIN for credit and equity, the bucket 1, 2 or 3 of a rate by the volatility of its currency, the tenors of a rate, the vertices of credit and the names of the sub-curves. Compared the units, which are one basis point for a rate or a credit spread and one per cent for an equity, a commodity or an FX rate, and the rule that the qualifier of an FX rate may be the calculation currency.
    Not checked
    The edition of 2017 is the one that could be read. It has eleven equity buckets and sixteen commodity buckets, as the methodology had then, and the engine follows version 2.8 of the methodology, which has twelve and seventeen. The standard puts a tab between columns, and the plate reads commas and semicolons too, which the standard does not say. The risk types that the engine refuses, the rows for the Schedule and for the parameters, the appendices and the worked examples. The standard says that the methodology takes priority over it.
    Statements
    SIMM SM-12

Limits

What this does not show

We would rather you heard this from us.

  • Real numbers, not floating point.

    A proof covers a rule over the real numbers. Computers round. The engines use a fixed set of operations that return the same bits on every platform, and they are tested against the proved rules on generated inputs. That is a test, not a proof.

  • The rule as we wrote it.

    A proof shows the code does what the statement says. It does not show that we read the regulation correctly. That is what the sources above are for, and they cover only the passages listed.

  • The edition we read.

    Amendments after the edition named in the ledger were not checked. The specification feed follows them, and a change that touches a statement is published in the changelog.

  • Solvers can be wrong.

    So two independent solvers rerun every file, and the proofs are small enough to read. If they disagreed, the statement would drop a level.

  • Not yet reviewed by a supervisor.

    The engines, the proofs and the figures on this site are real and can be rerun. No supervisor has reviewed or approved these engines, and a firm that uses one still validates it as it would any model.

Found a mistake? Tell us. A confirmed error in a statement is published in the changelog, with the date.

The next step

Bring us
one book

A scoping call, a sample book and a parallel run on your data. Most teams have the first reconciled number inside two weeks, and a receipt for it on the day.

Book a demo Work out a price