Project

plurimath

0.01
The project is in a healthy, maintained state
Converts LaTeX math into MathML.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

 Project Readme

Plurimath

Purpose

Plurimath provides a common data model for mathematical representation languages and allows conversion between various math representation languages.

Plurimath aims to streamline the process of converting mathematical expressions between different representation languages. This facilitates easier integration across different systems and platforms, ensuring that mathematical content remains consistent and accurate regardless of the format it is presented in.

Supported math representational languages:

Supported units representation languages:

Benefits

Suitability

Convert mathematical content to the required format for different tools and platforms.

Correctness

Ensure mathematical expressions are correctly formatted for print and digital publications.

Interoperability

Facilitate the integration of mathematical expressions across various software systems and platforms.

Accessibility

Convert mathematical content into formats that are more accessible for screen readers and other assistive technologies.

Installation

Add this line to your application’s Gemfile:

gem "plurimath"

And then execute:

$ bundle install

Or install it yourself with:

$ gem install plurimath

Command Line Interface (CLI) usage

General

Plurimath provides a Command Line Interface (CLI) tool for converting between different math formats.

Note
Before continuing, please ensure you have the gem installed.

To convert math equations between formats, use the following command followed by appropriate options.

plurimath convert [options]

Options available are:

-i, --input <INPUT>

Specifies the input math equation. Should be provided within double quotes.

-f, --input-format <FORMAT>

Specifies the input format of the equation. Defaults to asciimath.

-p, --file-path <FILE_PATH>

Reads input from a file instead of the command line input. Use this for larger inputs or when input contains special characters.

-t, --output-format <FORMAT>

Specifies the output format type. Defaults to mathml.

-m, --math-rendering

Renders the converted equation as a math zone display tree. Boolean option (true, false).

-d, --display-style

Specifies the DisplayStyle for OMML and MathML outputs only. Boolean option (true, false).

-s, --split-on-linebreak

Splits MathML and OMML output into multiple equations. Boolean option (true, false).

Example 1. Convert an AsciiMath equation to MathML
plurimath convert -i "sqrt(x^2 + y^2)" -f asciimath -t mathml
Example 2. Convert an OMML equation to MathML with DisplayStyle
plurimath convert -i "equation" -f omml -t mathml -d true
Example 3. Convert equations from a file and output as UnicodeMath
plurimath convert -e <file_path> -t unicodemath

For more detailed information and additional options, use:

plurimath help convert

Ruby API

The central data model in Plurimath is the Plurimath::Formula class, which allows you to transform any math representation language into any other representation language.

Conversion examples

AsciiMath Formula example

asciimath = "sin(1)"
formula = Plurimath::Math.parse(asciimath, :asciimath)

MathML Formula example

mathml = <<~MATHML
  <math xmlns='http://www.w3.org/1998/Math/MathML'>
    <mstyle displaystyle='true'>
      <mi>sin</mi>
      <mn>1</mn>
    </mstyle>
  </math>
MATHML
formula = Plurimath::Math.parse(mathml, :mathml)

LaTeX Formula example

latex = "\\sin{1}"
formula = Plurimath::Math.parse(latex, :latex)

UnicodeMath Formula example

unicodemath = "sin(1)"
formula = Plurimath::Math.parse(unicodemath, :unicodemath)

OMML Formula example

omml = <<~OMML
  <m:oMathPara xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">
    <m:oMath>
      <m:f>
        <m:fPr>
          <m:ctrlPr />
        </m:fPr>
        <m:num>
          <m:r>
            <m:t>sin</m:t>
          </m:r>
        </m:num>
        <m:den>
          <m:r>
            <m:t>1</m:t>
          </m:r>
        </m:den>
      </m:f>
    </m:oMath>
  </m:oMathPara>
OMML
formula = Plurimath::Math.parse(omml, :omml)

Converting to other formats

Once you have a Plurimath::Math::Formula object, you can convert it to AsciiMath, MathML, LaTeX, UnicodeMath, or OMML by calling the respective conversion function on the Formula object.

AsciiMath output conversion

formula.to_asciimath
# => "sin(1)"
Note
AsciiMath doesn’t support certain symbols that LaTeX does. During conversion from LaTeX to AsciiMath, if a symbol is not supported in AsciiMath, the LaTeX symbol will be returned.

LaTeX output conversion

formula.to_latex
# => "\\sin1"

MathML output conversion

formula.to_mathml
# => "<math xmlns='http://www.w3.org/1998/Math/MathML'><mstyle displaystyle='true'><mi>sin</mi><mn>1</mn></mstyle></math>"

