スタックベースの MathML 入力システム mathml-lifoinput
はじめに
ブログに MathML+MathJax で数式を表示することにした.
しかし,MathML を手打ちするのは大変だったので,入力システムを作った.
https:
Git リポジトリは
1995hnagamin
たとえば, という数式を書きたい場合は,次のように入力する.
x
=
-
b
±
b
2
msup
-
4
a
c
\packit 3
mrow 3
msqrt
mrow 4
2
a
\packit 2
mfrac
mrow 3
こうすると,次のような XML が生成される.
<mrow>
<mi>x</mi>
<mo>=</mo>
<mfrac>
<mrow>
<mo>-</mo>
<mi>b</mi>
<mo>±</mo>
<msqrt>
<mrow>
<msup>
<mi>b</mi>
<mn>2</mn>
</msup>
<mo>-</mo>
<mrow>
<mn>4</mn>
<mo>⁢</mo>
<mi>a</mi>
<mo>⁢</mo>
<mi>c</mi>
</mrow>
</mrow>
</msqrt>
</mrow>
<mrow>
<mn>2</mn>
<mo>⁢</mo>
<mi>a</mi>
</mrow>
</mfrac>
</mrow>
機能
トークン要素の入力
トークン要素 (token elements) は,数や識別子など数式を構成する基本要素を表現するための XML 要素である. MathML 3 では次の6つのトークン要素が定義されている(§3.2).
- 識別子を表現する
<mi>
要素 - 数を表現する
<mn>
要素 - 演算子,関係記号,括弧類,区切り記号,アクセント記号などを表現する
<mo>
要素 - テキストを表現する
<mtext>
要素 - (計算機科学において)文字列リテラルを表現する
<ms>
要素 - 空白を表現する
<mspace>
要素
<mi>
, <mn>
, <mo>
要素の入力に対応している.
<mi>
要素を作成するには,mi "{入力したい識別子}"
という形式で入力を行う.
たとえば, sin という識別子を入力するには mi "sin"
と入力する.
識別子がアルファベット1文字の場合は,mi "
, "
の部分を省略できる.
mi "sin"
mi "x"
x // これは,2行目と同じ
こうすると,<mi>sin</mi>
, <mi>x</mi>
,
<mi>x</mi>
がスタックにプッシュされる.
<mn>
要素を作成するには,mn "{入力したい数値表現}"
という形式で入力を行う.
たとえば, 123を入力するには mn "123"
と入力する.
一部の数値表現に対しては mn "
, "
の部分を省略できる.
mn "0xFFEF"
2
0.123
2.1e10
こうすると,
<mn>0xFFEF</mn>
,
<mn>2</mn>
,
<mn>0.123</mn>
,
<mn>2.1e10</mn>
がスタックにプッシュされる.
<mo>
要素を作成するには,mo "{入力したい演算子}"
という形式で入力を行う.
たとえば, +を入力するには mo "+"
と入力する.
一部の演算子に対しては mo "
, "
の部分を省略できる
(App.tsx も参照).
mo "+"
-
±
<
こうすると,
<mo>+</mo>
,
<mo>-</mo>
,
<mo>±</mo>
,
<mo><</mo>
がスタックにプッシュされる.
<mrow>
要素の入力
<mrow>
要素は,いくつかの要素をグループ化してひとつにまとめるための要素である.
<mrow>
要素を作成するには,mrow {子要素の数}
という形式で入力を行う.
たとえば,mrow 3
と入力すると,スタックから3つの要素がポップされ,
この3つの要素を子要素としてもつ mrow
要素がプッシュされる.
子要素はプッシュされた順に並べられる.
a
+
b
mrow 3
こうすると,
<mrow>
<mi>a</mi>
<mo>+</mo>
<mi>b</mi>
</mrow>
がスタックにプッシュされる.
分数の入力
分数を入力するには <mfrac>
要素を用いる.
mfrac
と入力すると,スタックから2つの要素がポップされ,
これらを子要素としてもつ <mfrac>
要素がプッシュされる.
a
b
mfrac
こうすると,
<mfrac>
<mi>a</mi>
<mi>b</mi>
</mfrac>
がスタックにプッシュされる.
属性の入力
スタックの先頭にある XML 要素に属性を追加するには,
@{属性名}="{値}"
という形式で入力を行う.
たとえば,
A
@mathvariant="fraktur"
こうすると,
<mi mathvariant="fraktur">A</mi>
()
がスタックにプッシュされる.
マクロ
入力を楽にするためにいくつかの特殊な命令を定義している. たとえば,いくつかの変数の積を入力したいときは,
4
⁢
a
⁢
c
mrow 5
のように入力すればよいが,これは少し面倒である.
そこで, \packit
命令が定義されている.
\packit {要素の数}
という形式で入力を行うと,
与えられた数の要素をスタックからポップし,
⁢
演算子ではさんだ上でこれらをまとめた
mrow
要素がプッシュされる.
4
a
c
\packit 3
今後の課題
内容 MathML に対応する
Content MathML に対応したい.
そのためには2つのアプローチがあると思う.
ひとつは自明なサポート,すなわち,
content MathML を単に木構造と見て,対応する命令(apply
, eq
など)を追加する方法.
この場合は命令の仕様が決まっているので,スタック上でどのように表示するかだけを検討すればよい.
MathML の構造を細かく制御できる点が mathml-lifoinput の特徴であるからこれらも実装する必要があると思う.
もうひとつは,presentation MathML と content MathML の内容を同期しながら編集する方法. この場合は特別なモードとして実装した方がよいと思う.
複数命令入力に対応する
今のところ各行で1命令だけを受理する仕組みになっているので,たまに不便と感じることがある.
x ; =
-;b;mrow 2; ± ; b;2;msup; -; 4;a;c;\packit 3; mrow 3; msqrt; mrow 3
2;a;\packit 2
mfrac
mrow 3
のように,1行に複数の命令を入力できるようにしたい.
React のパフォーマンスチューニング
今のところあまり困っていないが,React の勉強も兼ねてパフォーマンスチューニングの方法を学んでみたい. スタックの部分に react-window を使うとよさそう?
更新履歴
- 2021-07-14: 公開
- 2023-04-02: Document ID を追加
Permanent ID of this document: 95d1b628a42e0c7fbff8eb12f3eb2a75