What is taught wrongly

The dial that has no setting

The generator has one parameter. The real version history's run count asks it for 2.3% and its phrase count asks for 3.2% — and the reason is not that the dial is badly calibrated. Real edits average 7.3 characters a block and generated ones average 1.04.

A model with one parameter, fitted to one collection, using two measurements. If the model were right there would be a setting where both agree.

The dial has no settingThe generator has one parameter: what fraction of each copy's characters are replaced. The two curves are what it produces; the two horizontal lines are what the real version history actually is. If the generator were a model of a version history there would be one setting where both curves meet their line. The run count asks for 2.32% and the phrase count asks for 3.24% — 1.40x apart, and neither setting reproduces the other measure. Both axes are logarithmic.1.0%10.0%0.11fraction of characters changedper characterthe real runsthe real phrasesgenerated runsgenerated phrasesten revisions of one file · 24,580 characters2.32% against 3.24%
Fig. 1 The generator’s two measures as its dial turns, with the real version history’s own values as horizontal lines. Where each curve crosses its line is what that measure asks the dial for.

The fit

The generator makes k copies of a base text and replaces a fraction of each copy’s characters. Sweep that fraction from zero to sixty-four per cent and measure two things at each setting: runs of the transform per character, and phrases of the parse per character.

The real version history sits at 0.126 runs a character and 0.0668 phrases a character.

The run count asks for 2.32%. The phrase count asks for 3.24%. A factor of 1.40 apart, and neither setting reproduces the other measure.

That is a small discrepancy by the standards of model fitting and it is not nothing: at 2.32% the generated collection has 0.126 runs a character and 0.052 phrases, which is 22% short on the second; at 3.24% it has 0.153 runs, which is 21% over on the first.

The two settings are close enough that a reader might reasonably ask whether the difference is noise. It is not: both curves are monotone and smooth over the sweep, both are computed exactly rather than sampled, and the same measurement at nearly three times the corpus size gives the same two settings to within a few hundredths of a per cent. The disagreement is a property of the model.

Two measures of repetition, on real text and on the model of itRuns of the transform and phrases of the parse, both divided by the length of the text so that three parts of different sizes can sit on one plate. The version history is the only part that is repetitive in the sense this field means: 0.126 runs a character against 0.491 for twelve unrelated essays. The generated collection at the setting used throughout this collection lands near the version history on runs and well below it on phrases, and nowhere near either of the other two — which is the whole question this strand was written to ask, drawn once before it is answered properly.twelve essays — runs0.491generated, matched0.124twelve essays — phrases0.213generated, matched0.051eight source modules — runs0.461generated, matched0.132eight source modules — phrases0.210generated, matched0.054ten revisions of one file — runs0.126generated, matched0.129ten revisions of one file — phrases0.067generated, matched0.053per character24,576 characters a partdivergence 0.023
Fig. 2 The generated collection at the setting the run count asks for. It is close on runs and short on phrases, which is the disagreement seen as a pair of bars rather than as a crossing.

Why two measures rather than one

A one-parameter model fitted with one measurement always fits. That is not a property of the model; it is arithmetic. Any monotone curve crosses any horizontal line somewhere, and the crossing is the setting.

So a fit is only a test when there are more measurements than parameters, and this collection happens to have exactly the right two. The collection decides which index is small is the essay about them: runs of the Burrows-Wheeler transform and phrases of the Lempel-Ziv parse are both measures of repetition, they are not the same measure, and a text can be small on one and large on the other.

Two measures, one dial, and a 40% disagreement is what a one-parameter model looks like when it is asked to do two things. A limit is not a prediction is the general form of the same caution.

Why these two measures disagree at all

It is worth understanding what the two are sensitive to, because the direction of the disagreement is informative.

The run count of a transform counts contexts that repeat. A scattered substitution breaks a context wherever it lands, so scattering k substitutions breaks about k contexts — the damage is proportional to the number of edits and nearly independent of where they are.

The phrase count of a parse counts places where copying has to restart. A scattered substitution forces a restart at each edit; a block of substitutions forces one restart for the whole block. So the damage is proportional to the number of edit sites, not to the number of edited characters.