UnicodeMath output conversion

formula.to_unicodemath
# => "sin(1)"

OMML output conversion

formula.to_omml
# => "<m:oMathPara xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"><m:oMath><m:f><m:fPr><m:ctrlPr /></m:fPr><m:num><m:r><m:t>sin</m:t></m:r></m:num><m:den><m:r><m:t>1</m:t></m:r></m:den></m:f></m:oMath></m:oMathPara>"

Complex mathematical expressions

Plurimath is capable of handling complex mathematical expressions with nested functions and operators.

This feature is particularly useful for application that requires consistent and accurate conversion of intricate mathematical content.

Example. Consider the following complex LaTeX expression:

\frac{\sqrt{a^2 + b^2}}{\sin(\theta) + \cos(\theta)}

You can parse and convert this complex expression with Plurimath:

complex_latex = "\\frac{\\sqrt{a^2 + b^2}}{\\sin(\\theta) + \\cos(\\theta)}"
formula = Plurimath::Math.parse(complex_latex, :latex)

# Convert to AsciiMath
asciimath = formula.to_asciimath
# => "frac(sqrt(a^2 + b^2))(sin(theta) + cos(theta))"

# Convert to MathML
mathml = formula.to_mathml
# => "<math xmlns='http://www.w3.org/1998/Math/MathML'><mfrac><msqrt><mrow><msup><mi>a</mi><mn>2</mn></msup><mo>+</mo><msup><mi>b</mi><mn>2</mn></msup></mrow></msqrt><mrow><mi>sin</mi><mo>(</mo><mi>θ</mi><mo>)</mo><mo>+</mo><mi>cos</mi><mo>(</mo><mi>θ</mi><mo>)</mo></mrow></mfrac></math>"

# Convert to UnicodeMath
unicodemath = formula.to_unicodemath
# => "frac(√(a^2 + b^2))(sin(θ) + cos(θ))"

# Convert to OMML
omml = formula.to_omml
# => "<omml representation of the expression>"

Number formatting

Introduction

Number formatting is an essential aspect of presenting numerical data in a way that is consistent with regional conventions and user preferences. There are myriad number formatting conventions and standards that are widely used in various cultures and fields.

To address these needs, Plurimath now allows precise control over how numbers are presented through its number formatting feature.

Plurimath’s number formatter allows users to format numbers based on locale, ensuring that the formatting adheres to regional conventions and enhances both readability and precision.

For more details, please refer to the blog post Number formatting support in Plurimath

Existing conventions

Traditional conventions

Different cultures, orthographies and organizations have different conventions for formatting numbers.

These include practices on how to represent decimal points, digit grouping, digit grouping separators, and various mathematical notations.

Decimal point symbol

In the United States, a full stop (.) is used as the decimal point separator, while in many European countries, a comma (,) is used instead.

Digit grouping delimiter

In the United States, numbers are often grouped in sets of three digits using commas, such as 1,234,567.89. In some European countries, numbers are grouped using periods, such as 1.234.567,89, or a thin space, such as 1 234 567,89.

Digit grouping practices

In Western cultures, numbers ahead of the decimal are often grouped threes. Numbers behind the decimal are less standardized, but are often grouped in sets of two or three.

Mathematical notation

In scientific and engineering contexts, numbers are often formatted using scientific notation, which expresses numbers as a coefficient multiplied by a power of 10. For example, the number 123,456,789 can be expressed in scientific notation as 1.23456789 x 10^8.

Standardized conventions

Standardization organizations have established standards for number formatting to ensure uniformity and accuracy.

The SI system (International System of Units), by the BIPM (Bureau International des Poids et Mesures), specifies rules regarding the decimal point symbol, digit grouping delimiter and digit groupings.

ISO 80000-2, the international standard for quantities and units, used by all ISO and IEC standards, also provides guidelines for number formatting in a different manner than the SI system.

Using the number formatter

General

The number formatting feature is implemented in the Plurimath::NumberFormatter class, which allows users to re-use a single formatter class for formatting multiple numbers.

A simple two-step process to format numbers:

  1. Create a new Plurimath::NumberFormatter object, passing the desired locale and overriding options as arguments.

  2. Call the localized_number method on the formatter object, passing the number to be formatted as a string and any additional options.

