plurimath 0.11.1 → 0.11.3

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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop_todo.yml +108 -175
  4. data/Gemfile +1 -0
  5. data/README.adoc +282 -6
  6. data/lib/plurimath/asciimath/parse.rb +6 -1
  7. data/lib/plurimath/asciimath/transform.rb +2 -0
  8. data/lib/plurimath/base_number_prefix.rb +43 -0
  9. data/lib/plurimath/configuration.rb +9 -1
  10. data/lib/plurimath/errors/evaluation/division_by_zero_error.rb +13 -0
  11. data/lib/plurimath/errors/evaluation/error.rb +9 -0
  12. data/lib/plurimath/errors/evaluation/invalid_binding_error.rb +14 -0
  13. data/lib/plurimath/errors/evaluation/invalid_binding_key_error.rb +14 -0
  14. data/lib/plurimath/errors/evaluation/math_domain_error.rb +9 -0
  15. data/lib/plurimath/errors/evaluation/missing_variable_error.rb +13 -0
  16. data/lib/plurimath/errors/evaluation/non_finite_result_error.rb +13 -0
  17. data/lib/plurimath/errors/evaluation/unsupported_expression_error.rb +13 -0
  18. data/lib/plurimath/errors/evaluation.rb +18 -0
  19. data/lib/plurimath/errors.rb +1 -0
  20. data/lib/plurimath/formatter/numbers/base_notation.rb +54 -31
  21. data/lib/plurimath/formatter/numbers/formatted_notation.rb +62 -0
  22. data/lib/plurimath/formatter/numbers/formatted_number.rb +87 -0
  23. data/lib/plurimath/formatter/numbers/fraction.rb +1 -1
  24. data/lib/plurimath/formatter/numbers/mathml_renderer.rb +56 -0
  25. data/lib/plurimath/formatter/numbers/notation_renderer.rb +30 -29
  26. data/lib/plurimath/formatter/numbers/number_renderer.rb +10 -9
  27. data/lib/plurimath/formatter/numbers/omml_renderer.rb +74 -0
  28. data/lib/plurimath/formatter/numbers/source.rb +29 -4
  29. data/lib/plurimath/formatter/numbers/text_renderer.rb +52 -0
  30. data/lib/plurimath/formatter/numbers.rb +6 -2
  31. data/lib/plurimath/html/parse.rb +5 -0
  32. data/lib/plurimath/html/transform.rb +2 -0
  33. data/lib/plurimath/latex/parse.rb +5 -0
  34. data/lib/plurimath/latex/transform.rb +2 -0
  35. data/lib/plurimath/math/core.rb +52 -0
  36. data/lib/plurimath/math/evaluation/evaluator.rb +147 -0
  37. data/lib/plurimath/math/evaluation/expression_parser.rb +215 -0
  38. data/lib/plurimath/math/evaluation/iteration.rb +63 -0
  39. data/lib/plurimath/math/evaluation.rb +13 -0
  40. data/lib/plurimath/math/formula.rb +9 -0
  41. data/lib/plurimath/math/function/abs.rb +4 -0
  42. data/lib/plurimath/math/function/arccos.rb +4 -0
  43. data/lib/plurimath/math/function/arcsin.rb +4 -0
  44. data/lib/plurimath/math/function/arctan.rb +4 -0
  45. data/lib/plurimath/math/function/ceil.rb +4 -0
  46. data/lib/plurimath/math/function/cos.rb +4 -0
  47. data/lib/plurimath/math/function/cosh.rb +4 -0
  48. data/lib/plurimath/math/function/cot.rb +4 -0
  49. data/lib/plurimath/math/function/coth.rb +4 -0
  50. data/lib/plurimath/math/function/csc.rb +4 -0
  51. data/lib/plurimath/math/function/csch.rb +4 -0
  52. data/lib/plurimath/math/function/exp.rb +4 -0
  53. data/lib/plurimath/math/function/fenced.rb +4 -0
  54. data/lib/plurimath/math/function/floor.rb +4 -0
  55. data/lib/plurimath/math/function/frac.rb +7 -0
  56. data/lib/plurimath/math/function/gcd.rb +9 -0
  57. data/lib/plurimath/math/function/lcm.rb +9 -0
  58. data/lib/plurimath/math/function/lg.rb +4 -0
  59. data/lib/plurimath/math/function/ln.rb +4 -0
  60. data/lib/plurimath/math/function/log.rb +19 -0
  61. data/lib/plurimath/math/function/max.rb +4 -0
  62. data/lib/plurimath/math/function/min.rb +4 -0
  63. data/lib/plurimath/math/function/mod.rb +15 -0
  64. data/lib/plurimath/math/function/power.rb +10 -0
  65. data/lib/plurimath/math/function/prod.rb +10 -0
  66. data/lib/plurimath/math/function/root.rb +7 -0
  67. data/lib/plurimath/math/function/sec.rb +4 -0
  68. data/lib/plurimath/math/function/sech.rb +4 -0
  69. data/lib/plurimath/math/function/sin.rb +4 -0
  70. data/lib/plurimath/math/function/sinh.rb +4 -0
  71. data/lib/plurimath/math/function/sqrt.rb +4 -0
  72. data/lib/plurimath/math/function/sum.rb +10 -0
  73. data/lib/plurimath/math/function/tan.rb +4 -0
  74. data/lib/plurimath/math/function/tanh.rb +4 -0
  75. data/lib/plurimath/math/function/text.rb +17 -0
  76. data/lib/plurimath/math/number.rb +40 -29
  77. data/lib/plurimath/math/symbols/cdot.rb +4 -0
  78. data/lib/plurimath/math/symbols/div.rb +4 -0
  79. data/lib/plurimath/math/symbols/hat.rb +4 -0
  80. data/lib/plurimath/math/symbols/minus.rb +4 -0
  81. data/lib/plurimath/math/symbols/pi.rb +5 -1
  82. data/lib/plurimath/math/symbols/plus.rb +4 -0
  83. data/lib/plurimath/math/symbols/slash.rb +4 -0
  84. data/lib/plurimath/math/symbols/symbol.rb +45 -0
  85. data/lib/plurimath/math/symbols/times.rb +4 -0
  86. data/lib/plurimath/math.rb +1 -0
  87. data/lib/plurimath/mathml/constants.rb +18 -0
  88. data/lib/plurimath/number_formatter.rb +47 -28
  89. data/lib/plurimath/setup/opal.rb.erb +13 -0
  90. data/lib/plurimath/unicode_math/parse.rb +5 -1
  91. data/lib/plurimath/unicode_math/transform.rb +469 -755
  92. data/lib/plurimath/utility.rb +1 -1
  93. data/lib/plurimath/version.rb +1 -1
  94. data/lib/plurimath.rb +1 -0
  95. metadata +21 -3
  96. data/lib/plurimath/formatter/numbers/parts_renderer.rb +0 -30