The real collection has 20% of positions differing in blocks of 7.3, which is about 2.8% of positions as sites. The generated one at 2% has 2% of positions differing in blocks of 1, which is 2% as sites.

The two measures disagree because one counts characters and the other counts blocks, and the model has no blocks.

Where the model is wrong

The disagreement says the model is wrong; it does not say how. The measurement that says how is about where the edits are rather than how many there are.

Take consecutive documents and compare them position by position over their common length. Count the positions that differ, and count the maximal runs of differing positions. A scattered substitution is a run of one, by definition; a rewritten paragraph is one long run.

positions differing characters a run length change
real revisions 20.3% 7.31 333 characters
generated, 2% dial 3.2% 1.04 none

The generated collection’s edits are runs of 1.04 characters, which is what “replace a fraction of the characters at random” means. Real edits are runs of 7.31.

Where the changes are, not how many of them there areEach row is one consecutive pair of documents; the bar is the fraction of positions that differ over their common length, and the number beside it is how many characters a run of differing positions holds. Real revisions average 7.3 characters a block and generated ones 1.04 — a scattered substitution is a block of one, by definition. Several real pairs differ in nothing at all over their common prefix and simply have 333 characters appended, which the generator never does: its documents are all one length. And the large rates are an insertion seen positionally — everything after an inserted paragraph is at the wrong offset, so a comparison that only knows about substitutions reports most of the file as changed, which is exactly the model the dial implements.119.3 a block217.3 a block3nothing changed415.1 a block5nothing changed6nothing changed7nothing changed8nothing changed914.1 a blockfraction of positions differing · the thin bar is the generated pairreal 7.3 characters a block · generated 1.04ten revisions of one file · 10 documents7.05x apart
Fig. 3 Every consecutive pair of revisions, with the fraction of positions differing and the length of a run of differences beside it.

The five pairs that changed nothing

The table’s averages hide the shape, and the shape is the finding.

Of the nine consecutive pairs in the version history, five differ in nothing at all over their common prefix. The file simply grew — a few hundred characters appended — and everything that was there before is byte for byte identical.

The other four differ in 9%, 32%, 61% and 80% of their positions.

So a real version history is not “a few per cent changed each time”. It is nothing changed, nothing changed, a rewrite, nothing changed, nothing changed, a rewrite — and the generator has no setting that produces either half of that, because it changes exactly the same small fraction every time.

The dial is the wrong shape, not the wrong value. That is why no setting works, and it is the answer this essay is for.

The 80% that is an insertion

One of those four numbers deserves unpicking, because it is an artefact of the comparison rather than of the data — and the artefact is itself the point.

A positional comparison can only see substitutions. Insert a paragraph into the middle of a file and every character after it is at a different offset, so a position-by-position comparison reports the whole tail as changed. That is what 80% is.

The generator only substitutes, so a positional comparison is exactly right for it and hopelessly wrong for the real thing. The measurement that says the model is wrong is a measurement the model’s own assumptions make.

That is worth stating plainly because it cuts both ways: the 20.3% in the table above is an over-count of how much real text changed, and the 7.31 characters a block is an under-count of how localised real edits are. Both errors run in the direction that makes the model look better.

Where the changes are, not how many of them there areEach row is one consecutive pair of documents; the bar is the fraction of positions that differ over their common length, and the number beside it is how many characters a run of differing positions holds. Real revisions average 16.5 characters a block and generated ones 1.04 — a scattered substitution is a block of one, by definition. Several real pairs differ in nothing at all over their common prefix and simply have 879 characters appended, which the generator never does: its documents are all one length. And the large rates are an insertion seen positionally — everything after an inserted paragraph is at the wrong offset, so a comparison that only knows about substitutions reports most of the file as changed, which is exactly the model the dial implements.115.3 a block214.4 a block316.3 a block415.6 a block515.8 a block616.6 a block721.7 a blockfraction of positions differing · the thin bar is the generated pairreal 16.5 characters a block · generated 1.04eight source modules · 8 documents16x apart
Fig. 4 The same measurement on eight unrelated source modules, where nearly everything differs and the blocks are still long. Long blocks are a property of text, not only of version histories.