The final formatted number is formatted according to the following configuration priority, ordered from highest to lowest precedence:

  1. The format hash given to Plurimath::NumberFormatter#localized_number

  2. The localize_number string in the creation of a Plurimath::NumberFormatter

  3. The localizer_symbols hash in the creation of a Plurimath::NumberFormatter

  4. The default configuration of the locale of the Plurimath::NumberFormatter

Example 4. Formatting a number to group every 2 digits
formatter = Plurimath::NumberFormatter.new(:en)
formatted_number = formatter.localized_number(
  "1234567.89",
  format: {
    group_digits: 2,
    # other support options
  }
)
# => "1,23,45,67.89"

Creating a number formatter

The NumberFormatter is used to format numbers based on the locale and the formatting configuration provided.

Syntax:

Syntax for creating a Plurimath::NumberFormatter object
formatter = Plurimath::NumberFormatter.new(
  <locale-symbol>,                    # mandatory (1)
  localize_number: <localize-string>, # optional (2)
  localizer_symbols: <format-hash>,   # optional (3)
  precision: <precision-number>,      # optional (4)
)
  1. Locale to be used for number formatting.

  2. String pattern to define the number formatting.

  3. Hash containing relevant options for number formatting.

  4. Number of decimal places to round.

Where,

<locale-symbol>

(optional, default :en) The locale to be used for number formatting. Accepted values are listed in the Plurimath::Formatter::SupportedLocales::LOCALES constant.

localize_number: <localize-string>

(optional, default nil) A string containing a specific sequence of characters that defines the number formatting. Use either localize_number or localizer_symbols to set the number formatting pattern.

See localize_number for details.

localizer_symbols: <format-hash>

(optional, default {}) A hash containing the relevant options for number formatting. Use either localize_number or localizer_symbols to set the number formatting pattern.

See format options hash for details.

precision: <precision-number>

(optional, default nil) Number of decimal places to round. Accepts an integer value.

Example 5. Specifying a precision of 6 digits

"32232.232" ⇒ "32232.232000"

Example 6. Creating a Plurimath::NumberFormatter object using the :en locale
formatter = Plurimath::NumberFormatter.new(:en)
# => #<Plurimath::NumberFormatter:0x00007f8b1b8b3b10 @locale=:en>

Configuring the number formatter

The Plurimath::NumberFormatter object can be configured using either the localize_number or localizer_symbols options.

Via "format options" using localizer_symbols

The localizer_symbols key is used to set the number formatting pattern through a Hash object containing specified options.

This Hash object is called the "format options Hash".

Available options are explained below.

Note
Each option takes an input of a certain specified type (String or Numeric). Using an input type other than the specified type will result in errors or incorrect output.

The values passed to localizer_symbols persist as long as the initialized NumberFormatter instance is accessible. It is therefore useful in scenarios when configuration will be static or changes are not required very often.

decimal

(String value) Symbol to use for the decimal point. Accepts a character.

Example 7. Using the ',' "comma" symbol as the decimal point

"32232.232" ⇒ "32232,232"

Example 8. Using the '.' "full stop" symbol as the decimal point

"32232.232" ⇒ "32232.232"

digit_count

(Numeric value) Total number of digits to render, with the value truncated. Accepts an integer value.

Example 9. Specifying a total of 6 digits in rendering the number

"32232.232" ⇒ "32232.2"

group

(String value) Delimiter to use between groups of digits specified in group_digits. Accepts a character. (default is not to group digits.)

Example 10. Using the unicode thin space (THIN SPACE, U+2009) as the grouping delimiter

"32232.232" ⇒ "32 232.232"

group_digits

(Numeric value) Number of digits to group the integer portion, grouping from right to left. Accepts an integer value. (default is 3 in most locales.)

Example 11. Using the unicode thin space as the grouping delimiter, and grouping every 2 digits

"32232.232" ⇒ "3 22 32.232"

fraction_group

(String value) Delimiter to use between groups of fractional digits specified in fraction_group_digits. Accepts a character.

Example 12. Using the unicode thin space as the fraction grouping delimiter

"32232.232131" ⇒ "32232.232 131".

fraction_group_digits

(Numeric value) Number of digits in each group of fractional digits, grouping from left to right. Accepts an integer value.

Example 13. Using the unicode thin space as the fraction grouping delimiter, and grouping every 2 fraction digits

"32232.232131" ⇒ "32232.23 21 31"

significant

(Numeric value) Sets the number of significant digits to show, with the value rounded.

notation

(String value) Specifies the mathematical notation to be used. Accepts the following values.

e

Use exponent notation.

Example 14. Example of using exponent notation

1.23456789e8

scientific

Use scientific notation.