@@ -353,6 +353,58 @@ namespace: "m")
353
353
  false
354
354
  end
355
355
 
356
+ def plus_operator?
357
+ false
358
+ end
359
+
360
+ def minus_operator?
361
+ false
362
+ end
363
+
364
+ def multiply_operator?
365
+ false
366
+ end
367
+
368
+ def divide_operator?
369
+ false
370
+ end
371
+
372
+ def power_operator?
373
+ false
374
+ end
375
+
376
+ def operator?
377
+ plus_operator? || minus_operator? || multiply_operator? ||
378
+ divide_operator? || power_operator?
379
+ end
380
+
381
+ def reserved_constant
382
+ nil
383
+ end
384
+
385
+ # Default evaluation entry point: a node that does not implement a
386
+ # numeric evaluation raises UnsupportedExpressionError. Concrete nodes
387
+ # (Number, Symbol operators, Function::*) override this.
388
+ def evaluate(evaluator)
389
+ evaluator.unsupported(self)
390
+ end
391
+
392
+ def open?
393
+ false
394
+ end
395
+
396
+ def close?
397
+ false
398
+ end
399
+
400
+ # The bound variable a node represents, or nil if it is not a plain
401
+ # variable. Symbols and text nodes that name a variable override this;
402
+ # it lets iteration indexes accept both `Symbols::Symbol` (AsciiMath/
403
+ # MathML) and `Function::Text` (OMML) without type-sniffing.
404
+ def variable_name
405
+ nil
406
+ end
407
+
356
408
  def unicodemath_parens(field, options:)