The same failure, in a field that has met it

This is not the first time in this collection that a one-parameter model has been asked to stand in for something with structure.

Sized for a rate that does not hold still records a summary sized for a stream whose arrival rate was assumed constant and was not. The formula everybody sizes filters with records a sizing formula whose assumption about independence is not met by the hash families anybody uses. And the boundary that hides the burst records a window model that reports a periodic stream as an even one.

In every case the model is a good instrument and a bad sample, and in every case the failure appears only when somebody measures the thing the model was standing in for. That is what this strand is: the measurement, taken late, on the one input every structure here has been fed.

What the model gets right

It is worth being fair, because the disagreement is 40% and not a factor of ten.

The generated collection at 2% lands within 12% of the real version history on runs per character. On phrases it is 22% low. Those are the right order of magnitude, and no other setting of any parameter in this collection would have got that close by accident.

More importantly, it lands in the right regime. The version history is the repetitive case and the generator at a few per cent produces the repetitive case; the two agree that a compressed index on such a collection is several times smaller than the text, and they agree by how much to within a quarter.

Every structural conclusion in five strands is about that regime, and none of them turns on a quarter.

Two measures of repetition, on real text and on the model of itRuns of the transform and phrases of the parse, both divided by the length of the text so that three parts of different sizes can sit on one plate. The version history is the only part that is repetitive in the sense this field means: 0.126 runs a character against 0.491 for twelve unrelated essays. The generated collection at the setting used throughout this collection lands near the version history on runs and well below it on phrases, and nowhere near either of the other two — which is the whole question this strand was written to ask, drawn once before it is answered properly.twelve essays — runs0.491generated, matched0.109twelve essays — phrases0.213generated, matched0.046eight source modules — runs0.461generated, matched0.122eight source modules — phrases0.210generated, matched0.050ten revisions of one file — runs0.126generated, matched0.113ten revisions of one file — phrases0.067generated, matched0.047per character24,576 characters a partdivergence 0.02
Fig. 5 The generated collection beside all three real parts. It sits near the version history and nowhere near the other two, which is the model working.

The measurement that is cheap and was not taken

The edit-shape measurement is one pass over each pair of documents, comparing positions and counting runs. It costs nothing, it needs no structure, and it would have said the model was the wrong shape without any of the fitting above.

That is the third time in these five strands that a cheap measurement would have settled a question that was instead settled by building something. A break-even calculation would have said a run coder loses on a grid; a depth histogram would have said which caps are live; and a run-length comparison of two documents would have said that a substitution model does not describe an edit.

The pattern is worth naming: when a claim is about the shape of some data, measure the shape. It is nearly always one pass, and it nearly always answers the question the expensive apparatus was going to answer approximately.

Where the changes are, not how many of them there areEach row is one consecutive pair of documents; the bar is the fraction of positions that differ over their common length, and the number beside it is how many characters a run of differing positions holds. Real revisions average 15.5 characters a block and generated ones 1.04 — a scattered substitution is a block of one, by definition. Several real pairs differ in nothing at all over their common prefix and simply have 253 characters appended, which the generator never does: its documents are all one length. And the large rates are an insertion seen positionally — everything after an inserted paragraph is at the wrong offset, so a comparison that only knows about substitutions reports most of the file as changed, which is exactly the model the dial implements.117.8 a block215.5 a block314.7 a block416.8 a block515.2 a block615.4 a block713.4 a block814.6 a block913.8 a block1018.4 a block1114.4 a blockfraction of positions differing · the thin bar is the generated pairreal 15.5 characters a block · generated 1.04twelve essays · 12 documents15x apart
Fig. 6 The same one-pass measurement on twelve unrelated essays, where the comparison is meaningless in a way the numbers make obvious.

What a model with two parameters would need

The obvious repair is to give the generator an edit length as well as an edit rate: replace runs of L characters at a rate chosen so the total fraction matches. That is two parameters and it would fit both measures, because two parameters fitted with two measurements always fit.

Which is the problem. A two-parameter model fitted with two measurements is not tested by the fit, and the honest way to test it would be a third measure — the entropy at some order, or the depth profile of the parse, or the distribution of match lengths.