Example 15. Example of using scientific notation

1.23456789 × 10⁸

engineering

Use engineering notation, where the exponent of ten is always selected to be divisible by three to match the common metric prefixes.

Example 16. Example of using engineering notation

123.456789 × 10⁶

e

(String value) Symbol to use for exponents in E notation (default value E). (used in the mode: e only).

Example 17. Using the lowercase 'e' symbol as the exponent symbol
3.2232232e5
times

(String value) Symbol to use for multiplication where required by the notation (used in the modes: scientific and engineering). Defaults to ×.

Example 18. Using the '·' "middle dot" symbol as the multiplication symbol
32.232232 · 104
exponent_sign

(String value) Whether to use a plus sign to indicate positive exponents, in exponent-based notation (used in the modes: e, scientific, engineering). Legal values are:

plus

The + symbol is used.

Example 19. Using the plus sign to indicate positive exponents
32.232232 × 10⁺⁴

These options are to be grouped under a single Hash object.

Format options Hash for localizer_symbols
{
  decimal: ",",             # replaces the decimal point with the passed string
  group_digits: 2,          # groups integer part into passed integer
  group: "'",               # places the string between grouped parts of the integer
  fraction_group_digits: 3, # groups fraction part into passed integer
  fraction_group: ",",      # places the string between grouped parts of the fraction
}
Via the localize_number option

The localize_number option accepts a formatting pattern specified as a string, using the hash symbol # to represent a digit placeholder.

The localize_number option is useful when you want to format numbers in a specific way that is not covered by the localizer_symbols option.

A sample value of #,##0.### ### is interpreted as the following configuration in the format options hash:

group

This parameter is set to the very first non-hash character before 0. If there is no non-hash character before #+0, then the default group delimiter will be nil.

In this example, it is ,.

group_digits

This parameter is set to the "count of all hashes + 1" (including the zero). Minimum 1 hash symbol is required.

In this example, ##0 sets the value to 3.

decimal

This parameter is set to the character immediately to the right of 0. This is mandatory.

In this example, it is ..

fraction_group_digits

This parameter is set to "count of all the hashes right next to decimal". Minimum 1 hash symbol is required.

In our example, '###' sets the value to 3.

fraction_group

This parameter is set to the first character after fraction_group_digits. If there is no non-hash character after fraction_group_digits, it is set to nil.

In this example it is ' ' (a space).

Example 20. Formatting a number using the localize_number option
formatter = Plurimath::NumberFormatter.new(:en, localize_number: "#,##0.### ###")
formatter.localized_number("1234.56789")
# => "1,234.568 9"

Formatting a number using NumberFormatter

The localized_number method is used to format a number given a NumberFormatter instance.

Syntax:

Syntax for localized_number
formatter.localized_number(
  <number>,                      # mandatory (1)
  locale:    <locale-symbol>,    # optional (2)
  precision: <precision-number>, # optional (3)
  format:    <format-hash>       # optional (4)
)
  1. The number to be formatted.

  2. The locale to be used for number formatting.

  3. The number of decimal places to round the number to.

  4. Hash containing the relevant options for number formatting.

Where,

<number>

(mandatory) The number to be formatted. Value should be a Numeric, i.e. Integer, Float, or BigDecimal. If not provided, an ArgumentError will be raised.

locale: <locale-symbol>

(optional) The locale to be used for number formatting. Value is a symbol. Overrides the locale set during the creation of the NumberFormatter object. If not provided, the locale of the NumberFormatter instance will be used.

precision: <precision-number>

(optional) The number of decimal places to round the number to. If not provided, the precision of the NumberFormatter instance will be used.

format: <format-hash>

(optional, default {}) A Hash containing the relevant options for number formatting, that overrides the localizer_symbols configuration of the NumberFormatter. Takes a Hash in the form of the format options hash.

precision: <precision-number>

Number of decimal places to round. Accepts an integer value.

Example 21. Specifying a precision of 6 digits

"32232.232" ⇒ "32232.232000"

Example 22. Formatting a number using the localized_number method for the English locale
formatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number("1234.56789")
# => "1,234.56789"
Example 23. Formatting a number using the localized_number method for the French locale
formatter = Plurimath::NumberFormatter.new(:fr)
formatter.localized_number("1234.56789")
# => "1 234,56789"

The locale and precision set in the NumberFormatter can be overridden by passing the locale and precision options to the localized_number method.

Example 24. Overriding locale and precision in localized_number
formatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number("1234.56789", locale: :de, precision: 6)
# => "1.234,567890"

