plurimath 0.11.12 → 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 +2 -0
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e4112028ba3d71553b4695b371e34b8ba481739085e6d330fcba281970482f35
|
|
4
|
+
data.tar.gz: 1bf3a115ef3dc443d1c02d7e15d288f336177830dbcccbc00b68309c8cf05352
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28c135b5a874a229183a29adb31d1ef34ad2b700927800c6e557e83a2fa681afb959e3c95f7eb696c0fdaa7f5a2daeb7d7784e11f5db6f1f75e26a3de8ea1e11
|
|
7
|
+
data.tar.gz: 04fb461b9990cc43cb3ef39b5948eb76248e175d3d5bb8bf34a5d83958ed4fe29b843d06aa5c02c3f85684dce26b93c88ad16f8ba6ddcbb7168642c59fb1875c
|
|
@@ -14,4 +14,11 @@ jobs:
|
|
|
14
14
|
uses: metanorma/ci/.github/workflows/dependent-rake.yml@main
|
|
15
15
|
with:
|
|
16
16
|
command: bundle exec rspec
|
|
17
|
+
# Remove the source bootstrap once the amath runtime dependency in #512 is available.
|
|
18
|
+
after-setup-ruby: |
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
git init ../amath
|
|
21
|
+
git -C ../amath fetch --depth 1 https://github.com/plurimath/amath.git b67f924477ce129e85926eda5973d771c007dfec
|
|
22
|
+
git -C ../amath checkout --detach FETCH_HEAD
|
|
23
|
+
printf '\ngem "amath", path: "../amath"\ngem "parsanol", "~> 1.3", ">= 1.3.112"\n' >> Gemfile
|
|
17
24
|
repos-json-file: .github/workflows/dependent-repos-ruby.json
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Shared conformance suite
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
conformance:
|
|
13
|
+
runs-on: ubuntu-22.04
|
|
14
|
+
timeout-minutes: 45
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v5
|
|
17
|
+
with:
|
|
18
|
+
submodules: recursive
|
|
19
|
+
- uses: ruby/setup-ruby@v1
|
|
20
|
+
with:
|
|
21
|
+
ruby-version: "4.0.1"
|
|
22
|
+
bundler-cache: true
|
|
23
|
+
- name: Run shared YAML conformance cases
|
|
24
|
+
run: bundle exec rspec spec/conformance --format progress
|
data/.gitmodules
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
[submodule "submodules/unicodemath-tests"]
|
|
2
2
|
path = submodules/unicodemath-tests
|
|
3
3
|
url = git@github.com:plurimath/unicodemath-tests.git
|
|
4
|
+
[submodule "submodules/plurimath-testsuite"]
|
|
5
|
+
path = submodules/plurimath-testsuite
|
|
6
|
+
url = https://github.com/plurimath/plurimath-testsuite.git
|
data/.rspec-opal
CHANGED
data/Gemfile
CHANGED
|
@@ -4,11 +4,29 @@ source "https://rubygems.org"
|
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
6
|
gem "canon"
|
|
7
|
+
# Optional native image-rendering backend for `Formula#render` / `plurimath
|
|
8
|
+
# render`. Git-pinned until `lasem` ships to RubyGems; intentionally NOT a
|
|
9
|
+
# gemspec runtime dependency so Opal/plurimath-js and lasem-less installs keep
|
|
10
|
+
# working. For local dev against an in-progress checkout:
|
|
11
|
+
# bundle config set --local local.lasem /path/to/lasem-ruby
|
|
12
|
+
gem "lasem", github: "plurimath/lasem-ruby", branch: "main", submodules: true
|
|
7
13
|
# gem "lutaml-model", github: "lutaml/lutaml-model", branch: "main"
|
|
8
14
|
gem "oga"
|
|
15
|
+
# spec_helper selects the Nokogiri adapter directly.
|
|
16
|
+
gem "nokogiri"
|
|
17
|
+
# AsciiMath parser; tracks amath main until a release is published.
|
|
18
|
+
# AMATH_PATH points at a local amath checkout instead.
|
|
19
|
+
if ENV["AMATH_PATH"]
|
|
20
|
+
gem "amath", path: ENV["AMATH_PATH"]
|
|
21
|
+
else
|
|
22
|
+
gem "amath", github: "plurimath/amath", ref: "b67f924477ce129e85926eda5973d771c007dfec"
|
|
23
|
+
end
|
|
9
24
|
# gem "omml", github: "plurimath/omml", branch: "main"
|
|
10
25
|
gem "opal-rspec", "~> 1.1.0a"
|
|
11
26
|
gem "ox"
|
|
27
|
+
# Parsanol::Slice for the amath SliceAdapter specs.
|
|
28
|
+
# 1.3.112 restores the v1 edition default (1.3.110 and 1.3.111 are yanked).
|
|
29
|
+
gem "parsanol", "~> 1.3", ">= 1.3.112"
|
|
12
30
|
gem "rake", "~> 12.0"
|
|
13
31
|
gem "rspec", "~> 3.0"
|
|
14
32
|
gem "rubocop-performance"
|
data/README.adoc
CHANGED
|
@@ -13,7 +13,8 @@ remains consistent and accurate regardless of the format it is presented in.
|
|
|
13
13
|
Supported math representational languages:
|
|
14
14
|
|
|
15
15
|
* https://www.w3.org/TR/MathML3/[MathML 3] (and https://www.w3.org/TR/mathml4/[MathML 4])
|
|
16
|
-
* https://www.asciimath.org[AsciiMath]
|
|
16
|
+
* https://www.asciimath.org[AsciiMath] (parsed by the
|
|
17
|
+
https://github.com/plurimath/amath[amath] gem)
|
|
17
18
|
* http://unicodemath.org[UnicodeMath] (https://www.unicode.org/notes/tn28/UTN28-PlainTextMath-v3.2.pdf[UnicodeMath v3.2])
|
|
18
19
|
* LaTeX math
|
|
19
20
|
* Microsoft Office Math Markup Language (OMML) https://devblogs.microsoft.com/math-in-office/officemath/["OfficeMath"]
|
|
@@ -38,6 +39,13 @@ Accessibility:: Convert mathematical content into formats that are more
|
|
|
38
39
|
accessible for screen readers and other assistive technologies.
|
|
39
40
|
|
|
40
41
|
|
|
42
|
+
== Reference catalog
|
|
43
|
+
|
|
44
|
+
`Plurimath::Catalog.entries` generates reference data for documented functions,
|
|
45
|
+
including each serializer's output and separate availability notes. See
|
|
46
|
+
link:docs/catalog.adoc[the Ruby catalog contract] for the entry schema and export rules.
|
|
47
|
+
|
|
48
|
+
|
|
41
49
|
== Installation
|
|
42
50
|
|
|
43
51
|
Add this line to your application's Gemfile:
|
|
@@ -142,6 +150,68 @@ plurimath help convert
|
|
|
142
150
|
----
|
|
143
151
|
|
|
144
152
|
|
|
153
|
+
=== Rendering images
|
|
154
|
+
|
|
155
|
+
The `render` command rasterizes or vectorizes a formula to an image
|
|
156
|
+
(`svg`, `png`, `pdf`, or `ps`) using the optional
|
|
157
|
+
https://github.com/plurimath/lasem-ruby[`lasem`] gem (a native extension
|
|
158
|
+
wrapping the Lasem C library). Image rendering is OPTIONAL: Plurimath works
|
|
159
|
+
fully without it, and it is unavailable under Opal/plurimath-js. See
|
|
160
|
+
<<image-rendering,Rendering to images>> for installing the backend.
|
|
161
|
+
|
|
162
|
+
[source,bash]
|
|
163
|
+
----
|
|
164
|
+
plurimath render [options]
|
|
165
|
+
----
|
|
166
|
+
|
|
167
|
+
Options mirror `convert` for the input side (`-i`, `-f`, `-p`, `-e`), plus:
|
|
168
|
+
|
|
169
|
+
`-o`, `--output <FILE>`::
|
|
170
|
+
Output file path. The image format is taken from its extension
|
|
171
|
+
(`.svg`/`.png`/`.pdf`/`.ps`); an extension outside that set is an error. When
|
|
172
|
+
omitted, the rendered bytes are written to standard output.
|
|
173
|
+
|
|
174
|
+
`-r`, `--format <FORMAT>`::
|
|
175
|
+
Image format (`svg`, `png`, `pdf`, `ps`). Used when `--output` has no usable
|
|
176
|
+
extension or when writing to standard output (a file's extension takes
|
|
177
|
+
precedence). Defaults to `svg`.
|
|
178
|
+
|
|
179
|
+
`-d`, `--display-style`::
|
|
180
|
+
DisplayStyle, boolean. Defaults to the parsed formula's display style.
|
|
181
|
+
|
|
182
|
+
`-s`, `--split-on-linebreak`::
|
|
183
|
+
Boolean. Note that lasem renders a single MathML document, so this mainly
|
|
184
|
+
affects the serialized MathML rather than producing multiple images.
|
|
185
|
+
|
|
186
|
+
`-e`, `--xml-engine <ENGINE>`::
|
|
187
|
+
XML engine used to parse the input (`ox` or `oga`). Defaults to `ox`.
|
|
188
|
+
|
|
189
|
+
`--ppi`, `--zoom`, `--width`, `--height`, `--offset-x`, `--offset-y`::
|
|
190
|
+
Numeric geometry options passed through to lasem; omit them to use lasem's
|
|
191
|
+
defaults.
|
|
192
|
+
|
|
193
|
+
[example]
|
|
194
|
+
.Render an AsciiMath equation to a PNG file
|
|
195
|
+
====
|
|
196
|
+
[source,bash]
|
|
197
|
+
----
|
|
198
|
+
plurimath render -i "sqrt(x^2 + y^2)" -f asciimath -o formula.png --ppi 144
|
|
199
|
+
----
|
|
200
|
+
====
|
|
201
|
+
|
|
202
|
+
[example]
|
|
203
|
+
.Render a LaTeX file to SVG on standard output
|
|
204
|
+
====
|
|
205
|
+
[source,bash]
|
|
206
|
+
----
|
|
207
|
+
plurimath render -p formula.tex -f latex -r svg > formula.svg
|
|
208
|
+
----
|
|
209
|
+
====
|
|
210
|
+
|
|
211
|
+
If the `lasem` backend is unavailable, the format is unsupported, or rendering
|
|
212
|
+
fails, the command prints a message and exits with a non-zero status.
|
|
213
|
+
|
|
214
|
+
|
|
145
215
|
== Ruby API
|
|
146
216
|
|
|
147
217
|
|
|
@@ -457,6 +527,69 @@ omml = formula.to_omml
|
|
|
457
527
|
----
|
|
458
528
|
|
|
459
529
|
|
|
530
|
+
[#image-rendering]
|
|
531
|
+
=== Rendering to images
|
|
532
|
+
|
|
533
|
+
`Formula#render` produces a binary image (`:svg`, `:png`, `:pdf`, or `:ps`) by
|
|
534
|
+
serializing the formula to MathML and handing it to the optional
|
|
535
|
+
https://github.com/plurimath/lasem-ruby[`lasem`] gem, a native extension
|
|
536
|
+
wrapping the Lasem C library. `lasem` is an OPTIONAL, soft dependency: it is not
|
|
537
|
+
a runtime dependency of Plurimath, is unavailable under Opal/plurimath-js, and
|
|
538
|
+
must be added explicitly.
|
|
539
|
+
|
|
540
|
+
Until `lasem` is published to RubyGems, pin it via Git in your `Gemfile`:
|
|
541
|
+
|
|
542
|
+
[source,ruby]
|
|
543
|
+
----
|
|
544
|
+
gem "lasem", github: "plurimath/lasem-ruby", branch: "main", submodules: true
|
|
545
|
+
----
|
|
546
|
+
|
|
547
|
+
Then verify the native toolchain (cairo, pango, and the Lasem C library):
|
|
548
|
+
|
|
549
|
+
[source,sh]
|
|
550
|
+
----
|
|
551
|
+
bundle exec lasem-doctor
|
|
552
|
+
----
|
|
553
|
+
|
|
554
|
+
Render with `Formula#render`:
|
|
555
|
+
|
|
556
|
+
[source,ruby]
|
|
557
|
+
----
|
|
558
|
+
formula = Plurimath::Math.parse("sum_(i=1)^n i", "asciimath")
|
|
559
|
+
|
|
560
|
+
svg = formula.render(format: :svg)
|
|
561
|
+
png = formula.render(format: :png, ppi: 144, zoom: 2)
|
|
562
|
+
File.binwrite("sum.png", png)
|
|
563
|
+
----
|
|
564
|
+
|
|
565
|
+
Or render directly from source in one step with `Plurimath::Math.render`, which
|
|
566
|
+
parses and then renders (parse options such as `:locale` are routed to parsing):
|
|
567
|
+
|
|
568
|
+
[source,ruby]
|
|
569
|
+
----
|
|
570
|
+
png = Plurimath::Math.render("sum_(i=1)^n i", "asciimath", format: :png, ppi: 144)
|
|
571
|
+
File.binwrite("sum.png", png)
|
|
572
|
+
|
|
573
|
+
# Check availability before rendering to avoid a raise:
|
|
574
|
+
Plurimath::Math.render_available? # => true / false (always false under Opal)
|
|
575
|
+
----
|
|
576
|
+
|
|
577
|
+
Supported `format:` values are `:svg`, `:png`, `:pdf`, `:ps`. Remaining keyword
|
|
578
|
+
options are split between the MathML serialization (`:display_style`,
|
|
579
|
+
`:intent`, `:formatter`, `:unitsml`, `:unary_function_spacing`,
|
|
580
|
+
`:split_on_linebreak`) and the lasem renderer (`:ppi`, `:zoom`, `:width`,
|
|
581
|
+
`:height`, `:offset_x`, `:offset_y`); omit the geometry options to use lasem's
|
|
582
|
+
defaults. When `:display_style` is omitted the formula's own display style is
|
|
583
|
+
used.
|
|
584
|
+
|
|
585
|
+
If `lasem` or its native extension is unavailable, the format is unsupported, or
|
|
586
|
+
rendering fails, a `Plurimath::Errors` rendering error is raised
|
|
587
|
+
(`RenderingUnavailable`, `UnsupportedRenderFormat`, or `RenderingFailed` — all
|
|
588
|
+
subclasses of `Plurimath::Error`); the unavailable message points you to
|
|
589
|
+
`lasem-doctor`. A malformed formula surfaces as `Plurimath::Math::ParseError`
|
|
590
|
+
from the MathML step, not as a rendering error.
|
|
591
|
+
|
|
592
|
+
|
|
460
593
|
== Number formatting
|
|
461
594
|
|
|
462
595
|
=== Introduction
|
|
@@ -2099,8 +2232,29 @@ of the parsed mathematical expression.
|
|
|
2099
2232
|
----
|
|
2100
2233
|
formula = Plurimath::Math.parse("sin(1)", :asciimath)
|
|
2101
2234
|
formula.to_display(:formula)
|
|
2102
|
-
#
|
|
2103
|
-
|
|
2235
|
+
# Plurimath::Math::Formula
|
|
2236
|
+
# value[0]: Plurimath::Math::Function::Sin
|
|
2237
|
+
# parameter_one: Plurimath::Math::Function::Fenced
|
|
2238
|
+
# parameter_one: Plurimath::Math::Symbols::Paren::Lround
|
|
2239
|
+
# value: nil
|
|
2240
|
+
# parameter_two[0]: Plurimath::Math::Number
|
|
2241
|
+
# value: "1"
|
|
2242
|
+
# parameter_three: Plurimath::Math::Symbols::Paren::Rround
|
|
2243
|
+
# value: nil
|
|
2244
|
+
----
|
|
2245
|
+
|
|
2246
|
+
This tree shows the stored Ruby objects, with their full class names and ordered
|
|
2247
|
+
content fields. Array entries have indexes; empty arrays are shown as `[]` and
|
|
2248
|
+
absent values as `nil`. Some symbol classes, such as `Lround`, represent their
|
|
2249
|
+
symbol through the class itself and store no literal value. String literals are
|
|
2250
|
+
escaped, so quotes, backslashes and newlines stay on one tree line.
|
|
2251
|
+
|
|
2252
|
+
The tree preserves `Formula` and `Fenced` wrappers and does not group operators:
|
|
2253
|
+
the stored siblings in `a+b` remain siblings. It includes `value`, function
|
|
2254
|
+
parameters, table delimiters, UnitsML text and the declared uncertainty fields.
|
|
2255
|
+
Formatting flags and options, original input text, XML internals and rendering
|
|
2256
|
+
caches are omitted. Repeated references appear at each position; a reference to
|
|
2257
|
+
an ancestor is marked `<cycle: ClassName>`.
|
|
2104
2258
|
|
|
2105
2259
|
=== Displaying in the math language of expression
|
|
2106
2260
|
|
|
@@ -2131,6 +2285,107 @@ formula.to_display(:mathml)
|
|
|
2131
2285
|
# |_ "<mtext>1</mtext>" text
|
|
2132
2286
|
----
|
|
2133
2287
|
|
|
2288
|
+
=== Displaying a semantic operator tree
|
|
2289
|
+
|
|
2290
|
+
Use `tree: :semantic` to see which operands each operator owns. The default
|
|
2291
|
+
`tree: :display` keeps the display tree shown above. Both views support
|
|
2292
|
+
`:asciimath`, `:latex`, `:mathml`, `:omml`, and `:unicodemath`; semantic expression,
|
|
2293
|
+
operand-role and leaf labels use the existing writer for the selected language.
|
|
2294
|
+
|
|
2295
|
+
[source,ruby]
|
|
2296
|
+
----
|
|
2297
|
+
formula = Plurimath::Math.parse("a+b*c", :asciimath)
|
|
2298
|
+
puts formula.to_display(:unicodemath, tree: :semantic)
|
|
2299
|
+
# |_ Semantic tree
|
|
2300
|
+
# |_ expression "a + b × c"
|
|
2301
|
+
# |_ add "+"
|
|
2302
|
+
# |_ symbol "a"
|
|
2303
|
+
# |_ multiply
|
|
2304
|
+
# |_ symbol "b"
|
|
2305
|
+
# |_ symbol "c"
|
|
2306
|
+
----
|
|
2307
|
+
|
|
2308
|
+
The semantic view shares numeric evaluation's precedence parser, but does not
|
|
2309
|
+
evaluate numbers or require variable bindings. It distinguishes explicit and
|
|
2310
|
+
implicit multiplication, retains explicit round groups, and preserves the
|
|
2311
|
+
parser's left nesting for chained subtraction, powers, and relations. Fractions,
|
|
2312
|
+
radicals, scripts, function arguments, and integral limits remain attached to
|
|
2313
|
+
their owning nodes. Fractions expose numerator and denominator roles; functions
|
|
2314
|
+
expose their name and argument; powers expose base and script. A square root
|
|
2315
|
+
exposes the implicit-degree placeholder `⬚` and its radicand. Unbounded and
|
|
2316
|
+
partly bounded integrals, sums and products also retain their body, and a powered
|
|
2317
|
+
function such as `sin^2 x` binds `x` as the function argument inside the power.
|
|
2318
|
+
|
|
2319
|
+
For example, the original integral expression produces this UnicodeMath view:
|
|
2320
|
+
|
|
2321
|
+
[source,ruby]
|
|
2322
|
+
----
|
|
2323
|
+
formula = Plurimath::Math.parse(
|
|
2324
|
+
'1/(2pi) int_0^(2pi) (bbb"d" theta) / (a + b sin theta) = 1/sqrt(a^2−b^2)',
|
|
2325
|
+
:asciimath,
|
|
2326
|
+
)
|
|
2327
|
+
puts formula.to_display(:unicodemath, tree: :semantic)
|
|
2328
|
+
# |_ Semantic tree
|
|
2329
|
+
# |_ expression "(1)/(2 π) ∫_(0)^(2 π)▒〖(\\Bbb\"d\" θ)/(a + b sinθ)〗 = (1)/(√(a^(2) − b^(2)))"
|
|
2330
|
+
# |_ relation "="
|
|
2331
|
+
# |_ implicit multiply
|
|
2332
|
+
# |_ fraction "(1)/(2 π)"
|
|
2333
|
+
# |_ numerator "1"
|
|
2334
|
+
# |_ number "1"
|
|
2335
|
+
# |_ denominator "2 π"
|
|
2336
|
+
# |_ implicit multiply
|
|
2337
|
+
# |_ number "2"
|
|
2338
|
+
# |_ symbol "π"
|
|
2339
|
+
# |_ integral "∫_(0)^(2 π)▒〖(\\Bbb\"d\" θ)/(a + b sinθ)〗"
|
|
2340
|
+
# |_ lower limit "0"
|
|
2341
|
+
# |_ number "0"
|
|
2342
|
+
# |_ upper limit "2 π"
|
|
2343
|
+
# |_ implicit multiply
|
|
2344
|
+
# |_ number "2"
|
|
2345
|
+
# |_ symbol "π"
|
|
2346
|
+
# |_ integrand "(\\Bbb\"d\" θ)/(a + b sinθ)"
|
|
2347
|
+
# |_ fraction "(\\Bbb\"d\" θ)/(a + b sinθ)"
|
|
2348
|
+
# |_ numerator "\\Bbb\"d\" θ"
|
|
2349
|
+
# |_ implicit multiply
|
|
2350
|
+
# |_ symbol "\\Bbb\"d\""
|
|
2351
|
+
# |_ symbol "θ"
|
|
2352
|
+
# |_ denominator "a + b sinθ"
|
|
2353
|
+
# |_ add "+"
|
|
2354
|
+
# |_ symbol "a"
|
|
2355
|
+
# |_ implicit multiply
|
|
2356
|
+
# |_ symbol "b"
|
|
2357
|
+
# |_ apply "sinθ"
|
|
2358
|
+
# |_ function name "sin"
|
|
2359
|
+
# |_ argument "θ"
|
|
2360
|
+
# |_ symbol "θ"
|
|
2361
|
+
# |_ fraction "(1)/(√(a^(2) − b^(2)))"
|
|
2362
|
+
# |_ numerator "1"
|
|
2363
|
+
# |_ number "1"
|
|
2364
|
+
# |_ denominator "√(a^(2) − b^(2))"
|
|
2365
|
+
# |_ square root "√(a^(2) − b^(2))"
|
|
2366
|
+
# |_ degree "⬚"
|
|
2367
|
+
# |_ radicand "a^(2) − b^(2)"
|
|
2368
|
+
# |_ subtract "−"
|
|
2369
|
+
# |_ power "a^(2)"
|
|
2370
|
+
# |_ base "a"
|
|
2371
|
+
# |_ symbol "a"
|
|
2372
|
+
# |_ script "2"
|
|
2373
|
+
# |_ number "2"
|
|
2374
|
+
# |_ power "b^(2)"
|
|
2375
|
+
# |_ base "b"
|
|
2376
|
+
# |_ symbol "b"
|
|
2377
|
+
# |_ script "2"
|
|
2378
|
+
# |_ number "2"
|
|
2379
|
+
----
|
|
2380
|
+
|
|
2381
|
+
The double-struck `d` remains a styled symbol multiplied by `theta`; the view
|
|
2382
|
+
does not infer a differential. It builds a temporary rendering view and leaves
|
|
2383
|
+
the stored Formula model unchanged. This is not a general symbolic algebra
|
|
2384
|
+
engine: unsupported or ambiguous constructs, including tables, text runs,
|
|
2385
|
+
non-round fences, missing operands, and adjacent number literals, raise
|
|
2386
|
+
`Plurimath::Errors::UnsupportedSemanticTreeError` naming the construct. Unknown
|
|
2387
|
+
`tree:` values raise `ArgumentError`.
|
|
2388
|
+
|
|
2134
2389
|
// == Integration
|
|
2135
2390
|
|
|
2136
2391
|
// Integrate Plurimath into your project by requiring the gem and using its
|
|
@@ -2375,6 +2630,45 @@ NOTE: To regenerate these files, delete them and run:
|
|
|
2375
2630
|
* link:OMML-Supported-Data.adoc[OMML Supported Data]
|
|
2376
2631
|
* link:UnitsML-Supported-Data.adoc[UnitsML Supported Data]
|
|
2377
2632
|
|
|
2633
|
+
== Shared conformance fixtures
|
|
2634
|
+
|
|
2635
|
+
The language-independent YAML expectations used by the TypeScript port are
|
|
2636
|
+
pinned at `submodules/plurimath-testsuite`. Initialize the test data before
|
|
2637
|
+
running specs:
|
|
2638
|
+
|
|
2639
|
+
[source,sh]
|
|
2640
|
+
----
|
|
2641
|
+
git submodule update --init --recursive
|
|
2642
|
+
bundle exec rspec spec/conformance
|
|
2643
|
+
----
|
|
2644
|
+
|
|
2645
|
+
The conformance specs validate the dataset and compare preprocessing, parser
|
|
2646
|
+
trees, formula models, rendering outcomes, rejection positions and recorded
|
|
2647
|
+
formatter/UnitsML calls. Cases are read directly from the pinned repository;
|
|
2648
|
+
the test run never regenerates expectations. Missing, empty or unsupported
|
|
2649
|
+
corpora fail the run. The golden bytes were recorded with Ox, so these specs
|
|
2650
|
+
run once with Ox. Existing native specs still run with Ox and Oga. The native
|
|
2651
|
+
filesystem/YAML adapter is excluded from Opal test discovery.
|
|
2652
|
+
|
|
2653
|
+
Portable parser and renderer expectations also live in the pinned repository's
|
|
2654
|
+
`fixtures/` directory. Native specs select shared case IDs instead of embedding
|
|
2655
|
+
expected trees, constructor graphs or output strings. The authored datasets
|
|
2656
|
+
retain each assertion's source revision and location. They are extracted from
|
|
2657
|
+
the original expectations, independently of production parser or renderer output.
|
|
2658
|
+
|
|
2659
|
+
The adapters preserve the original entry points, argument types, configuration,
|
|
2660
|
+
operation order and comparisons. Typed constructor recipes distinguish symbols,
|
|
2661
|
+
string keys, positional arguments and keyword arguments. Memo references preserve
|
|
2662
|
+
sharing within one example, while each example receives fresh mutable values.
|
|
2663
|
+
Raw grammar fixtures preserve their preprocessing and tree projection steps.
|
|
2664
|
+
External UnicodeMath fixtures retain the original inputs, expected raw trees,
|
|
2665
|
+
models and refusal patterns.
|
|
2666
|
+
|
|
2667
|
+
These examples continue to run through the native Ox/Oga hooks. Node/Opal uses
|
|
2668
|
+
the same YAML files from the checkout. Ruby API, configuration, identity and
|
|
2669
|
+
extension-hook tests remain native. Missing cases, unsupported schemas and
|
|
2670
|
+
unknown recipe operations fail rather than silently skipping coverage.
|
|
2671
|
+
|
|
2378
2672
|
== Copyright and license
|
|
2379
2673
|
|
|
2380
2674
|
Copyright Ribose. BSD 2-clause license.
|
data/docs/catalog.adoc
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
= Ruby reference catalog
|
|
2
|
+
|
|
3
|
+
`Plurimath::Catalog.entries` returns plain Ruby hashes suitable for YAML or JSON
|
|
4
|
+
export. The catalog describes the Ruby implementation. TypeScript conformance
|
|
5
|
+
is separate work and does not gate the Ruby catalog.
|
|
6
|
+
|
|
7
|
+
== Entry identity and compatibility
|
|
8
|
+
|
|
9
|
+
Each entry has a safe lowercase `name` and a `kind`: `function` or `symbol`.
|
|
10
|
+
Use the pair `[kind, name]` as its identity. A function and symbol may share a
|
|
11
|
+
name, such as `bar`; write them to separate directories.
|
|
12
|
+
The catalog rejects duplicate identities instead of allowing exports to overwrite
|
|
13
|
+
one another.
|
|
14
|
+
|
|
15
|
+
`arity` is the reference-page category (`unary`, `binary`, or `ternary`) for a
|
|
16
|
+
function, and `nil` for a symbol. It describes the reference classification,
|
|
17
|
+
not the number of arguments accepted by a Ruby constructor.
|
|
18
|
+
|
|
19
|
+
The legacy `type` field remains unchanged: it holds the function's reference
|
|
20
|
+
category, or `symbol`. Function entries retain `description` and `reference`;
|
|
21
|
+
symbol entries omit them. Existing `asciimath`, `latexmath`, `mathml`, and `omml`
|
|
22
|
+
fields retain the serializers' exact output, including empty strings and
|
|
23
|
+
placeholders. The additional metadata does not repair or rewrite serializer output.
|
|
24
|
+
|
|
25
|
+
== Format availability
|
|
26
|
+
|
|
27
|
+
`formats` contains an entry for each of the four serialization formats:
|
|
28
|
+
|
|
29
|
+
[source,ruby]
|
|
30
|
+
----
|
|
31
|
+
entry = Plurimath::Math::Function::Sum.catalog_entry
|
|
32
|
+
entry["kind"] # => "function"
|
|
33
|
+
entry["arity"] # => "ternary"
|
|
34
|
+
entry["formats"]["mathml"]["status"] # => "available"
|
|
35
|
+
entry["formats"]["mathml"]["notes"] # => []
|
|
36
|
+
----
|
|
37
|
+
|
|
38
|
+
* `available`: the serializer returns nonempty output and no limitation is
|
|
39
|
+
declared. This is not proof of semantic parity or round-trip correctness.
|
|
40
|
+
* `limited`: a known loss or limitation is described in `notes`.
|
|
41
|
+
* `unavailable`: output is empty or the declaration identifies an unsupported
|
|
42
|
+
representation, including nonempty placeholders. `notes` explains why.
|
|
43
|
+
|
|
44
|
+
Consumers should read this metadata before presenting an example as supported.
|
|
45
|
+
Unexpected serializer exceptions still propagate; the catalog does not convert
|
|
46
|
+
programming failures into a successful availability record.
|
|
47
|
+
|
|
48
|
+
A class can declare its own limitations without affecting sibling classes:
|
|
49
|
+
|
|
50
|
+
[source,ruby]
|
|
51
|
+
----
|
|
52
|
+
CATALOG_FORMAT_LIMITATIONS = {
|
|
53
|
+
mathml: { status: :limited, notes: ["The current serializer omits a modifier."] },
|
|
54
|
+
}.freeze
|
|
55
|
+
----
|
|
56
|
+
|
|
57
|
+
Declarations use canonical keys `asciimath`, `latexmath`, `mathml`, and `omml`.
|
|
58
|
+
Keys and statuses accept strings or symbols. A declaration must use `limited`
|
|
59
|
+
or `unavailable` and include a nonempty array of explanatory strings.
|
|
60
|
+
Empty serializer output always becomes `unavailable`, with a reason.
|
|
61
|
+
|
|
62
|
+
== Validation and extension classes
|
|
63
|
+
|
|
64
|
+
The shared entry builder validates required fields, safe slugs, type/kind/arity
|
|
65
|
+
agreement, format records, and limitation declarations. Invalid data raises
|
|
66
|
+
`Plurimath::Catalog::InvalidEntryError`, a subclass of `ArgumentError`.
|
|
67
|
+
`Plurimath::Catalog::Validation.validate_all!(entries)` also checks identity
|
|
68
|
+
uniqueness when validating an exported array.
|
|
69
|
+
|
|
70
|
+
Function classes need their own description, reference, and deferred example
|
|
71
|
+
to be documentable. Anonymous classes are excluded because they have no stable
|
|
72
|
+
Ruby name. Examples and format notes are built afresh; modifying returned notes
|
|
73
|
+
does not modify the class's declarations.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# AsciiMath uncertainty: parse tree contract (plurimath#493, B4)
|
|
2
|
+
|
|
3
|
+
The amath grammar turns `ustd(...)`, `uexp(...)` and `ucov(...)` into the tree
|
|
4
|
+
below. `Plurimath::Asciimath::Transform` (rule `uncertainty:`) turns it into
|
|
5
|
+
`Math::Function::Uncertainty`. Design: `docs/uncertainty.adoc`; cases:
|
|
6
|
+
`spec/plurimath/fixtures/uncertainty/contract.yml`; spec that checks this
|
|
7
|
+
tree against amath, the transform and `Math.parse`, and round-trips every case
|
|
8
|
+
through `to_asciimath`: `spec/plurimath/asciimath/uncertainty_spec.rb`.
|
|
9
|
+
|
|
10
|
+
## Shape
|
|
11
|
+
|
|
12
|
+
The node sits where any other operand sits, for example as the whole formula:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
{ expr: { sequence: { uncertainty: { uncertainty_class: "uexp", value: "10.0",
|
|
16
|
+
magnitude: "0.3", coverage_factor: "2" } } } }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Every leaf under `uncertainty:` is a `Parslet::Slice` holding the text exactly
|
|
20
|
+
as written (no `{number: ...}` wrapper, no sign or whitespace). Keys absent from
|
|
21
|
+
the input are left out, never given as nil.
|
|
22
|
+
|
|
23
|
+
| Input | Keys under `uncertainty:` |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `ustd(y, u)` | `uncertainty_class: "ustd"`, `value`, `magnitude` |
|
|
26
|
+
| `ustd(y(d))` | `uncertainty_class: "ustd"`, `value`, `concise_digits` |
|
|
27
|
+
| `uexp(y, U, k[, p])` | `uncertainty_class: "uexp"`, `value`, `magnitude`, `coverage_factor`[, `coverage_probability`] |
|
|
28
|
+
| `ucov(y, lo, hi, p[, kind])` | `uncertainty_class: "ucov"`, `value`, `lower`, `upper`, `coverage_probability`[, `interval_kind`] |
|
|
29
|
+
| `..., "unitsml(g)")` (last argument, any form) | adds `unit: "g"` (the text inside `unitsml(...)`) |
|
|
30
|
+
|
|
31
|
+
- `value` may carry a leading `-`; every other number is unsigned. The decimal
|
|
32
|
+
marker is always a full stop, whatever the locale.
|
|
33
|
+
- `concise_digits` is the digit run inside the inner brackets: `ustd(1.230(4))`
|
|
34
|
+
gives `value: "1.230"`, `concise_digits: "4"`. The transform turns it into
|
|
35
|
+
`magnitude: 0.004`, `notation: :concise`.
|
|
36
|
+
- `unit` must not use the existing `{unitsml: ...}` key: that rule turns the unit
|
|
37
|
+
into a rendered `Formula`, but the node keeps a `Math::Function::Unitsml`.
|
|
38
|
+
|
|
39
|
+
## Shared decimal exponents
|
|
40
|
+
|
|
41
|
+
The following call forms add an optional `shared_exponent` slice containing
|
|
42
|
+
signed exponent digits without `e`. No space is allowed before `e`:
|
|
43
|
+
|
|
44
|
+
```asciimath
|
|
45
|
+
ustd((3.85, 0.23)e4)
|
|
46
|
+
ustd(680(41)e-3)
|
|
47
|
+
uexp((3.85, 0.23)e+4, 2, 0.95)
|
|
48
|
+
ucov((1.024, 0.983, 1.088)e-3, 0.95, shortest)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The transform shifts the decimal point using strings, never floating-point
|
|
52
|
+
arithmetic. It scales value and magnitude, or value and both interval
|
|
53
|
+
endpoints; coverage factors and probabilities remain unchanged. Concise
|
|
54
|
+
magnitude is derived before applying the scale. The first two examples yield
|
|
55
|
+
`38500` with magnitude `2300`, and `0.680` with magnitude `0.041`.
|
|
56
|
+
Trailing decimal zeros remain significant stored text. Writers emit the
|
|
57
|
+
normalized existing uncertainty form, which can be read back into the same
|
|
58
|
+
model.
|
|
59
|
+
|
|
60
|
+
Existing calls omit this key and retain their behavior. Bare inline uncertainty
|
|
61
|
+
is part of the separate expression-language work in #513. To bound allocation,
|
|
62
|
+
the reader rejects a shared exponent that would expand a number beyond
|
|
63
|
+
1,000,000 decimal characters with `Errors::InvalidUncertainty`; no partial
|
|
64
|
+
number or rounded approximation is returned.
|
|
65
|
+
|
|
66
|
+
The shipped amath corpus `corpora/uncertainty-shared-exponent.yml` contains the
|
|
67
|
+
input trees and exact normalized model expectations checked by the reader specs.
|
|
68
|
+
|
|
69
|
+
## Interval kind spelling
|
|
70
|
+
|
|
71
|
+
`interval_kind` is a bare word: `shortest` or `symmetric`.
|
|
72
|
+
`probabilistically-symmetric` cannot be used, because AsciiMath reads the `-` as
|
|
73
|
+
minus. `symmetric` means the probabilistically symmetric coverage interval of
|
|
74
|
+
JCGM 101 §5.3.4 and maps to `:probabilistically_symmetric`. The output side
|
|
75
|
+
(`Uncertainty#to_asciimath`, which today writes `probabilistically-symmetric`)
|
|
76
|
+
must write `symmetric` so that output reads back.
|
|
77
|
+
|
|
78
|
+
## Errors
|
|
79
|
+
|
|
80
|
+
- Wrong argument count (for example `uexp(10.0, 0.3)`, no `k`): the call is
|
|
81
|
+
not an uncertainty, and amath falls back to the letter reading it had before
|
|
82
|
+
the uncertainty words (plurimath/amath#9). `uexp(10.0, 0.3)` reads as the
|
|
83
|
+
symbol `u` followed by `exp(10.0, 0.3)`, as the contract cell
|
|
84
|
+
`invalid.asciimath_missing_k` records; no error is raised. Should a tree with
|
|
85
|
+
too few fields reach the transform anyway, the node raises
|
|
86
|
+
`Errors::InvalidUncertainty`, which `Math.parse` reports as
|
|
87
|
+
`Math::ParseError`.
|
|
88
|
+
- An unknown `uncertainty_class`, an unexpected key, a non-text leaf, both
|
|
89
|
+
`magnitude` and `concise_digits`, non-digit `concise_digits` or an unknown
|
|
90
|
+
`interval_kind` raise `Errors::InvalidUncertainty`.
|
|
91
|
+
- `+-`, `pm`, `±` and `1.230(4)` outside these three words never produce this
|
|
92
|
+
tree.
|