The value of the disagreement here is that it exists, and it exists because the model has fewer parameters than there are measurements. A better-fitting model would be less informative unless it were tested harder.

That is the general shape of the model has parameters, and it is the reason this essay does not end by proposing a better generator.

Free parameters, not parameters

The argument against a two-parameter generator is that two parameters fitted with two measurements always fit, so the fit tests nothing. That is true and it is not an argument against the model — it is an argument against fitting it, and the distinction is worth separating because this essay has already produced the thing that removes the objection.

A fit tests a model when there are more measurements than free parameters. A parameter measured directly is not free. And the edit-shape measurement above measures one of the two: real edits arrive in blocks averaging 7.31 characters, which is exactly the length parameter a two-parameter generator would want, obtained in one pass over consecutive documents with no structure and no fitting.

So the honest version of the repair is not add a parameter and fit both. It is set the block length from the measurement and fit only the rate — one free parameter, two measurements, and the run count and the phrase count are still free to disagree. If they then agree, the model has passed a test it could have failed; if they disagree, the disagreement is again informative, and it is informative about something other than the edits being scattered, since the edits are no longer scattered.

That is a better use of the same two measures than either the current model or the fitted two-parameter one, and it costs a pass that has already been written.

It also states what would have to be measured for a third parameter, and so on: each new parameter needs its own direct measurement, not another curve to cross. A generator with an edit rate, a block length and an insertion rate is testable exactly as long as at least one of the two repetition measures is left over, and it stops being testable the moment the parameters are fitted rather than observed.

Which is fitting a class to measurements’s discipline arriving in a place it has not been applied here. There, a class is granted only if the measurements support it and the alternatives do not; the machinery’s whole value is that it can refuse. A model fitted with as many parameters as measurements cannot refuse, so it is decoration — and the fix is not fewer parameters, it is fewer free ones.

One caution belongs with the proposal, and this essay supplies it. The 7.31 comes from a positional comparison, and a positional comparison cannot see an insertion — so it over-reports how much changed and under-reports how localised the changes are. A block length taken from it is therefore biased in the direction that flatters a substitution model, which is exactly the wrong direction for a parameter that is supposed to test one. Getting an honest block length needs an alignment rather than a comparison, which is a real cost and is the reason the shortcut is not free.

So the sequence is: align, measure the block length, fix it, fit the rate, and read the disagreement between the two repetition measures as a result rather than as a residual. None of that is proposed as a better generator — a limit is not a prediction applies to models as much as to classes — but it is the arrangement under which a better generator could be shown to be one.

What the measures do not see

One more thing worth recording, because it is a null result and it constrains what a better model would need.

Shuffle the version history’s documents into an order they were never in. Every document is kept, every character, every symbol. The run count moves by 0.06% and the phrase count by 0.4%.

So neither measure sees the order at all. A generator that produced the right documents in the wrong order would be indistinguishable, on these two measures, from one that got the order right — and a two-parameter model of edits is therefore not being asked to model a history at all. It is being asked to model a set of similar documents.

Real documents are not the same lengthEach bar is one document. The version history's ten revisions run from 1,086 to 4,079 characters and grow monotonically, because a file that is edited across ten versions mostly gets longer. The eight source modules vary by 3.12x. The twelve essays vary by only 1.26x, and that is the one uniformity here that is genuinely an artefact: they come from a collection that requires every essay to sit inside a length band. A generated collection matched to any of them has 12 documents of exactly 2,048 characters each, every time.twelve essaysrepeats a vocabulary1.26xeight source modulesrepeats a form3.12xten revisions of one filerepeats almost everything3.76xgenerated, matchedone length by construction1.00xdocument length · the ratio of longest to shortest at the right24,576 characters a part3.76x at the widest
Fig. 7 The documents themselves, which is what the measures see. Their order does not enter either number.

What a model is for

It is worth being clear about the claim, because “the model is wrong” is too strong and “the model is fine” is too weak.

A generator in this collection has one job: to produce a collection with a stated, reproducible degree of repetition, so that a structure’s behaviour can be measured as a function of it. For that job the shape of the edits is irrelevant — what matters is that turning the dial moves the measures monotonically and that the same setting always gives the same collection.