Overriding specified NumberFormatter options using the format key

The format option is used to override the specified configuration of the NumberFormatter object.

It expects a Hash in the form of the format options hash.

formatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number(
  "1234.56789",
  format: {
    decimal: "x",
    # other supported options
  }
)
# => "1,234x56789"
Example 25. Formatting a number using the format key in the localized_number method
formatter = Plurimath::NumberFormatter.new(:en)
formatter.localized_number(
  "1234.56789",
  format: {
    decimal: "x",
    group_digits: 2,
    group: "'",
    fraction_group_digits: 3,
    fraction_group: ","
  }
)
# => "12'34x567,89"

Supported locales

Plurimath supports the following locales for number formatting. The locale values are sourced from the Unicode CLDR repository.

The list of locales and their values are given in the file lib/plurimath/formatter/supported_locales.rb.

The locales and their values can be obtained through the following code.

Getting the supported locales and their default values
Plurimath::Formatter::SupportedLocales::LOCALES[:en]
# => { decimal: ".", group: "," }
Table 1. Locales supported by Plurimath (delimiters wrapped in double quotes)
Locale Decimal delimiter Group delimiter

sr-Cyrl-ME

","

"."

sr-Latn-ME

","

"."

zh-Hant

"."

","

en-001

"."

","

en-150

"."

","

pt-PT

","

" "

nl-BE

","

"."

it-CH

"."

"’"

fr-BE

","

" "

fr-CA

","

" "

fr-CH

","

" "

de-AT

","

" "

de-CH

"."

"’"

en-AU

"."

","

en-CA

"."

","

en-GB

"."

","

en-IE

"."

","

en-IN

"."

","

en-NZ

"."

","

en-SG

"."

","

en-US

"."

","

en-ZA

"."

","

es-419

"."

","

es-AR

","

"."

es-CO

","

"."

es-MX

"."

","

es-US

"."

","

fil

"."

","

af

","

" "

ar

"٫"

"٬"

az

","

"."

be

","

" "

bg

","

" "

bn

"."

","

bo

"."

","

bs

","

"."

ca

","

"."

cs

","

" "

cy

"."

","

da

","

"."

de

","

"."

el

","

"."

en

"."

","

eo

","

" "

es

","

"."

et

","

" "

eu

","

"."

fa

"٫"

"٬"

fi

","

" "

fr

","

" "

ga

"."

","

gl

","

"."

gu

"."

","

he

"."

","

hi

"."

","

hr

","

"."

hu

","

" "

hy

","

" "

id

","

"."

is

","

"."

it

","

"."

ja

"."

","

ka

","

" "

kk

","

" "

km

","

"."

kn

"."

","

ko

"."

","

lo

","

"."

lt

","

" "

lv

","

" "

mk

","

"."

mr

"."

","

ms

"."

","

mt

"."

","

my

"."

","

nb

","

" "

nl

","

"."

pl

","

" "

pt

","

"."

ro

","

"."

ru

","

" "

sk

","

" "

sl

","

"."

sq

","

" "

sr

","

"."

sv

","

" "

sw

"."

","

ta

"."

","

th

"."

","

tr

","

"."

uk

","

" "

ur

"."

","

vi

","

"."

xh

"."

" "

zh

"."

","

zu

"."

","

Formatting numbers in a formula

General

Plurimath supports number formatting within formulas for all supported languages. This feature allows you to apply custom number formatting when converting formulas to any of the supported format.

The steps to format numbers within a formula are:

  1. Create a number formatter that can be configured;

  2. Apply the number formatter to a formula through the Formula.to_{format} method using a formatter option, which serializes the formula into an math representation language.

The formatter should be an instance of Plurimath::NumberFormatter or a custom formatter derived from Plurimath::Formatter::Standard.

The quick example below demonstrates how to format a number in a formula.

Example 26. Applying number formatting to a formula in LaTeX math

The following code applies number formatting to a LaTeX math formula.

formula = Plurimath::Math.parse('\sum_{i=1}^{10000} i^2121221', :latex) (1)
formatter = Plurimath::Formatter::Standard.new (2)
formula.to_latex(formatter: formatter) (3)
# => '\sum_{i = 1}^{10,000} i^{2,121,221}'
  1. The formula is parsed into a Formula object using the Plurimath::Math.parse method.

  2. A Plurimath::Formatter is created.

  3. The Formula.to_latex method is called with the formatter option to format the formula.