357
409
  paren = field.to_unicodemath(options: options)
358
410
  return paren if field.is_a?(Math::Function::Fenced)
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ module Math
5
+ module Evaluation
6
+ # Computes the numeric value of a Formula tree against variable
7
+ # bindings, enforcing the strict error contract: results are always
8
+ # real, finite numbers or one of the Errors::Evaluation classes is
9
+ # raised.
10
+ class Evaluator
11
+ def initialize(formula, bindings = {})
12
+ @formula = formula
13
+ @bindings = normalize_bindings(bindings)
14
+ end
15
+
16
+ def evaluate
17
+ result = begin
18
+ evaluate_formula(@formula)
19
+ rescue ::Math::DomainError => e
20
+ raise Errors::Evaluation::MathDomainError, e.message
21
+ rescue ::FloatDomainError
22
+ raise Errors::Evaluation::NonFiniteResultError
23
+ rescue ::ZeroDivisionError
24
+ raise Errors::Evaluation::DivisionByZeroError
25
+ end
26
+
27
+ raise Errors::Evaluation::NonFiniteResultError unless result.finite?
28
+
29
+ result
30
+ end
31
+
32
+ def evaluate_formula(formula)
33
+ real_result(ExpressionParser.new(self, formula.value).parse)
34
+ end
35
+
36
+ def evaluate_nodes(nodes)
37
+ evaluate_formula(Formula.new(Array(nodes)))
38
+ end
39
+
40
+ def evaluate_node(node)
41
+ case node
42
+ when nil
43
+ unsupported("missing operand")
44
+ when Formula
45
+ evaluate_formula(node)
46
+ else
47
+ real_result(node.evaluate(self))
48
+ end
49
+ end
50
+
51
+ def value_for(name)
52
+ raise Errors::Evaluation::MissingVariableError, name unless bindings.key?(name)
53
+
54
+ bindings[name]
55
+ end
56
+
57
+ def divide(dividend, divisor)
58
+ raise Errors::Evaluation::DivisionByZeroError if divisor.zero?
59
+
60
+ dividend / divisor.to_f
61
+ end
62
+
63
+ def modulo(dividend, divisor)
64
+ raise Errors::Evaluation::DivisionByZeroError if divisor.zero?
65
+
66
+ dividend % divisor
67
+ end
68
+
69
+ def power(base, exponent)
70
+ real_result(base**exponent)
71
+ end
72
+
73
+ # Non-real values are rejected per subexpression so they cannot reach
74
+ # other numeric operations. Non-finite values are only rejected on the
75
+ # final result, so correct asymptotic values like `1/exp(1000)` still
76
+ # evaluate.
77
+ def real_result(value)
78
+ raise Errors::Evaluation::MathDomainError, "result is not a real number" unless value.real?
79
+
80
+ value
81
+ end
82
+
83
+ # Comma-separated argument lists for functions like `max(2,3)`.
84
+ def evaluate_arguments(nodes)
85
+ split_on_commas(Array(nodes)).map { |segment| evaluate_nodes(segment) }
86
+ end
87
+
88
+ def function_arguments(node)
89
+ return evaluate_arguments(node.parameter_two) if node.is_a?(Function::Fenced)
90
+
91
+ evaluate_arguments(Array(node))
92
+ end
93
+
94
+ # Temporarily binds an iteration index, shadowing any outer binding
95
+ # of the same name and restoring it afterwards.
96
+ def with_binding(name, value)
97
+ had_key = bindings.key?(name)
98
+ previous = bindings[name]
99
+ bindings[name] = value
100
+ yield
101
+ ensure
102
+ had_key ? bindings[name] = previous : bindings.delete(name)
103
+ end
104
+
105
+ def unsupported(node_or_message)
106
+ raise Errors::Evaluation::UnsupportedExpressionError, unsupported_message(node_or_message)
107
+ end
108
+
109
+ private
110
+
111
+ attr_reader :bindings
112
+
113
+ def normalize_bindings(bindings)
114
+ bindings.to_hash.each_with_object({}) do |(key, value), normalized|
115
+ unless key.is_a?(String) || key.is_a?(Symbol)
116
+ raise Errors::Evaluation::InvalidBindingKeyError, key
117
+ end
118
+ unless value.is_a?(Numeric) && value.real?
119
+ raise Errors::Evaluation::InvalidBindingError.new(key, value)
120
+ end
121
+
122
+ normalized[key.to_s] = value
123
+ end
124
+ end
125
+
126
+ def split_on_commas(nodes)
127
+ nodes.each_with_object([[]]) do |node, segments|
128
+ node.is_a?(Symbols::Comma) ? segments << [] : segments.last << node
129
+ end
130
+ end
131
+
132
+ def unsupported_message(node_or_message)
133
+ return node_or_message if node_or_message.is_a?(String)
134
+ return "equation" if node_or_message.is_a?(Symbols::Equal)
135
+ return "number `#{node_or_message.value}`" if node_or_message.is_a?(Number)
136
+
137
+ if node_or_message.instance_of?(Symbols::Symbol) &&
138
+ node_or_message.value.to_s != ""
139
+ return "symbol `#{node_or_message.value}`"
140
+ end
141
+
142
+ node_or_message.class.name.sub(/^Plurimath::Math::/, "")
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,215 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ module Math
5
+ module Evaluation
6
+ # Resolves operator precedence over the flat token sequences stored in
7
+ # Formula#value, delegating node evaluation back to the evaluator.
8
+ #
9
+ # Standard recursive-descent precedence ladder — each level parses its
10
+ # operands at the next-tighter level, so the operands of `+`/`-` are
11
+ # whole multiplicative expressions, and so on down to single operands:
12
+ # parse_additive -> parse_multiplicative -> parse_unary
13
+ # -> parse_power -> parse_operand
14
+ class ExpressionParser
15
+ def initialize(evaluator, tokens)
16
+ @evaluator = evaluator
17
+ @tokens = tokens
18
+ @index = 0
19
+ end
20
+
21
+ def parse
22
+ result = parse_additive
23
+ evaluator.unsupported(current) unless eof?
24
+
25
+ result
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :evaluator, :tokens
31
+
32
+ def parse_additive
33
+ result = parse_multiplicative
34
+ loop do
35
+ if take?(:plus_operator?)
36
+ result += parse_multiplicative
37
+ elsif take?(:minus_operator?)
38
+ result -= parse_multiplicative
39
+ else
40
+ break result
41
+ end
42
+ end
43
+ end
44
+
45
+ def parse_multiplicative
46
+ result = parse_unary
47
+ loop do
48
+ if take?(:multiply_operator?)
49
+ result *= parse_unary
50
+ elsif take?(:divide_operator?)
51
+ result = evaluator.divide(result, parse_unary)
52
+ elsif implicit_multiplication?
53
+ result *= parse_power
54
+ else
55
+ break result
56
+ end
57
+ end
58
+ end
59
+
60
+ def parse_unary
61
+ if take?(:plus_operator?)
62
+ parse_unary
63
+ elsif take?(:minus_operator?)
64
+ negated_unary
65
+ else
66
+ parse_power
67
+ end
68
+ end
69
+
70
+ # Unary minus binds tighter than `mod`, so `-7 mod 3` negates the
71
+ # dividend, not the result: `(-7) mod 3 == 2`, not `-(7 mod 3)`.
72
+ def negated_unary
73
+ return next_token.evaluate_negated(evaluator) if current.is_a?(Function::Mod)
74
+
75
+ -parse_unary
76
+ end
77
+
78
+ # Chained powers evaluate left-to-right, matching the left-nested
79
+ # trees parsers build for chains like `2^3^2`.
80
+ def parse_power
81
+ result = parse_operand
82
+ result = evaluator.power(result, parse_exponent) while take?(:power_operator?)
83
+ result
84
+ end
85
+
86
+ def parse_exponent
87
+ if take?(:plus_operator?)
88
+ parse_exponent
89
+ elsif take?(:minus_operator?)
90
+ negated_exponent
91
+ else
92
+ parse_operand
93
+ end
94
+ end
95
+
96
+ def negated_exponent
97
+ return next_token.evaluate_negated(evaluator) if current.is_a?(Function::Mod)
98
+
99
+ -parse_exponent
100
+ end
101
+
102
+ def parse_operand
103
+ evaluator.unsupported("empty expression") if eof?
104
+ return parse_group if open_paren?(current)
105
+
106
+ node = next_token
107
+ return bind_argument(node) if next_argument?(node)
108
+ return bind_log_argument(node) if log_argument?(node)
109
+
110
+ node = bind_nary_body(node) if nary_body?(node)
111
+ evaluator.evaluate_node(node)
112
+ end
113
+
114
+ # A non-close token before the close paren is reported as itself;
115
+ # "unmatched parenthesis" is reserved for true end-of-input.
116
+ def parse_group
117
+ advance
118
+ result = parse_additive
119
+ evaluator.unsupported(current || "unmatched parenthesis") unless close_paren?(current)
120
+
121
+ advance
122
+ result
123
+ end
124
+
125
+ # Unary functions and `log` parse separately from their argument in
126
+ # some syntaxes; both bind the following fenced group.
127
+ def next_argument?(node)
128
+ node.is_a?(Function::UnaryFunction) && node.parameter_one.nil? &&
129
+ current.is_a?(Function::Fenced)
130
+ end
131
+
132
+ def bind_argument(node)
133
+ evaluator.evaluate_node(node.class.new(next_token))
134
+ end
135
+
136
+ # MathML/OMML n-ary Sum/Prod carry their bounds but leave the body as
137
+ # the following sibling token; AsciiMath binds a single operand as the
138
+ # body, so we match by adopting the next operand as parameter_three.
139
+ def nary_body?(node)
140
+ (node.is_a?(Function::Sum) || node.is_a?(Function::Prod)) &&
141
+ node.parameter_three.nil? &&
142
+ node.parameter_one && node.parameter_two &&
143
+ !eof? && operand_start?(current)
144
+ end
145
+
146
+ # The body is a single following operand; if that operand is itself a
147
+ # sibling-body Sum/Prod (e.g. nested MathML `sum sum …`), complete it
148
+ # recursively so the inner body binds too.
149
+ def bind_nary_body(node)
150
+ body = next_token
151
+ body = bind_nary_body(body) if nary_body?(body)
152
+ node.class.new(node.parameter_one, node.parameter_two, body)
153
+ end
154
+
155
+ def log_argument?(node)
156
+ node.is_a?(Function::Log) && current.is_a?(Function::Fenced)
157
+ end
158
+
159
+ def bind_log_argument(node)
160
+ evaluator.real_result(node.evaluate_with_argument(evaluator, next_token))
161
+ end
162
+
163
+ # Adjacent operands multiply by juxtaposition (`2a`, `2(a+b)`), except
164
+ # two adjacent numeric literals, which usually indicate a split number
165
+ # literal. Signs are never consumed implicitly.
166
+ def implicit_multiplication?
167
+ operand_start?(current) &&
168
+ !(current.is_a?(Number) && tokens[@index - 1].is_a?(Number))
169
+ end
170
+
171
+ def operand_start?(node)
172
+ return false if node.nil? || node.operator?
173
+
174
+ !close_paren?(node)
175
+ end
176
+
177
+ def take?(predicate)
178
+ return false if eof? || !current.public_send(predicate)
179
+
180
+ advance
181
+ true
182
+ end
183
+
184
+ def next_token
185
+ token = current
186
+ advance
187
+ token
188
+ end
189
+
190
+ def open_paren?(node)
191
+ node&.open?
192
+ end
193
+
194
+ def close_paren?(node)
195
+ node&.close?
196
+ end
197
+
198
+ def current
199
+ token = tokens[@index]
200
+ evaluator.unsupported("malformed token") unless token.nil? || token.is_a?(Core)
201
+
202
+ token
203
+ end
204
+
205
+ def advance
206
+ @index += 1
207
+ end
208
+
209
+ def eof?
210
+ @index >= tokens.length
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Plurimath
4
+ module Math
5
+ module Evaluation
6
+ # Evaluates bounded Sum/Prod iterations: parses the `i=1` lower bound,
7
+ # validates the integer bounds and step limit, then folds the body with
8
+ # the index temporarily bound.
9
+ class Iteration
10
+ def initialize(evaluator, lower, upper, body)
11
+ @evaluator = evaluator
12
+ @lower = lower
13
+ @upper = upper
14
+ @body = body
15
+ end
16
+
17
+ def accumulate(initial, operation)
18
+ name, from = index_definition
19
+ to = evaluator.evaluate_node(upper)
20
+ validate_bounds(from, to)
21
+
22
+ (from..to).reduce(initial) do |accumulator, index|
23
+ accumulator.public_send(operation, body_value(name, index))
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :evaluator, :lower, :upper, :body
30
+
31
+ # Parses `i=1` style lower bounds into the index name and its start.
32
+ def index_definition
33
+ tokens = lower.is_a?(Formula) ? lower.value : Array(lower)
34
+ index = tokens.first
35
+ if index.is_a?(Core) && index.reserved_constant
36
+ evaluator.unsupported("reserved constant as iteration index")
37
+ end
38
+ name = index.is_a?(Core) ? index.variable_name : nil
39
+ unless name && tokens[1].is_a?(Symbols::Equal)
40
+ evaluator.unsupported("malformed iteration bounds")
41
+ end
42
+
43
+ [name, evaluator.evaluate_nodes(tokens[2..])]
44
+ end
45
+
46
+ def validate_bounds(from, to)
47
+ unless from.is_a?(Integer) && to.is_a?(Integer)
48
+ raise Errors::Evaluation::MathDomainError, "iteration bounds must be integers"
49
+ end
50
+
51
+ limit = Plurimath.configuration.evaluation_max_iterations
52
+ return if limit.nil? || (to - from + 1) <= limit
53
+
54
+ evaluator.unsupported("iteration range larger than #{limit} steps")
55
+ end
56
+
57
+ def body_value(name, index)
58
+ evaluator.with_binding(name, index) { evaluator.evaluate_node(body) }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "plurimath/errors/evaluation"
4
+
5
+ module Plurimath
6
+ module Math
7
+ module Evaluation
8
+ autoload :Evaluator, "#{__dir__}/evaluation/evaluator"
9
+ autoload :ExpressionParser, "#{__dir__}/evaluation/expression_parser"
10
+ autoload :Iteration, "#{__dir__}/evaluation/iteration"
11
+ end
12
+ end
13
+ end
@@ -54,6 +54,15 @@ module Plurimath
54
54
  object.left_right_wrapper == left_right_wrapper
