plurimath 0.11.11 → 0.11.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/dependent-tests.yml +7 -0
- data/.github/workflows/shared-testsuite.yml +24 -0
- data/.gitmodules +3 -0
- data/.rspec-opal +3 -0
- data/Gemfile +18 -0
- data/README.adoc +297 -3
- data/docs/catalog.adoc +73 -0
- data/docs/uncertainty-asciimath-tree.md +92 -0
- data/docs/uncertainty.adoc +522 -0
- data/lib/plurimath/asciimath/parse.rb +43 -226
- data/lib/plurimath/asciimath/parser.rb +58 -1
- data/lib/plurimath/asciimath/slice_adapter.rb +138 -0
- data/lib/plurimath/asciimath/transform.rb +218 -0
- data/lib/plurimath/asciimath.rb +1 -0
- data/lib/plurimath/catalog/entry.rb +109 -0
- data/lib/plurimath/catalog/validation.rb +109 -0
- data/lib/plurimath/catalog.rb +96 -0
- data/lib/plurimath/cli/convert.rb +40 -0
- data/lib/plurimath/cli/helpers.rb +49 -0
- data/lib/plurimath/cli/render.rb +64 -0
- data/lib/plurimath/cli.rb +55 -57
- data/lib/plurimath/documentation.rb +99 -0
- data/lib/plurimath/errors/ambiguous_decimal_error.rb +19 -0
- data/lib/plurimath/errors/invalid_uncertainty.rb +18 -0
- data/lib/plurimath/errors/missing_dependency_error.rb +23 -0
- data/lib/plurimath/errors/rendering_failed.rb +17 -0
- data/lib/plurimath/errors/rendering_unavailable.rb +25 -0
- data/lib/plurimath/errors/unsupported_render_format.rb +18 -0
- data/lib/plurimath/errors/unsupported_semantic_tree_error.rb +12 -0
- data/lib/plurimath/errors.rb +5 -0
- data/lib/plurimath/math/evaluation/evaluator.rb +48 -0
- data/lib/plurimath/math/evaluation/expression_parser.rb +29 -20
- data/lib/plurimath/math/formula/class_tree.rb +92 -0
- data/lib/plurimath/math/formula.rb +43 -2
- data/lib/plurimath/math/function/abs.rb +6 -0
- data/lib/plurimath/math/function/arccos.rb +6 -0
- data/lib/plurimath/math/function/arcsin.rb +6 -0
- data/lib/plurimath/math/function/arctan.rb +6 -0
- data/lib/plurimath/math/function/arg.rb +20 -0
- data/lib/plurimath/math/function/bar.rb +6 -0
- data/lib/plurimath/math/function/base.rb +6 -0
- data/lib/plurimath/math/function/binary_function.rb +4 -0
- data/lib/plurimath/math/function/cancel.rb +6 -0
- data/lib/plurimath/math/function/ceil.rb +6 -0
- data/lib/plurimath/math/function/color.rb +12 -0
- data/lib/plurimath/math/function/cos.rb +6 -0
- data/lib/plurimath/math/function/cosh.rb +6 -0
- data/lib/plurimath/math/function/cot.rb +6 -0
- data/lib/plurimath/math/function/coth.rb +6 -0
- data/lib/plurimath/math/function/csc.rb +6 -0
- data/lib/plurimath/math/function/csch.rb +6 -0
- data/lib/plurimath/math/function/ddot.rb +6 -0
- data/lib/plurimath/math/function/deg.rb +6 -0
- data/lib/plurimath/math/function/det.rb +6 -0
- data/lib/plurimath/math/function/dim.rb +6 -0
- data/lib/plurimath/math/function/dot.rb +6 -0
- data/lib/plurimath/math/function/exp.rb +6 -0
- data/lib/plurimath/math/function/fenced.rb +6 -0
- data/lib/plurimath/math/function/floor.rb +6 -0
- data/lib/plurimath/math/function/font_style/bold-fraktur.rb +6 -0
- data/lib/plurimath/math/function/font_style/bold-italic.rb +6 -0
- data/lib/plurimath/math/function/font_style/bold-sans-serif.rb +6 -0
- data/lib/plurimath/math/function/font_style/bold-script.rb +6 -0
- data/lib/plurimath/math/function/font_style/bold.rb +6 -0
- data/lib/plurimath/math/function/font_style/double_struck.rb +6 -0
- data/lib/plurimath/math/function/font_style/fraktur.rb +6 -0
- data/lib/plurimath/math/function/font_style/italic.rb +6 -0
- data/lib/plurimath/math/function/font_style/monospace.rb +6 -0
- data/lib/plurimath/math/function/font_style/normal.rb +6 -0
- data/lib/plurimath/math/function/font_style/sans-serif-bold-italic.rb +6 -0
- data/lib/plurimath/math/function/font_style/sans-serif-italic.rb +6 -0
- data/lib/plurimath/math/function/font_style/sans-serif.rb +6 -0
- data/lib/plurimath/math/function/font_style/script.rb +6 -0
- data/lib/plurimath/math/function/font_style.rb +4 -0
- data/lib/plurimath/math/function/frac.rb +6 -0
- data/lib/plurimath/math/function/gcd.rb +6 -0
- data/lib/plurimath/math/function/glb.rb +12 -0
- data/lib/plurimath/math/function/hat.rb +6 -0
- data/lib/plurimath/math/function/hom.rb +6 -0
- data/lib/plurimath/math/function/inf.rb +6 -0
- data/lib/plurimath/math/function/int.rb +7 -1
- data/lib/plurimath/math/function/intent.rb +35 -0
- data/lib/plurimath/math/function/ker.rb +6 -0
- data/lib/plurimath/math/function/lcm.rb +12 -0
- data/lib/plurimath/math/function/lg.rb +6 -0
- data/lib/plurimath/math/function/lim.rb +6 -0
- data/lib/plurimath/math/function/liminf.rb +6 -0
- data/lib/plurimath/math/function/limits.rb +6 -0
- data/lib/plurimath/math/function/limsup.rb +6 -0
- data/lib/plurimath/math/function/ln.rb +6 -0
- data/lib/plurimath/math/function/log.rb +6 -0
- data/lib/plurimath/math/function/longdiv.rb +6 -0
- data/lib/plurimath/math/function/lub.rb +6 -0
- data/lib/plurimath/math/function/max.rb +6 -0
- data/lib/plurimath/math/function/mbox.rb +6 -0
- data/lib/plurimath/math/function/menclose.rb +19 -0
- data/lib/plurimath/math/function/merror.rb +22 -0
- data/lib/plurimath/math/function/min.rb +6 -0
- data/lib/plurimath/math/function/mlabeledtr.rb +23 -0
- data/lib/plurimath/math/function/mod.rb +6 -0
- data/lib/plurimath/math/function/msgroup.rb +20 -0
- data/lib/plurimath/math/function/multiscript.rb +6 -0
- data/lib/plurimath/math/function/nary.rb +11 -0
- data/lib/plurimath/math/function/norm.rb +6 -0
- data/lib/plurimath/math/function/obrace.rb +6 -0
- data/lib/plurimath/math/function/oint.rb +7 -1
- data/lib/plurimath/math/function/over.rb +6 -0
- data/lib/plurimath/math/function/overleftrightarrow.rb +6 -0
- data/lib/plurimath/math/function/overset.rb +6 -0
- data/lib/plurimath/math/function/phantom.rb +6 -0
- data/lib/plurimath/math/function/power.rb +6 -0
- data/lib/plurimath/math/function/power_base.rb +6 -0
- data/lib/plurimath/math/function/prod.rb +7 -1
- data/lib/plurimath/math/function/right.rb +1 -1
- data/lib/plurimath/math/function/root.rb +6 -0
- data/lib/plurimath/math/function/rule.rb +20 -0
- data/lib/plurimath/math/function/scarries.rb +20 -0
- data/lib/plurimath/math/function/sec.rb +6 -0
- data/lib/plurimath/math/function/sech.rb +6 -0
- data/lib/plurimath/math/function/semantics.rb +20 -0
- data/lib/plurimath/math/function/sin.rb +6 -0
- data/lib/plurimath/math/function/sinh.rb +6 -0
- data/lib/plurimath/math/function/sqrt.rb +6 -0
- data/lib/plurimath/math/function/stackrel.rb +6 -0
- data/lib/plurimath/math/function/substack.rb +6 -0
- data/lib/plurimath/math/function/sum.rb +7 -1
- data/lib/plurimath/math/function/sup.rb +6 -0
- data/lib/plurimath/math/function/table/align.rb +6 -0
- data/lib/plurimath/math/function/table/array.rb +6 -0
- data/lib/plurimath/math/function/table/bmatrix.rb +6 -0
- data/lib/plurimath/math/function/table/cases.rb +6 -0
- data/lib/plurimath/math/function/table/eqarray.rb +6 -0
- data/lib/plurimath/math/function/table/matrix.rb +6 -0
- data/lib/plurimath/math/function/table/multline.rb +6 -0
- data/lib/plurimath/math/function/table/pmatrix.rb +6 -0
- data/lib/plurimath/math/function/table/split.rb +6 -0
- data/lib/plurimath/math/function/table/vmatrix.rb +6 -0
- data/lib/plurimath/math/function/table.rb +10 -0
- data/lib/plurimath/math/function/tan.rb +6 -0
- data/lib/plurimath/math/function/tanh.rb +6 -0
- data/lib/plurimath/math/function/ternary_function.rb +4 -0
- data/lib/plurimath/math/function/text.rb +6 -0
- data/lib/plurimath/math/function/tilde.rb +6 -0
- data/lib/plurimath/math/function/ubrace.rb +6 -0
- data/lib/plurimath/math/function/ul.rb +6 -0
- data/lib/plurimath/math/function/unary_function.rb +4 -0
- data/lib/plurimath/math/function/uncertainty.rb +655 -0
- data/lib/plurimath/math/function/underover.rb +6 -0
- data/lib/plurimath/math/function/underset.rb +6 -0
- data/lib/plurimath/math/function/vec.rb +6 -0
- data/lib/plurimath/math/function.rb +1 -0
- data/lib/plurimath/math/renderer.rb +95 -0
- data/lib/plurimath/math/semantic_tree.rb +331 -0
- data/lib/plurimath/math/symbols/symbol.rb +12 -5
- data/lib/plurimath/math.rb +26 -0
- data/lib/plurimath/mathml/translator.rb +32 -0
- data/lib/plurimath/mathml/uncertainty_marker.rb +118 -0
- data/lib/plurimath/omml/translator.rb +68 -0
- data/lib/plurimath/omml/utility.rb +9 -1
- data/lib/plurimath/symbol_documentation.rb +57 -0
- data/lib/plurimath/unicode_math/parsing_rules/common_rules.rb +2 -1
- data/lib/plurimath/unicode_math/parsing_rules/masked.rb +3 -0
- data/lib/plurimath/unicode_math/transform.rb +64 -3
- data/lib/plurimath/unicode_math/utility.rb +38 -0
- data/lib/plurimath/version.rb +1 -1
- data/lib/plurimath.rb +3 -0
- data/plurimath.gemspec +3 -1
- data/scripts/replay_asciimath_corpus.rb +611 -0
- metadata +30 -4
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
= Measurement uncertainty
|
|
2
|
+
|
|
3
|
+
*Status: proposal, not yet approved.* This page proposes how Plurimath should
|
|
4
|
+
represent a measured value with its uncertainty
|
|
5
|
+
(https://github.com/plurimath/plurimath/issues/493[#493]). Nothing here is
|
|
6
|
+
implemented. Once approved, record the approval link and the approved revision
|
|
7
|
+
here, and build the work on this page and on
|
|
8
|
+
`spec/plurimath/fixtures/uncertainty/contract.yml`, which holds every exact
|
|
9
|
+
string and XML form referred to below.
|
|
10
|
+
|
|
11
|
+
Section numbers refer to JCGM 100:2008 (the GUM) unless marked JCGM 101:2008.
|
|
12
|
+
|
|
13
|
+
== What is supported
|
|
14
|
+
|
|
15
|
+
Plurimath records and converts a reported result such as `100.02147(35)` or
|
|
16
|
+
`(10.0 ± 0.3), k = 2`. It does not calculate anything: no uncertainty
|
|
17
|
+
propagation, no combination, no conversion between `U`, `k`, `p` and `u`,
|
|
18
|
+
no rounding, no unit conversion.
|
|
19
|
+
|
|
20
|
+
Input and output: AsciiMath, MathML, OMML and UnicodeMath. Output only: LaTeX
|
|
21
|
+
and HTML.
|
|
22
|
+
|
|
23
|
+
An ordinary `±` keeps meaning plus-or-minus (`Math::Symbols::Pm`). A measurement
|
|
24
|
+
is only recognised from an explicit form (see <<plain-pm>>).
|
|
25
|
+
|
|
26
|
+
== The three kinds of result
|
|
27
|
+
|
|
28
|
+
Standard uncertainty (§7.2.1, §7.2.2)::
|
|
29
|
+
A value `y` and its standard uncertainty `u`, an absolute, nonnegative number in
|
|
30
|
+
the unit of `y`. It has no coverage factor and no coverage probability.
|
|
31
|
+
Supplying either is an error, because §7.2.2 (note) warns that reading `u` as an
|
|
32
|
+
interval with a level of confidence is usually not justified.
|
|
33
|
+
|
|
34
|
+
Expanded uncertainty, symmetric (§6.2.1, §6.3, §7.2.3, §7.2.4)::
|
|
35
|
+
A value `y`, an expanded uncertainty `U` and the coverage factor `k` that was
|
|
36
|
+
used. `k` is required: §7.2.3 (4) asks for it, and without it the result cannot
|
|
37
|
+
be told apart from an unqualified `±`. Write that as ordinary `±` instead.
|
|
38
|
+
The coverage probability `p` is optional and only recorded if the author gives
|
|
39
|
+
it. Plurimath never derives `p` from `k` or the reverse: §6.3.2 says these
|
|
40
|
+
parameters are not enough to know the level of confidence exactly, and §6.3.3
|
|
41
|
+
gives `k = 2` ≈ 95 % only under stated conditions.
|
|
42
|
+
|
|
43
|
+
Asymmetric: coverage interval (proposal, needs a decision)::
|
|
44
|
+
JCGM 101 §5.3.2 defines a coverage interval by its two endpoints for a stated
|
|
45
|
+
coverage probability `p`. §5.3.3 and §5.3.4 name two choices: the
|
|
46
|
+
probabilistically symmetric interval and the shortest interval. §5.5 asks for
|
|
47
|
+
the estimate `y`, its standard uncertainty, the coverage probability, the
|
|
48
|
+
endpoints and which interval was chosen. (The standard uncertainty can be given
|
|
49
|
+
as a separate standard-uncertainty result.) Its example: `y = 1.024 V`, shortest 95 % coverage interval
|
|
50
|
+
`[0.983, 1.088] V`.
|
|
51
|
+
+
|
|
52
|
+
Proposal: record `y`, the lower and upper *endpoints* (not distances from `y`),
|
|
53
|
+
the required `p`, and the optional interval choice (`shortest`,
|
|
54
|
+
`probabilistically-symmetric`, or not stated). `k` is rejected. Plurimath does not
|
|
55
|
+
require `y` to lie between the endpoints, because JCGM 101 §5.3.4 only says the
|
|
56
|
+
shortest interval contains the mode, not the estimate.
|
|
57
|
+
+
|
|
58
|
+
The common `10.0^{+0.3}_{-0.2}` layout is *not* proposed. Neither JCGM 100 §6–§7
|
|
59
|
+
nor JCGM 101 §5.3/§5.5 defines what its two numbers mean, so supporting it needs
|
|
60
|
+
a maintainer decision about its meaning first. Approving, changing or leaving
|
|
61
|
+
out this variant is a scope decision for #493.
|
|
62
|
+
|
|
63
|
+
== Model node
|
|
64
|
+
|
|
65
|
+
Proposed class `Plurimath::Math::Function::Uncertainty`
|
|
66
|
+
(`lib/plurimath/math/function/uncertainty.rb`), a direct subclass of
|
|
67
|
+
`Math::Core`.
|
|
68
|
+
|
|
69
|
+
[source,ruby]
|
|
70
|
+
----
|
|
71
|
+
Uncertainty.new(
|
|
72
|
+
value, # Math::Number, the measured value y
|
|
73
|
+
category:, # :standard, :expanded or :coverage_interval
|
|
74
|
+
magnitude: nil, # Math::Number, u or U (standard, expanded)
|
|
75
|
+
coverage_factor: nil, # Math::Number, k (expanded only, required)
|
|
76
|
+
coverage_probability: nil, # Math::Number, p (optional for expanded, required for coverage_interval)
|
|
77
|
+
lower: nil, upper: nil, # Math::Number, interval endpoints (coverage_interval only)
|
|
78
|
+
interval_kind: nil, # :shortest, :probabilistically_symmetric or nil (coverage_interval only)
|
|
79
|
+
notation: :absolute, # :absolute or :concise (standard only)
|
|
80
|
+
unit: nil, # Math::Function::Unitsml, or Math::Formula when read from markup
|
|
81
|
+
)
|
|
82
|
+
----
|
|
83
|
+
|
|
84
|
+
Validation runs in the constructor and raises a new
|
|
85
|
+
`Plurimath::Errors::InvalidUncertainty < Plurimath::Error`:
|
|
86
|
+
|
|
87
|
+
* every number is a `Math::Number` whose text is a plain decimal,
|
|
88
|
+
`-?[0-9]+(\.[0-9]+)?`; magnitudes, `k`, `p` and endpoints have no sign. No
|
|
89
|
+
exponent, no comma or other locale decimal marker, no `base`, no mini-sized
|
|
90
|
+
digits. Text is kept as given (`1.230` stays `1.230`); no `Float` is used.
|
|
91
|
+
Range checks use exact decimal comparison of the text.
|
|
92
|
+
* `u` and `U` are ≥ 0; `k` is > 0; `p` is strictly between 0 and 1 (`0.95`, not
|
|
93
|
+
`95`); `lower` < `upper`.
|
|
94
|
+
* fields that do not belong to the category must be `nil` (for example `k` on a
|
|
95
|
+
standard result, `notation` other than `:absolute` on an expanded one).
|
|
96
|
+
* `notation: :concise` needs `magnitude` to have exactly as many decimal places
|
|
97
|
+
as `value` (see <<concise>>).
|
|
98
|
+
* `unit` is `nil`, a `Math::Function::Unitsml`, or a `Math::Formula` (only
|
|
99
|
+
produced by the MathML, OMML and UnicodeMath readers, see <<units>>). A
|
|
100
|
+
`Math::Formula` unit must not be empty and must not contain another
|
|
101
|
+
`Uncertainty`; either raises `Errors::InvalidUncertainty`.
|
|
102
|
+
|
|
103
|
+
Equality (`==`) compares class and every field, including `notation` and the
|
|
104
|
+
exact number text. `ustd(1.23(4))` and `ustd(1.23, 0.04)` hold the same
|
|
105
|
+
magnitude but are *not* equal, matching how `Math::Number` already compares text.
|
|
106
|
+
|
|
107
|
+
Cloning: `Core#cloned_objects` builds `self.class.new(nil)` and then copies
|
|
108
|
+
instance variables. A validating constructor would raise on that call, so
|
|
109
|
+
`Uncertainty` overrides `cloned_objects` to rebuild itself through the full
|
|
110
|
+
constructor with cloned children, as `Math::Function::Unitsml#cloned_objects`
|
|
111
|
+
already does. The other `self.class.new(nil)` caller,
|
|
112
|
+
`Core#updated_object_values`, is only reached when a field holds a line break;
|
|
113
|
+
the fields above cannot, so B1 adds a test that line breaking leaves the node
|
|
114
|
+
alone. The clone must be `==` to the original and share no child objects.
|
|
115
|
+
|
|
116
|
+
Numbers are rendered as their raw text. The configured number formatter and
|
|
117
|
+
locale are not applied, so output never re-rounds a value or changes its
|
|
118
|
+
decimal marker. Rounding (§7.2.6) is the author's choice, not Plurimath's.
|
|
119
|
+
|
|
120
|
+
[[plain-pm]]
|
|
121
|
+
== Plain ± and measurements
|
|
122
|
+
|
|
123
|
+
A measurement is recognised only from these explicit forms. Everything else
|
|
124
|
+
keeps its current meaning.
|
|
125
|
+
|
|
126
|
+
[cols="1,3,3"]
|
|
127
|
+
|===
|
|
128
|
+
|Language |Becomes `Uncertainty` |Stays ordinary
|
|
129
|
+
|
|
130
|
+
|AsciiMath
|
|
131
|
+
|`ustd(...)`, `uexp(...)`, `ucov(...)` (added to amath at B4)
|
|
132
|
+
|`+-`, `pm`, `±` are always `Pm`; `1.230(4)` is a number followed by a bracket
|
|
133
|
+
|
|
134
|
+
|MathML
|
|
135
|
+
|an `mrow` whose `intent` starts with `standard-uncertainty`,
|
|
136
|
+
`expanded-uncertainty` or `coverage-interval`
|
|
137
|
+
|`<mo>±</mo>`, any other `intent` (still read as `Function::Intent`)
|
|
138
|
+
|
|
139
|
+
|OMML
|
|
140
|
+
|an `m:box` whose first child is the hidden marker `m:phant` described below
|
|
141
|
+
|`±` runs, `m:d` brackets, any other box or phantom
|
|
142
|
+
|
|
143
|
+
|UnicodeMath
|
|
144
|
+
|`ⓘ("<marker>" ...)` with one of the three marker names
|
|
145
|
+
|`±`, any other `ⓘ(...)`
|
|
146
|
+
|
|
147
|
+
|LaTeX (output only)
|
|
148
|
+
|—
|
|
149
|
+
|`\pm`
|
|
150
|
+
|===
|
|
151
|
+
|
|
152
|
+
A marker that uses one of the three names but is malformed (missing `k`, bad
|
|
153
|
+
number, wrong argument count) raises `InvalidUncertainty`. It is never quietly
|
|
154
|
+
read as ordinary content.
|
|
155
|
+
|
|
156
|
+
AsciiMath has no marker, only the words. A malformed AsciiMath call, for
|
|
157
|
+
example `uexp(10.0, 0.3)` with no `k`, is not an uncertainty and falls back to
|
|
158
|
+
the letter reading it had before the words were added: `u` followed by
|
|
159
|
+
`exp(10.0, 0.3)` (plurimath/amath#9). No error is raised.
|
|
160
|
+
|
|
161
|
+
Word list note for B4: today `uexp(10.0, 0.3, 2)` is read as `u` followed by
|
|
162
|
+
`exp(...)`, and `ustd`, `ucov` as separate letters. Adding the words changes
|
|
163
|
+
how such text is read, so B4 needs ambiguity tests for `uexp` against `exp`.
|
|
164
|
+
|
|
165
|
+
[[concise]]
|
|
166
|
+
== Concise, absolute and ± notation
|
|
167
|
+
|
|
168
|
+
§7.2.2 lists four ways to write a standard uncertainty. Plurimath supports two
|
|
169
|
+
of them as `notation`:
|
|
170
|
+
|
|
171
|
+
* `:concise`, §7.2.2 form 2, `100.02147(35)`: the digits in parentheses apply
|
|
172
|
+
to the last digits of the value.
|
|
173
|
+
* `:absolute`, §7.2.2 form 3, `100.02147(0.00035)`: the number in parentheses
|
|
174
|
+
is the uncertainty itself. This is the default, because it can always be
|
|
175
|
+
written and needs no digit alignment.
|
|
176
|
+
|
|
177
|
+
The model always stores the absolute magnitude. The two notations convert by
|
|
178
|
+
moving the decimal point, never through floating point:
|
|
179
|
+
|
|
180
|
+
* `1.23(4)` means `u = 0.04`; `1.230(4)` means `u = 0.004`.
|
|
181
|
+
* From model to concise: `magnitude` must have the same number of decimal
|
|
182
|
+
places as `value`; the digits are `magnitude` without its decimal point and
|
|
183
|
+
leading zeros (`0.00035` with `100.02147` gives `35`; `2.0` with `1234.5`
|
|
184
|
+
gives `20`).
|
|
185
|
+
* From concise to model: pad the digits with leading zeros and insert the
|
|
186
|
+
decimal point so the result has as many decimal places as `value`.
|
|
187
|
+
* `1.2` with `0.004` cannot be written concisely; asking for that is an error.
|
|
188
|
+
|
|
189
|
+
§7.2.2 form 4, `(y ± u)` with a written caveat, is not offered for standard
|
|
190
|
+
uncertainty: the §7.2.2 note says to avoid it. `±` is used only for expanded
|
|
191
|
+
uncertainty, always together with `k`. Form 1 (`u_c = 0.35 mg` as a separate
|
|
192
|
+
statement) is ordinary text and needs no node.
|
|
193
|
+
|
|
194
|
+
== Exact forms
|
|
195
|
+
|
|
196
|
+
=== Visible rendering
|
|
197
|
+
|
|
198
|
+
[cols="1,2,2,2"]
|
|
199
|
+
|===
|
|
200
|
+
| |LaTeX |HTML |Shown in MathML, OMML, UnicodeMath
|
|
201
|
+
|
|
202
|
+
|standard, absolute
|
|
203
|
+
|`1.230(0.004)`
|
|
204
|
+
|`1.230(0.004)`
|
|
205
|
+
|`1.230(0.004)`
|
|
206
|
+
|
|
207
|
+
|standard, concise
|
|
208
|
+
|`1.230(4)`
|
|
209
|
+
|`1.230(4)`
|
|
210
|
+
|`1.230(4)`
|
|
211
|
+
|
|
212
|
+
|expanded
|
|
213
|
+
|`(10.0 \pm 0.3),\ k = 2`
|
|
214
|
+
|`(10.0 ± 0.3), k = 2`
|
|
215
|
+
|`(10.0 ± 0.3), k = 2`
|
|
216
|
+
|
|
217
|
+
|expanded with `p`
|
|
218
|
+
|`(10.0 \pm 0.3),\ k = 2,\ p = 0.95`
|
|
219
|
+
|`(10.0 ± 0.3), k = 2, p = 0.95`
|
|
220
|
+
|`(10.0 ± 0.3), k = 2, p = 0.95`
|
|
221
|
+
|
|
222
|
+
|coverage interval (proposal)
|
|
223
|
+
|`1.024,\ [0.983, 1.088],\ p = 0.95`
|
|
224
|
+
|`1.024, [0.983, 1.088], p = 0.95`
|
|
225
|
+
|`1.024, [0.983, 1.088], p = 0.95`
|
|
226
|
+
|===
|
|
227
|
+
|
|
228
|
+
=== The marker
|
|
229
|
+
|
|
230
|
+
MathML, OMML and UnicodeMath carry the full meaning in one marker string
|
|
231
|
+
written in MathML intent syntax, with literal numbers:
|
|
232
|
+
|
|
233
|
+
[cols="1,3"]
|
|
234
|
+
|===
|
|
235
|
+
|standard, absolute |`standard-uncertainty(1.230,0.004)`
|
|
236
|
+
|standard, concise |`standard-uncertainty:concise(1.230,0.004)`
|
|
237
|
+
|expanded |`expanded-uncertainty(10.0,0.3,2)`
|
|
238
|
+
|expanded with `p` |`expanded-uncertainty(10.0,0.3,2,0.95)`
|
|
239
|
+
|coverage interval (proposal) |`coverage-interval:shortest(1.024,0.983,1.088,0.95)`;
|
|
240
|
+
`:probabilistically-symmetric`, or no property when the choice is not stated
|
|
241
|
+
|with a unit |a final `$unit` argument, for example `expanded-uncertainty(100.02147,0.00079,2,$unit)`
|
|
242
|
+
|===
|
|
243
|
+
|
|
244
|
+
The concise marker still holds the absolute magnitude, so the meaning never
|
|
245
|
+
depends on digit alignment. When reading, the marker is authoritative and the
|
|
246
|
+
visible content is regenerated on output.
|
|
247
|
+
|
|
248
|
+
=== Per language
|
|
249
|
+
|
|
250
|
+
AsciiMath (output at B2, input in amath at B4)::
|
|
251
|
+
+
|
|
252
|
+
[source]
|
|
253
|
+
----
|
|
254
|
+
ustd(1.230, 0.004) standard, absolute
|
|
255
|
+
ustd(1.230(4)) standard, concise
|
|
256
|
+
uexp(10.0, 0.3, 2) expanded
|
|
257
|
+
uexp(10.0, 0.3, 2, 0.95) expanded with p
|
|
258
|
+
ucov(1.024, 0.983, 1.088, 0.95, shortest) coverage interval (proposal)
|
|
259
|
+
uexp(100.02147, 0.00079, 2, "unitsml(g)") with a unit, always last
|
|
260
|
+
----
|
|
261
|
+
+
|
|
262
|
+
Arguments always use a full stop as decimal marker and a comma between
|
|
263
|
+
arguments, whatever the parse locale. Under a parse locale whose decimal marker
|
|
264
|
+
is not a full stop (for example `locale: :fr`, decimal `,`, or `:ar`, decimal
|
|
265
|
+
`٫`), a comma between arguments that is directly followed by a digit, as in
|
|
266
|
+
`ustd(1,5)`, `uexp(10,0, 0,3, 2)`, `ustd(1,230, 0,004)` or `ustd(1.230,0.004)`,
|
|
267
|
+
is taken as a likely decimal comma: the AsciiMath parser raises
|
|
268
|
+
`Plurimath::Errors::InvalidUncertainty` instead of guessing, which
|
|
269
|
+
`Plurimath::Math.parse` reports as `Plurimath::Math::ParseError`.
|
|
270
|
+
`ustd(1.230, 0.004)`, with a full stop and a space after each comma, reads the
|
|
271
|
+
same under every locale. Input without `ustd(`, `uexp(` or `ucov(` is not
|
|
272
|
+
checked. A value written with the Arabic decimal mark, such as
|
|
273
|
+
`ustd(1٫230, 0٫004)` under `:ar`, is not an uncertainty form and is still read
|
|
274
|
+
as the letters `u s t d` followed by a bracket.
|
|
275
|
+
|
|
276
|
+
UnicodeMath::
|
|
277
|
+
The existing intent form `ⓘ("marker"content)`:
|
|
278
|
+
+
|
|
279
|
+
[source]
|
|
280
|
+
----
|
|
281
|
+
ⓘ("standard-uncertainty(1.230,0.004)"1.230(0.004))
|
|
282
|
+
ⓘ("standard-uncertainty:concise(1.230,0.004)"1.230(4))
|
|
283
|
+
ⓘ("expanded-uncertainty(10.0,0.3,2)"(10.0±0.3), k=2)
|
|
284
|
+
ⓘ("expanded-uncertainty(10.0,0.3,2,0.95)"(10.0±0.3), k=2, p=0.95)
|
|
285
|
+
ⓘ("coverage-interval:shortest(1.024,0.983,1.088,0.95)"1.024, [0.983, 1.088], p=0.95)
|
|
286
|
+
----
|
|
287
|
+
+
|
|
288
|
+
`±` is written without spaces here because today's UnicodeMath reader fails on
|
|
289
|
+
`1.23 ± 0.04` with spaces (see <<baseline>>).
|
|
290
|
+
+
|
|
291
|
+
A negative value that would start the visible content is put in the invisible
|
|
292
|
+
`〖〗` group, because the reader cannot take `"marker"-…`. The marker is
|
|
293
|
+
unchanged:
|
|
294
|
+
+
|
|
295
|
+
----
|
|
296
|
+
ⓘ("standard-uncertainty(-1.230,0.004)"〖-1.230〗(0.004))
|
|
297
|
+
ⓘ("coverage-interval(-1.024,0.983,1.088,0.95)"〖-1.024〗, [0.983, 1.088], p=0.95)
|
|
298
|
+
----
|
|
299
|
+
+
|
|
300
|
+
An expanded result already starts with `(`, so it is written as before.
|
|
301
|
+
|
|
302
|
+
MathML::
|
|
303
|
+
An `mrow` carrying the marker as `intent`, written whatever the `intent:`
|
|
304
|
+
option of `to_mathml` is, because it carries data, not just speech hints.
|
|
305
|
+
Plurimath already writes back an `intent` it has read in the same way.
|
|
306
|
+
+
|
|
307
|
+
[source,xml]
|
|
308
|
+
----
|
|
309
|
+
<mrow intent="standard-uncertainty(1.230,0.004)">
|
|
310
|
+
<mn>1.230</mn>
|
|
311
|
+
<mrow>
|
|
312
|
+
<mo>(</mo>
|
|
313
|
+
<mn>0.004</mn>
|
|
314
|
+
<mo>)</mo>
|
|
315
|
+
</mrow>
|
|
316
|
+
</mrow>
|
|
317
|
+
|
|
318
|
+
<mrow intent="standard-uncertainty:concise(1.230,0.004)">
|
|
319
|
+
<mn>1.230</mn>
|
|
320
|
+
<mrow>
|
|
321
|
+
<mo>(</mo>
|
|
322
|
+
<mn>4</mn>
|
|
323
|
+
<mo>)</mo>
|
|
324
|
+
</mrow>
|
|
325
|
+
</mrow>
|
|
326
|
+
|
|
327
|
+
<mrow intent="expanded-uncertainty(10.0,0.3,2)">
|
|
328
|
+
<mrow>
|
|
329
|
+
<mo>(</mo>
|
|
330
|
+
<mn>10.0</mn>
|
|
331
|
+
<mo>±</mo>
|
|
332
|
+
<mn>0.3</mn>
|
|
333
|
+
<mo>)</mo>
|
|
334
|
+
</mrow>
|
|
335
|
+
<mo>,</mo>
|
|
336
|
+
<mi>k</mi>
|
|
337
|
+
<mo>=</mo>
|
|
338
|
+
<mn>2</mn>
|
|
339
|
+
</mrow>
|
|
340
|
+
|
|
341
|
+
<mrow intent="coverage-interval:shortest(1.024,0.983,1.088,0.95)">
|
|
342
|
+
<mn>1.024</mn>
|
|
343
|
+
<mo>,</mo>
|
|
344
|
+
<mrow>
|
|
345
|
+
<mo>[</mo>
|
|
346
|
+
<mn>0.983</mn>
|
|
347
|
+
<mo>,</mo>
|
|
348
|
+
<mn>1.088</mn>
|
|
349
|
+
<mo>]</mo>
|
|
350
|
+
</mrow>
|
|
351
|
+
<mo>,</mo>
|
|
352
|
+
<mi>p</mi>
|
|
353
|
+
<mo>=</mo>
|
|
354
|
+
<mn>0.95</mn>
|
|
355
|
+
</mrow>
|
|
356
|
+
----
|
|
357
|
+
+
|
|
358
|
+
Expanded with `p` appends `<mo>,</mo><mi>p</mi><mo>=</mo><mn>0.95</mn>`.
|
|
359
|
+
The full `<math>` documents are in the contract. A reader that ignores `intent`
|
|
360
|
+
shows the visible form; a reader that speaks `intent` hears the concept name
|
|
361
|
+
and its numbers.
|
|
362
|
+
|
|
363
|
+
OMML::
|
|
364
|
+
OMML has no attribute for meaning, so the marker is the text of a hidden,
|
|
365
|
+
zero-size phantom placed first inside an `m:box` that holds the whole result:
|
|
366
|
+
+
|
|
367
|
+
[source,xml]
|
|
368
|
+
----
|
|
369
|
+
<m:box>
|
|
370
|
+
<m:e>
|
|
371
|
+
<m:phant>
|
|
372
|
+
<m:phantPr>
|
|
373
|
+
<m:show m:val="off"/>
|
|
374
|
+
<m:zeroWid m:val="on"/>
|
|
375
|
+
<m:zeroAsc m:val="on"/>
|
|
376
|
+
<m:zeroDesc m:val="on"/>
|
|
377
|
+
</m:phantPr>
|
|
378
|
+
<m:e>
|
|
379
|
+
<m:r>
|
|
380
|
+
<m:rPr>
|
|
381
|
+
<m:sty m:val="p"/>
|
|
382
|
+
</m:rPr>
|
|
383
|
+
<m:t>standard-uncertainty(1.230,0.004)</m:t>
|
|
384
|
+
</m:r>
|
|
385
|
+
</m:e>
|
|
386
|
+
</m:phant>
|
|
387
|
+
<m:r>
|
|
388
|
+
<m:t>1.230</m:t>
|
|
389
|
+
</m:r>
|
|
390
|
+
<m:d>
|
|
391
|
+
<m:dPr>
|
|
392
|
+
<m:begChr m:val="("/>
|
|
393
|
+
<m:sepChr m:val=""/>
|
|
394
|
+
<m:endChr m:val=")"/>
|
|
395
|
+
</m:dPr>
|
|
396
|
+
<m:e>
|
|
397
|
+
<m:r>
|
|
398
|
+
<m:t>0.004</m:t>
|
|
399
|
+
</m:r>
|
|
400
|
+
</m:e>
|
|
401
|
+
</m:d>
|
|
402
|
+
</m:e>
|
|
403
|
+
</m:box>
|
|
404
|
+
----
|
|
405
|
+
+
|
|
406
|
+
The other variants use the same box and phantom with their own marker, followed
|
|
407
|
+
by the visible content written the way Plurimath writes it today: one `m:r` per
|
|
408
|
+
number, `±`, `,`, `k`, `p` and `=`, and an `m:d` for each bracket (`(` `)` or
|
|
409
|
+
`[` `]`). A unit is wrapped in its own inner `m:box`. Exact XML for every case is
|
|
410
|
+
in the contract.
|
|
411
|
+
|
|
412
|
+
[[units]]
|
|
413
|
+
== Units
|
|
414
|
+
|
|
415
|
+
Recommendation: *allow* an optional unit child, limited to
|
|
416
|
+
`Math::Function::Unitsml`.
|
|
417
|
+
|
|
418
|
+
Why:
|
|
419
|
+
|
|
420
|
+
* §7.2.1 (2) and §7.2.3 (2) say the unit should always be given.
|
|
421
|
+
* §7.2.4 places the unit right after the bracketed result and before the
|
|
422
|
+
coverage statement: `(100.02147 ± 0.00079) g, k = 2`. A unit written as a
|
|
423
|
+
separate expression after the node would land after `k = 2`.
|
|
424
|
+
* No dependency change is needed; the node reuses the existing
|
|
425
|
+
`Math::Function::Unitsml` rendering. No unit conversion is done.
|
|
426
|
+
|
|
427
|
+
What survives a round trip:
|
|
428
|
+
|
|
429
|
+
* AsciiMath: exact, the UnitsML text is written back
|
|
430
|
+
(`uexp(100.02147, 0.00079, 2, "unitsml(g)")`). A unit read from MathML,
|
|
431
|
+
OMML or UnicodeMath is a rendered `Math::Formula`; it is written back as
|
|
432
|
+
`"unitsml(...)"` when that is possible, by this rule:
|
|
433
|
+
** The formula must be a product of unit symbols separated by `·`
|
|
434
|
+
(`Math::Symbols::Cdot`), each symbol optionally raised to an integer power,
|
|
435
|
+
which may be negative.
|
|
436
|
+
** A unit symbol is ASCII letters only, upright (`Math::Function::FontStyle::Normal`)
|
|
437
|
+
or plain, held as a symbol or a text. `kg`, `m^2` and `s^-1` qualify; `µm`
|
|
438
|
+
and `°C` do not, because their rendered symbols are not UnitsML input.
|
|
439
|
+
** The derived text, for example `kg*m^2` or `m*s^-1`, must parse as UnitsML
|
|
440
|
+
and UnitsML must render it back to the same product. A unit written as
|
|
441
|
+
`m/s` therefore comes back as `"unitsml(m*s^-1)"`, which renders the same.
|
|
442
|
+
** Any other unit cannot be written in the AsciiMath call, whose grammar
|
|
443
|
+
accepts only a final `"unitsml(...)"` argument. It is written after the call
|
|
444
|
+
in its own AsciiMath form, for example `ustd(1.230, 0.004) mathbf(x)`. That
|
|
445
|
+
text still parses and shows the unit, but it reads back as an uncertainty
|
|
446
|
+
without a unit followed by the unit expression.
|
|
447
|
+
* MathML: the unit is written with the usual UnitsML rendering in an
|
|
448
|
+
`mrow arg="unit"`, referred to by `$unit` in the marker. On reading, the unit
|
|
449
|
+
comes back as that rendered content (a `Math::Formula`), not as a `Unitsml`
|
|
450
|
+
node. This is the same loss every UnitsML node has today: Plurimath does not
|
|
451
|
+
turn rendered MathML, OMML, UnicodeMath or AsciiMath back into `Unitsml`.
|
|
452
|
+
* OMML: as MathML, with the unit in an inner `m:box`.
|
|
453
|
+
* UnicodeMath: as MathML, with the unit as `ⓐ(unit \mupg)`. Today's reader
|
|
454
|
+
rejects `ⓐ` in this position, so B3 needs grammar work for it.
|
|
455
|
+
|
|
456
|
+
If this is judged too much for the first release, the fallback is to leave
|
|
457
|
+
units out of the node in B1–B4 and note that expanded results with units then
|
|
458
|
+
render with the unit after `k`.
|
|
459
|
+
|
|
460
|
+
== What each format keeps
|
|
461
|
+
|
|
462
|
+
[cols="2,1,1,1,1,1,1"]
|
|
463
|
+
|===
|
|
464
|
+
| |AsciiMath |MathML |OMML |UnicodeMath |LaTeX |HTML
|
|
465
|
+
|
|
466
|
+
|value, magnitude or endpoints, exact text |yes |yes |yes |yes |shown |shown
|
|
467
|
+
|kind of result |yes |yes |yes |yes |by layout only |by layout only
|
|
468
|
+
|`k`, `p` |yes |yes |yes |yes |shown |shown
|
|
469
|
+
|interval choice (shortest, symmetric) |yes |yes |yes |yes |lost |lost
|
|
470
|
+
|concise or absolute notation |yes |yes |yes |yes |shown |shown
|
|
471
|
+
|unit |exact |rendered only |rendered only |rendered only (B3 grammar) |shown |shown
|
|
472
|
+
|read back as `Uncertainty` |from B4 |yes |yes |yes |no |no
|
|
473
|
+
|===
|
|
474
|
+
|
|
475
|
+
"Shown" means visible in the output but there is no reader. LaTeX and HTML
|
|
476
|
+
never turn an expanded or interval result into a standard one; standard results
|
|
477
|
+
are never written with `±`.
|
|
478
|
+
|
|
479
|
+
Other software: a MathML consumer that ignores `intent` shows the visible form
|
|
480
|
+
correctly. An OMML consumer that ignores phantoms, including Plurimath before
|
|
481
|
+
this work, will show the marker text as ordinary text. Today's Plurimath reads
|
|
482
|
+
these MathML and UnicodeMath forms as a generic `Function::Intent` (except the
|
|
483
|
+
UnicodeMath unit form, which it rejects).
|
|
484
|
+
|
|
485
|
+
== LaTeX input
|
|
486
|
+
|
|
487
|
+
Recommendation: output only for #493. #493 does not require LaTeX input, and
|
|
488
|
+
LaTeX has no single notation for this; the usual one is the `siunitx` package
|
|
489
|
+
(`\num{1.230(4)}`). Reading `siunitx` can be added later as its own task with
|
|
490
|
+
its own tests. The LaTeX output above uses only plain math so that no package is
|
|
491
|
+
needed.
|
|
492
|
+
|
|
493
|
+
== Questions for the maintainer
|
|
494
|
+
|
|
495
|
+
. Approve, change or leave out the coverage-interval variant (and confirm that
|
|
496
|
+
the `+a/−b` layout stays out until its meaning is decided).
|
|
497
|
+
. Units: allow the `Unitsml` child as recommended, or leave units out at first.
|
|
498
|
+
. Marker names and the use of MathML intent syntax with literal numbers. The
|
|
499
|
+
syntax follows our reading of the MathML 4 intent grammar (concept name,
|
|
500
|
+
`:property`, arguments that are numbers or `$references`) and has not been
|
|
501
|
+
checked with a MathML 4 validator or screen reader.
|
|
502
|
+
. OMML hidden phantom marker. Not yet checked in Microsoft Word: whether Word
|
|
503
|
+
keeps the hidden zero-size phantom when the equation is edited, and how it
|
|
504
|
+
displays it.
|
|
505
|
+
. When the visible content in MathML, OMML or UnicodeMath disagrees with the
|
|
506
|
+
marker, the proposal trusts the marker without warning. A stricter option is to
|
|
507
|
+
raise an error.
|
|
508
|
+
. AsciiMath word names `ustd`, `uexp`, `ucov`.
|
|
509
|
+
|
|
510
|
+
[[baseline]]
|
|
511
|
+
== Observations on the current code
|
|
512
|
+
|
|
513
|
+
Measured on revision `d2aa3236` while writing this page; none of these is
|
|
514
|
+
changed by this proposal:
|
|
515
|
+
|
|
516
|
+
* UnicodeMath: `1.23 ± 0.04` (with spaces, as Plurimath itself writes it)
|
|
517
|
+
is read into raw arrays and fails to render; `1.23±0.04` works.
|
|
518
|
+
* OMML input reads `1.23` as `Math::Symbols::Symbol`, not `Math::Number`, so
|
|
519
|
+
MathML written from OMML input uses `<mi>1.23</mi>`.
|
|
520
|
+
* A generic `Function::Intent` written to OMML puts its intent text into the
|
|
521
|
+
visible equation inside nested `m:r` elements.
|
|
522
|
+
* The MathML reader dropped `arg="unit"` on an `mrow` in our test.
|