Example 27. Applying number formatting to an AsciiMath formula in MathML
formula = Plurimath::Math.parse("e^(i*pi) + 1.1 = 0.2", :asciimath)
custom_formatter = Plurimath::Formatter::Standard.new(
  locale: :fr,
  options: { number_sign: :plus },
  precision: 3
)
print formula.to_mathml(formatter: custom_formatter)
# <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
#   <mstyle displaystyle="true">
#     <msup>
#       <mi>e</mi>
#       <mrow>
#         <mi>i</mi>
#         <mo>&#x22c5;</mo>
#         <mi>&#x3c0;</mi>
#       </mrow>
#     </msup>
#     <mo>+</mo>
#     <mn>+1.100</mn>
#     <mo>=</mo>
#     <mn>+0.200</mn>
#   </mstyle>
# </math>

Defining a number formatter

A "number formatter" is a class that formats numbers in a specific way. It contains the configuration for formatting numbers, such as the number of digits in a group, the decimal separator, and the group separator.

Plurimath offers a standard formatter class called Plurimath::Formatter::Standard that includes a comprehensive standard configuration.

Creating a standard Plurimath::Formatter::Standard object
> formatter = Plurimath::Formatter::Standard.new (1)
  1. Creates a Plurimath::Formatter object that uses standard configuration.

The number formatting configuration can be changed in these ways:

  1. Pass options to the Plurimath::Formatter::Standard class initializer (with options explained in the number formatter blog post).

  2. Create a custom formatter inheriting from the Plurimath::Formatter::Standard class.

Changing number formatting configuration

The typical way to change the number formatting configuration is to create a Plurimath::Formatter::Standard object with the desired configuration options.

There are two types of number formatting configuration to change:

  1. Arguments passed to the Plurimath::Formatter::Standard class initializer.

  2. Overriding options through the options argument.

The arguments are:

locale

(default: :en for English) a symbol or string value. The supported locales are listed in the number formatter blog post.

options

(default: empty) a hash of options (localizer_symbols). The options are listed in the number formatter blog post.

format_string

(default: nil, disabled) a string value (localize_number)

precision

(default: nil, disabled) an integer value.

Example 28. Passing arguments to the Plurimath::Formatter::Standard class initializer
> options = {
  fraction_group_digits: 2,
  fraction_group: ".",
  group_digits: 2,
  decimal: ";",
  group: ",",
}

> formatter = Plurimath::Formatter::Standard.new(locale: :hy, options: options, precision: 2)
# format_string: <string value> if provided

> Plurimath::Math.parse('2121221.3434', :latex).to_latex(formatter: formatter)
# => '2,12,12,21;34'

The precision = 2 option in the initializer causes the formatted value to have decimal places truncated from 4 to 2.

Creating a custom formatter

In cases where the standard formatter’s available options do not meet the needs for number presentation, a custom formatter can be created to apply new mechanisms of formatting numbers.

The custom formatter is to be subclassed from Plurimath::Formatter::Standard.

Creating a custom formatter
class MyCustomFormatter < Plurimath::Formatter::Standard (1)
  def initialize(locale:, precision:, options:, format_string:) (2)
    super
  end
end
  1. The custom formatter class inherits from Plurimath::Formatter::Standard.

  2. The arguments can be overridden in the initialize method.

The default options of the custom formatter are set using the set_default_options method.

Syntax to override the set_default_options method
class MyCustomFormatter < Plurimath::Formatter::Standard
  def initialize(locale:, precision:, options:, format_string:)
    super
  end

  def set_default_options(options = {}) (1)
    options = {
      fraction_group_digits: 2,
      fraction_group: ".",
      ...
    }
  end
end
  1. The set_default_options method is overridden to set the default options. The shown options are ones inherited from the Plurimath::Formatter::Standard class, but additional ones understood by the class can be set.

It is used in the following manner.

Example 29. Creating a CustomFormatter object and using it to format numbers in a formula
class MyCustomFormatter < Plurimath::Formatter::Standard
  def initialize(locale: :fr)
    super
  end

  def set_default_options(options = {})
    {
      fraction_group_digits: 2,
      fraction_group: ".",
      group_digits: 2,
      decimal: ";",
      group: ",",
      ...
    }
  end
end

> formula = Plurimath::Math.parse('\sum_{i=1}^{1000.001} i^2121221.3434', :latex)
# => Plurimath::Math::Formula...
> formula.to_latex(formatter: formatter)
# => '\sum_{i = 1}^{10,00;00.1} i^{2,12,12,21;34.34}'
> formula.to_asciimath(formatter: formatter)
# => 'sum_(i = 1)^(10,00;00.1) i^(2,12,12,21;34.34)'