55
55
  end
56
56
 
57
+ def evaluate(bindings = {})
58
+ hash = bindings.to_hash if bindings.respond_to?(:to_hash)
59
+ unless hash.is_a?(Hash)
60
+ raise ArgumentError, "bindings must be a Hash-like object"
61
+ end
62
+
63
+ Evaluation::Evaluator.new(self, hash).evaluate
64
+ end
65
+
57
66
  def to_asciimath(formatter: nil, unitsml: {}, options: nil)
58
67
  options ||= { formatter: formatter, unitsml: unitsml }.compact
59
68
  options[:formula] ||= self
@@ -39,6 +39,10 @@ module Plurimath
39
39
  "⒜#{unicodemath_parens(parameter_one, options: options)}"
40
40
  end
41
41
 
42
+ def evaluate(evaluator)
43
+ evaluator.evaluate_node(parameter_one).abs
44
+ end
45
+
42
46
  def intent_names
43
47
  { name: "absolute-value" }
44
48
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ ::Math.acos(evaluator.evaluate_node(parameter_one))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ ::Math.asin(evaluator.evaluate_node(parameter_one))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ ::Math.atan(evaluator.evaluate_node(parameter_one))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -39,6 +39,10 @@ module Plurimath
39
39
  "#{first_value}#{parameter_one&.to_unicodemath(options: options)}#{second_value}"
