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.
Evidence
proofs/smt2/PR-01.smt2
Verification
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.
Levels
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.
True for every input.
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.
True for the case in hand, with evidence anyone can recheck.
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.
True on every input we tried.
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
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.
True for every input.
A solver or proof assistant checks the statement. You rely on the checker, which is small and public.
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.
proofs/smt2/PR-01.smt2EN-01
The repetition count cutoff is the smallest integer C for which H times (C − 1) reaches the false positive exponent.
proofs/smt2/EN-01.smt2EN-02
The repetition count cutoff never rises when the claimed min-entropy rises.
proofs/smt2/EN-02.smt2WL-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.
proofs/smt2/WL-01.smt2WL-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.
proofs/smt2/WL-02.smt2SI-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.
proofs/smt2/SI-01.smt2PQ-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.
proofs/smt2/PQ-01.smt2PQ-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.
proofs/smt2/PQ-02.smt2PQ-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.
proofs/smt2/PQ-03.smt2AE-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.
proofs/smt2/AE-01.smt2AE-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.
proofs/smt2/AE-02.smt2AE-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.
proofs/smt2/AE-03.smt2AE-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.
proofs/smt2/AE-04.smt2AE-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.
proofs/smt2/AE-05.smt2RS-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.
proofs/smt2/RS-01.smt2RS-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.
proofs/smt2/RS-02.smt2RS-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.
proofs/smt2/RS-03.smt2RS-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.
proofs/smt2/RS-04.smt2RS-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.
proofs/smt2/RS-05.smt2RS-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.
proofs/smt2/RS-06.smt2RS-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.
proofs/smt2/RS-07.smt2RS-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.
proofs/smt2/RS-08.smt2SC-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.
proofs/smt2/SC-01.smt2SC-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.
proofs/smt2/SC-02.smt2SC-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.
proofs/smt2/SC-03.smt2SC-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.
proofs/smt2/SC-04.smt2IC-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.
proofs/smt2/IC-01.smt2IC-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.
proofs/smt2/IC-02.smt2IC-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.
proofs/smt2/IC-03.smt2IC-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.
proofs/smt2/IC-04.smt2IC-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.
proofs/smt2/IC-05.smt2IC-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.
proofs/smt2/IC-06.smt2SM-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.
proofs/smt2/SM-01.smt2SM-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.
proofs/smt2/SM-02.smt2SM-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.
proofs/smt2/SM-03.smt2SM-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.
proofs/smt2/SM-04.smt2SM-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.
proofs/smt2/SM-05.smt2SM-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.
proofs/smt2/SM-06.smt2True 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.
tests/kernel/frtb.test.tssrc/kernel/frtb.tssrc/kernel/rational.tsSI-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.
tests/kernel/exact.test.tssrc/kernel/certify.tsPQ-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.
tests/kernel/pqc.test.tssrc/kernel/pqc.tsAE-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.
tests/kernel/aermod.test.tssrc/kernel/aermod.tsSC-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.
tests/kernel/sacva.test.tssrc/kernel/certify.tssrc/kernel/rational.tsIC-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.
tests/kernel/ics.test.tssrc/kernel/certify.tssrc/kernel/rational.tsSM-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.
tests/kernel/simm.test.tssrc/kernel/certify.tssrc/kernel/rational.tsTrue on every input we tried.
Property tests over generated inputs and published results. You rely on the test inputs and the oracle.
KE-01
exp and ln stay within three units in the last place of the platform library over generated inputs.
tests/kernel/dmath.test.tsKE-02
Changing any single bit of an input number changes the receipt, except that every not-a-number is written as the same one.
tests/kernel/rng-receipt.test.tsKE-03
Node, workerd, Chromium, Firefox and WebKit return identical receipts for every parity fixture.
scripts/parity/run.mjsKE-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.
tests/kernel/dmath.test.tsFR-01
Risk factor shares add up to the capital charge in every correlation scenario, and each matches a numerical derivative of the charge.
tests/kernel/frtb.test.tsFR-02
The capital charge is positively homogeneous of degree one and unchanged when every position flips sign.
tests/kernel/frtb.test.tsFR-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.
tests/kernel/frtb.test.tsFR-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.
tests/kernel/frtb.test.tsFR-06
The capital charge is never negative and equals the largest of the three scenario charges.
tests/kernel/frtb.test.tsSI-03
At every level of the Solvency II trace, the shares of the parts add up to the share of the whole.
tests/kernel/solvency.test.tsSI-04
Every module’s share of the basic SCR is at least zero and at most the module’s own charge.
tests/kernel/solvency.test.tsSI-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.
tests/kernel/solvency.test.tsPR-02
The VEV matches a case worked by hand, rises with negative skew and with fat tails, and tracks annualised volatility for normal returns.
tests/kernel/priips.test.tsPR-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.
tests/kernel/priips.test.tsEN-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.
tests/kernel/entropy.test.tsEN-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.
tests/kernel/entropy.test.tsEN-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.
tests/kernel/entropy.test.tsEN-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.
tests/kernel/entropy.test.tsEN-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.
tests/kernel/entropy.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsWL-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.
tests/kernel/wltp.test.tsPQ-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.
tests/kernel/pqc.test.tsPQ-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.
tests/kernel/pqc.test.tsPQ-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.
tests/kernel/pqc.test.tsPQ-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.
tests/kernel/pqc.test.tsPQ-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.
tests/kernel/pqc.test.tsPQ-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.
tests/kernel/pqc.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsAE-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.
tests/kernel/aermod.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/reserving.test.tsRS-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.
tests/kernel/curve.test.tsRS-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.
tests/kernel/curve.test.tsRS-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.
tests/kernel/curve.test.tsRS-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.
tests/kernel/curve.test.tsRS-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.
tests/kernel/curve.test.tsRS-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.
tests/kernel/curve.test.tsRS-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.
tests/kernel/curve-fit.test.tsRS-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.
tests/kernel/curve-fit.test.tsRS-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.
tests/kernel/curve-fit.test.tsRS-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.
tests/kernel/curve-fit.test.tsRS-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.
tests/kernel/curve-fit.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsRS-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.
tests/kernel/curve-rules.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsscripts/verify/sacva_oracle.pytests/support/sacva-oracle.jsonSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsSC-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.
tests/kernel/sacva.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsscripts/verify/ics_oracle.pytests/support/ics-oracle.jsonIC-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.
tests/kernel/ics.test.tsIC-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.
tests/kernel/ics.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsscripts/verify/simm_oracle.pytests/support/simm-oracle.jsonSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsSM-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.
tests/kernel/simm.test.tsProofs
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.
# 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.
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.
Choose the file you downloaded. Your browser works out its SHA-256, compares it with the one above and looks inside. Nothing is uploaded.
# 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 What the solver was given mrmClass in src/kernel/priips.ts, built from MRM_TABLE with the exact binary value of each limit.
| 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
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.
limits-swapped refuted at goal 6
The 12% and 20% limits swap places, so the limits no longer increase.
; 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
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.
| 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
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.
off-by-one refuted at goal 1
Subtract one from the cutoff.
; 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)
What the solver was given rctCutoff in src/kernel/entropy.ts, for every pair of claims 0 < H1 ≤ H2 ≤ 64.
| 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
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.
; 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)
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.
| 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
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.
scaled-weight refuted at goal 1
Multiply the weight by 1.1, as a unit slip would.
; 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
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.
| 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
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.
; 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)
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.
| 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
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.
negative-correlation refuted at goal 2
Set the market and default correlation to -0.9.
; 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
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.
| 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
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.
a-year-early refuted at goal 2
Start one year before the latest start, which is safe but not the latest.
forgets-migration refuted at goal 1
Leave out the years the migration takes.
forgets-keeping refuted at goal 1
Leave out the years the data must stay secure.
; 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
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.
| 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
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.
keep-threshold-11 refuted at goal 3
Count only eleven years or more of confidentiality as long.
migrate-threshold-7 refuted at goal 2
Count a migration of more than seven years as long.
migrate-threshold-9 refuted at goal 2
Count a migration of more than nine years as long.
every-use-confidential refuted at goal 2
Treat a signature as if it protected confidentiality.
ignores-impact refuted at goal 3
Leave out the test for a high impact.
; 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)
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.
| 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
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.
ignores-own-date refuted at goal 1
Leave out the date the use has on its own.
finish-not-start refuted at goal 2
Compare with the finish of the first dependent, not with its latest start.
first-dependent-only refuted at goal 3
Look at the first dependent only.
; 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
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.
| 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
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.
rounds-down refuted at goal 4
Take the days over 50 rounded down, plus one, so that exactly 50 days has the second rank.
a-gap refuted at goal 1
Leave out the row for ranks of 4, so that 151 to 200 days has no rank.
the-99th-for-the-98th refuted at goal 3
Use the table of the 99th percentile where the 98th is meant.
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.
; 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
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.
| 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
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.
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.
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.
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.
e-and-f-swapped-across refuted at goal 21
Swap the coefficients across the wind of classes E and F.
; 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
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.
| 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
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.
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.
22 other variables are 0.
divides-by-23 refuted at goal 1
Divide the hours by 23 instead of 24.
23 other variables are 0.
; 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
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.
| 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
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.
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.
at-the-level-counts refuted at goal 1
Count a rounded day that equals the level as well as one above it.
compares-unrounded refuted at goal 1
Compare the day with the level without rounding it first, which is how a model is compared.
; 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
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.
| 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
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.
compares-unrounded refuted at goal 1
Compare the mean with the level before rounding it, which is how a model is compared.
; 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
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.
| 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
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.
weights-are-the-later-amounts refuted at goal 1
Weigh each ratio by its later amount, which is a mean of the wrong thing.
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.
sum-of-the-ratios refuted at goal 1
Add the ratios instead of averaging them.
; 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
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.
| 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
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.
oldest-open-year-skipped refuted at goal 1
Leave origin year 2 out of the first calendar year.
last-calendar-year-missing refuted at goal 1
Stop after two calendar years, so the youngest origin year is never paid in full.
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.
; 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
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.
| 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
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.
mean-of-the-two refuted at goal 2
Take the mean of the two estimates.
later-estimate-repeated refuted at goal 2
Repeat the later estimate.
no-guard-for-nothing refuted at goal 1
Divide by the earlier variance without asking whether it is nothing.
; 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
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.
| 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
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.
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.
step-of-thirty refuted at goal 1
Limit the move to 30 basis points.
wrong-direction refuted at goal 2
Move down when the rate before the limit is above, and up when it is below.
jumps-to-the-unlimited-rate refuted at goal 1
Take the rate before the limit whenever it is a step or more away.
; 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
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.
| 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
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.
weight-with-a-sum refuted at goal 3
Divide by a plus h where the formula has a times h.
weight-of-the-exponential refuted at goal 2
Take the exponential itself over a times h, which is the weight of the wrong end.
; 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
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.
| 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
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.
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.
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.
; 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
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.
| 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
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.
divides-by-the-horizon refuted at goal 1
Divide by the horizon alone, so that the two weights add up to more than one.
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.
; 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
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.
| 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
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.
direction-swapped refuted at goal 3
Round down when the rate is below the year before, and up when it is not.
to-the-nearest refuted at goal 3
Round to the nearest five basis points, a half upwards.
ten-basis-points refuted at goal 2
Round to a whole number of ten basis points, in the right direction.
; 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
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)².
| 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
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.
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.
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.
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.
; 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)
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.
| 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
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.
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.
edge-from-the-wrong-sum refuted at goal 2
Take the edge as 2 × Q / (Q + N), with no disallowance in it.
; 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
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.
| 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
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.
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.
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.
10 other variables are 0.
; 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)
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.
| 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
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.
correlation-above-one refuted at goal 1
Use a correlation of 1.2 between the buckets, which a correlation cannot be.
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.
; 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
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.
| 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
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.
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.
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.
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.
; 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
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.
| 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
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.
no-correlation refuted at goal 1
Give mortality and longevity a correlation of zero, so that the form is the sum of the squares.
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.
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².
; 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
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.
| 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
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.
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.
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.
9 other variables are 0.
; 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
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.
| 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
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.
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.
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.
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.
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.
; 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
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.
| 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
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.
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.
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.
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.
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.
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.
9 other variables are 0.
; 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
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.
| 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
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.
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.
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.
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.
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.
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.
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.
7 other variables are 0.
; 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
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.
| 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
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.
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.
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.
; 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
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.
| 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
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.
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.
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.
floor-of-two refuted at goal 2
Floor the factor at two, so that exposures below the threshold are concentrated.
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.
; 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
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.
| 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
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.
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.
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.
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-term-twice-inside refuted at goal 1
Count the cross term twice for each factor when the sum is inside the clip.
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.
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.
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.
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.
; 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
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.
| 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
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.
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.
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.
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.
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.
; 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
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.
| 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
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.
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.
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.
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.
4 other variables are 0.
; 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
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.
| 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
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.
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.
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.
no-upper-clip refuted at goal 1
Leave out the clip from above, so that a sum above K is not clipped.
; 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
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.
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Read and matched
Structure only
Structure only
Limits
We would rather you heard this from us.
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.
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.
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.
So two independent solvers rerun every file, and the proofs are small enough to read. If they disagreed, the statement would drop a level.
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
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.