It does both. Everything measured against it in five strands is measured against a controlled input, which is what a controlled input is for.

What it cannot do is stand in for a real collection when the question is what a real collection is like. The document strand asked exactly that question — how many documents, what alphabet, how uneven — and answered it from a generator, which is where documents that are not the same length finds something that does not survive.

A model is an instrument, not a sample. The failure is not in the generator; it is in the sentences that treated its output as data.

What this does to the five strands

Nothing, directly, and that is worth saying before the essay that says it carefully.

Every conclusion in the repetition, index, phrase-index, grid and cap strands — from an index with z in its size onwards — is a statement about a structure’s behaviour as a function of a collection’s measures — how an index’s size follows the run count, how a query’s cost follows the phrase count. Those are relationships, and a collection that sits at a slightly different point of the same relationship does not disturb them.

What the disagreement does disturb is any conclusion of the form this is what a repetitive collection is like. There are a few of those, and what the generated collection was right about sorts them out.

The dial has no settingThe generator has one parameter: what fraction of each copy's characters are replaced. The two curves are what it produces; the two horizontal lines are what the real version history actually is. If the generator were a model of a version history there would be one setting where both curves meet their line. The run count asks for 1.25% and the phrase count asks for 1.82% — 1.46x apart, and neither setting reproduces the other measure. Both axes are logarithmic.1.0%10.0%0.11fraction of characters changedper characterthe real runsthe real phrasesgenerated runsgenerated phrasesten revisions of one file · 65,541 characters1.25% against 1.82%
Fig. 8 The same fit at nearly three times the size. The two settings stay apart by about the same factor, which is what makes it a property of the model rather than of the sample.

What a reader with their own collection should do

The transferable part of this essay is not the two settings. It is the procedure.

Measure two things, not one. A model with one parameter fitted with one measurement always fits, and the fit therefore says nothing. Runs of a transform and phrases of a parse are both one pass over the text and they are sensitive to different structure.

Measure the shape of the differences. Positions differing and characters per differing block, over consecutive documents. One pass, no structure, and it says immediately whether the collection’s changes are scattered or localised — which decides which of the two measures a model will get wrong.

And check the direction of every artefact. A positional comparison cannot see an insertion, so it over-reports change and under-reports localisation, and both errors flatter a substitution model. Knowing which way an instrument is wrong is most of what makes it usable.

None of that needs the generator, and all of it is available before deciding whether a compressed structure is worth building.

What is checked

The sweep reaches the real values on both measures, which is what makes “the setting each asks for” a crossing rather than a nearest point. A sweep that never reached them would give two arbitrary numbers.

The two settings differ by more than a quarter — asserted, so that a change to the generator that made them agree would fail here rather than quietly removing this essay’s subject.

Real edits arrive in blocks more than three times longer than generated ones, which is the measurement that explains the disagreement rather than merely reporting it.

And two things must fail. A corpus cut to one length — the ordinary preparation step — loses 55.8% of the collection and moves both measures. A corpus with its characters shuffled multiplies the run count by 7.42 with its zero-order entropy unchanged, which is what makes both measures measures of repetition rather than of symbol frequencies.

The dial has no settingThe generator has one parameter: what fraction of each copy's characters are replaced. The two curves are what it produces; the two horizontal lines are what the real version history actually is. If the generator were a model of a version history there would be one setting where both curves meet their line. The run count asks for 13.81% and the phrase count asks for 19.12% — 1.38x apart, and neither setting reproduces the other measure. Both axes are logarithmic.1.0%10.0%0.11fraction of characters changedper characterthe real runsthe real phrasesgenerated runsgenerated phraseseight source modules · 24,578 characters13.81% against 19.12%
Fig. 9 The same fit against the source part, which the generator does not even land near. A model of a version history is a model of a version history.

What this makes readable

Essays that name this one as a prerequisite.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

What links here

Every essay whose body links to this one.

The objects this essay names

Each one links to every other essay that touches it.

ControlCorpusEdit distanceFitGenerated collectionMeasurementModelParameterPhrase countRepetitionRun countVersion history