Default number formatting configuration

The default configuration for formatting numbers is as follows, set in the Plurimath::Formatter::Standard class.

Option key Description Value

locale

The locale used for number formatting

:en

fraction_group_digits

The number of digits in each group of the fraction part

3

exponent_sign

The sign used for the exponent part of the number

"plus"

fraction_group

The character used to separate groups of digits in the fraction part

"'"

notation

The notation used for the number formatting

:basic

group_digits

The number of digits in each group of the integer part

3

significant

The number of significant digits to display

0

digit_count

The number of digits to display

0

precision

The number of decimal places to display

0

decimal

The character used as the decimal separator

"."

group

The character used to separate groups of digits in the integer part

","

times

The character used for multiplication

"x"

e

The character used for exponentiation

"e"

Math parse trees

General

Plurimath allows you to display the math parse tree both as Formula objects and in the math language of expression.

Displaying as Formula objects

You can display the parse tree as Formula objects to understand the structure of the parsed mathematical expression.

formula = Plurimath::Math.parse("sin(1)", :asciimath)
formula.to_display(:formula)
# ...

Displaying in the math language of expression

You can also display the parse tree in the math language of expression to see how the expression is represented in that language.

formula = Plurimath::Math.parse("sin(1)", :asciimath)
formula.to_display(:asciimath)
# |_ Math zone
#   |_ "sin(1)"
#      |_ "sin" function apply
#         |_ "1" argument

formula.to_display(:latex)
# |_ Math zone
#   |_ "\\sin1"
#      |_ "sin" function apply
#         |_ "1" argument

formula.to_display(:mathml)
# |_ Math zone
#   |_ "<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mstyle displaystyle="true"><mrow><mi>sin</mi><mrow><mo>(</mo><mn>1</mn><mo>)</mo></mrow></mrow></mstyle></math>"
#      |_ "<mrow><mi>sin</mi><mrow><mo>(</mo><mn>1</mn><mo>)</mo></mrow></mrow>" function apply
#         |_ "sin" function name
#         |_ "<mrow><mo>(</mo><mn>1</mn><mo>)</mo></mrow>" argument
#            |_ "<mtext>1</mtext>" text

Working with UnitsML

General

Plurimath supports UnitsML, a markup language used to express units of measure in a way that can be understood by humans and machines. This allows you to handle mathematical expressions involving units of measure seamlessly.

UnitsML can be used with the following math representation languages:

  • MathML

  • AsciiMath

For detailed information on supported units and symbols in UnitsML, refer to the UnitsML Supported Data documentation.

Parsing and Converting UnitsML Expressions

Plurimath can parse UnitsML expressions and convert them to other mathematical representation languages. Here’s an example of how to work with UnitsML in Plurimath.

Example: Parsing and Converting UnitsML

Consider the following UnitsML expression in AsciiMath syntax:

h = 6.62607015 xx 10^(-34) "unitsml(kg*m^2*s^(-1))"

Step-by-Step Customization

  1. Parse the UnitsML Expression

  2. Customize and Convert to AsciiMath

  3. Customize and Convert to MathML

  4. Customize and Convert to UnicodeMath

  5. Customize and Convert to OMML

Parse the UnitsML Expression

First, parse the UnitsML expression using Plurimath:

require 'plurimath'

asciimath_unitsml = 'h = 6.62607015 xx 10^(-34) "unitsml(kg*m^2*s^(-1))"'
formula = Plurimath::Math.parse(asciimath_unitsml, :asciimath)

Customize and Convert to AsciiMath

You can customize the output by modifying the resulting string after conversion:

asciimath = formula.to_asciimath
# Customization logic (if any)
puts asciimath
# Output: 'h = 6.62607015 xx 10^(-34) "unitsml(kg*m^2*s^(-1))"'

Customize and convert to MathML

To customize the MathML output, you can use additional attributes and options:

mathml = formula.to_mathml
# Customization logic (if any)
puts mathml
# Output: "<math xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mi>h</mi><mo>=</mo><mn>6.62607015</mn><mo>×</mo><msup><mn>10</mn><mrow><mo>−</mo><mn>34</mn></mrow></msup><mtext>kg·m²·s⁻¹</mtext></mrow></math>"

Customize and convert to UnicodeMath

Similarly, customize the UnicodeMath output:

unicodemath = formula.to_unicodemath
# Customization logic (if any)
puts unicodemath
# Output: 'h = 6.62607015 × 10^(−34) kg·m²·s⁻¹'

Customize and convert to OMML

For OMML output, you can customize the XML structure:

omml = formula.to_omml
# Customization logic (if any)
puts omml
# Output: "<m:oMathPara xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math'><m:oMath><m:r><m:t>h</m:t></m:r><m:r><m:t>=</m:t></m:r><m:r><m:t>6.62607015</m:t></m:r><m:r><m:t>×</m:t></m:r><m:sSup><m:sSupPr><m:ctrlPr /></m:sSupPr><m:e><m:r><m:t>10</m:t></m:r></m:e><m:sup><m:r><m:t>−34</m:t></m:r></m:sup></m:sSup><m:r><m:t>kg·m²·s⁻¹</m:t></m:r></m:oMath></m:oMathPara>"

Complete example code with customization

Here’s the complete code for parsing, converting, and customizing the UnitsML expression between different formats:

require 'plurimath'

# Step 1: Parse the UnitsML Expression
asciimath_unitsml = 'h = 6.62607015 xx 10^(-34) "unitsml(kg*m^2*s^(-1))"'
formula = Plurimath::Math.parse(asciimath_unitsml, :asciimath)

# Step 2: Convert to AsciiMath
asciimath = formula.to_asciimath
# Customization logic for AsciiMath (if needed)
puts "AsciiMath: #{asciimath}"
# Output: 'h = 6.62607015 xx 10^(-34) "unitsml(kg*m^2*s^(-1))"'

# Step 3: Convert to MathML
mathml = formula.to_mathml
# Customization logic for MathML (if needed)
puts "MathML: #{mathml}"
# Output: "<math xmlns='http://www.w3.org/1998/Math/MathML'><mrow><mi>h</mi><mo>=</mo><mn>6.62607015</mn><mo>×</mo><msup><mn>10</mn><mrow><mo>−</mo><mn>34</mn></mrow></msup><mtext>kg·m²·s⁻¹</mtext></mrow></math>"

# Step 4: Convert to UnicodeMath
unicodemath = formula.to_unicodemath
# Customization logic for UnicodeMath (if needed)
puts "UnicodeMath: #{unicodemath}"
# Output: 'h = 6.62607015 × 10^(−34) kg·m²·s⁻¹'

# Step 5: Convert to OMML
omml = formula.to_omml
# Customization logic for OMML (if needed)
puts "OMML: #{omml}"
# Output: "<m:oMathPara xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math'><m:oMath><m:r><m:t>h</m:t></m:r><m:r><m:t>=</m:t></m:r><m:r><m:t>6.62607015</m:t></m:r><m:r><m:t>×</m:t></m:r><m:sSup><m:sSupPr><m:ctrlPr /></m:sSupPr><m:e><m:r><m:t>10</m:t></m:r></m:e><m:sup><m:r><m:t>−34</m:t></m:r></m:sup></m:sSup><m:r><m:t>kg·m²·s⁻¹</m:t></m:r></m:oMath></m:oMathPara>"

Compatibility

General

Not every math representation language supports expressing all symbols and primitives supported by another. For example, the backepsilon symbol is supported by LaTeX and UnicodeMath, but not AsciiMath.

Plurimath implements a "compatibility wrapper" syntax for each math representation language to allow all symbols usable by Plurimath to be expressed in a side-effect-free wrapper in those languages. For example, in AsciiMath, the "{symbol-name}" is side-effect-free because it is considered a single symbol as a text string of "{symbol-name}". Plurimath can recognize it, but other renderers or processors would treat it as a single symbol, which is accurate.

Usage of the compatibility wrapper

For a symbol like backepsilon.

In AsciiMath:

"__{backepsilon}"

In LaTeX:

"\\backepsilon"

In UnicodeMath:

"∍"

In MathML:

<mi>∍</mi>

XML engines

Plurimath supports two XML engines:

  1. Ox: (default) A fast XML parser

  2. Oga: A pure Ruby XML parser

By default, Ox is used.

To switch to Oga, use the following syntax:

require "plurimath/xml_engines/oga"
Plurimath.xml_engine = Plurimath::XmlEngine::Oga

You can switch back to Ox similarly.

Supported content

General

Consult the following tables for details on supported symbols and parentheses:

The following table shows the classes that support MathML "intent" encoding:

Note
To regenerate these files, delete them and run: bundle exec rake supported_symbols_list.adoc.

Copyright Ribose. BSD 2-clause license.