40
40
  end
41
41
 
42
+ def evaluate(evaluator)
43
+ evaluator.evaluate_node(parameter_one).ceil
44
+ end
45
+
42
46
  def line_breaking(obj)
43
47
  parameter_one.line_breaking(obj)
44
48
  if obj.value_exist?
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ ::Math.cos(evaluator.evaluate_node(parameter_one))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ ::Math.cosh(evaluator.evaluate_node(parameter_one))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ evaluator.divide(1.0, ::Math.tan(evaluator.evaluate_node(parameter_one)))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ evaluator.divide(1.0, ::Math.tanh(evaluator.evaluate_node(parameter_one)))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ evaluator.divide(1.0, ::Math.sin(evaluator.evaluate_node(parameter_one)))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -7,6 +7,10 @@ module Plurimath
7
7
  def validate_function_formula
8
8
  false
9
9
  end
10
+
11
+ def evaluate(evaluator)
12
+ evaluator.divide(1.0, ::Math.sinh(evaluator.evaluate_node(parameter_one)))
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -8,6 +8,10 @@ module Plurimath
8
8
  false
9
9
  end
10
10
 
11
+ def evaluate(evaluator)
12
+ ::Math.exp(evaluator.evaluate_node(parameter_one))
13
+ end
14
+
11
15
  def to_omml_without_math_tag(display_style, options:)
12
16
  array = []
13
17
  array << r_element("exp", rpr_tag: false) unless hide_function_name
@@ -116,6 +116,10 @@ module Plurimath
116
116
  "#{unicode_open_paren(options: options)}#{fenced_value}#{unicode_close_paren(options: options)}"
117
117
  end
118
118
 
119
+ def evaluate(evaluator)
120
+ evaluator.evaluate_nodes(parameter_two)
121
+ end
122
+
119
123
  def to_asciimath_math_zone(spacing, last = false, indent = true,
120
124
  options:)
121
125
  filtered_values(parameter_two,
@@ -36,6 +36,10 @@ module Plurimath
36
36
  "#{first_value}#{parameter_one&.to_unicodemath(options: options)}#{second_value}"
37
37
  end
38
38
 
39
+ def evaluate(evaluator)
40
+ evaluator.evaluate_node(parameter_one).floor
41
+ end
42
+
39
43
  def line_breaking(obj)
40
44
  parameter_one.line_breaking(obj)
41
45
  if obj.value_exist?