latex_eval 0.1.0
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 +7 -0
- data/README.md +86 -0
- data/lib/latex_eval.rb +21 -0
- data/lib/latex_eval/equation.rb +104 -0
- data/lib/latex_eval/latex.rb +128 -0
- data/lib/latex_eval/postfix_notation.rb +61 -0
- data/test/equation_test.rb +169 -0
- data/test/latex_eval_test.rb +14 -0
- data/test/latex_test.rb +134 -0
- data/test/postfix_notation_test.rb +54 -0
- metadata +87 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d0562d9054359a1d2a318e8dec10943b3a56bb8a
|
4
|
+
data.tar.gz: a1ff0986f7fd46f1c6a8adf4a07656a533b19ece
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 63370a4e0a0f39c47de118b18d695c77b0e10fb62ad38d7507ab0eb2c1991f52c086965826be26c327f8a95cae88b82c35a2a8552dde0fbf8f13d84d8c6d0702
|
7
|
+
data.tar.gz: d4d0b786b24b969ea3adfc9cba2a64c3d632ba4b7db8de44326608e676fff90fc4a5d591f7dd63b067cf935da4aa20120d22b2ae3fd2944b50ad9d8ad7157279
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# latex\_eval
|
2
|
+
|
3
|
+
This gem can be used to safely evaluate simple latex expressions.
|
4
|
+
|
5
|
+
For example, if you want to evaluate `\frac{\xi}{2}+3` where `\xi = 3` you can do
|
6
|
+
|
7
|
+
LatexEval.eval('\frac{\xi}{2}+3', {xi: 3})
|
8
|
+
|
9
|
+
However, if you are going to be evaluating the expression many times, it is best to save the postfix notation first.
|
10
|
+
|
11
|
+
postfix = LatexEval.postfix_notation('\frac{\xi}{2}+3')
|
12
|
+
LatexEval::PostfixNotation.eval(postfix, {xi: 3})
|
13
|
+
|
14
|
+
This gem is made up of 3 classes. `Latex`, `Equation`, and `PostfixNotation`. I will explain their uses.
|
15
|
+
|
16
|
+
## Latex
|
17
|
+
|
18
|
+
The latex class is used to convert your latex into an equation. For example,
|
19
|
+
|
20
|
+
LatexEval::Latex.new('\frac{\xi}{2}+3').equation
|
21
|
+
|
22
|
+
will output `((xi)/(2)+3)`.
|
23
|
+
|
24
|
+
Currently, the `equation` method for the `Latex` class supports the following latex expressions:
|
25
|
+
|
26
|
+
- capital and lowercase Greek letters (`\alpha`, `\Beta`, etc.)
|
27
|
+
- single letter variables (`a`, `b`, ..., `z`)
|
28
|
+
- fractions in the form of `\frac{}{}` and `\dfrac{}{}`
|
29
|
+
- roots in the form `\sqrt{}` and `\sqrt[]{}`
|
30
|
+
- binary operators
|
31
|
+
- multiplication (\*, `\cdot`, `\times`)
|
32
|
+
- division(/)
|
33
|
+
- powers (^)
|
34
|
+
- modulus (%)
|
35
|
+
- addition (+)
|
36
|
+
- subtraction (-)
|
37
|
+
- unary operators
|
38
|
+
- positive (+)
|
39
|
+
- negative (-)
|
40
|
+
|
41
|
+
## Equation
|
42
|
+
|
43
|
+
The equation class is used to convert your equations into postfix notation. For example,
|
44
|
+
|
45
|
+
LatexEval::Equation.new('((xi)/(2)+3)').postfix_notation
|
46
|
+
|
47
|
+
will output `[3, :xi, 2, :divide, :add]`.
|
48
|
+
|
49
|
+
Currently, the `postfix_notation` method for the `Equation` class can interpret
|
50
|
+
|
51
|
+
- brackets
|
52
|
+
- binary operators
|
53
|
+
- multiplication (\*)
|
54
|
+
- division(/)
|
55
|
+
- powers (^)
|
56
|
+
- modulus (%)
|
57
|
+
- addition (+)
|
58
|
+
- subtraction (-)
|
59
|
+
- unary operators
|
60
|
+
- positive (+)
|
61
|
+
- negative (-)
|
62
|
+
|
63
|
+
and will adhere to the generally accepted order of operations.
|
64
|
+
|
65
|
+
## PostfixNotation
|
66
|
+
|
67
|
+
The postfix equation class is used to safely evaluate postfix notation. For example,
|
68
|
+
|
69
|
+
LatexEval::PostfixNotation.new([3, :xi, 2, :divide, :add]).eval({xi: 3})
|
70
|
+
|
71
|
+
will output `4.5`.
|
72
|
+
|
73
|
+
The `eval` method accepts one argument, which is a hash of variable values.
|
74
|
+
|
75
|
+
Currently, the `eval` method for the `PostfixNotation` class can interpret
|
76
|
+
|
77
|
+
- binary operators
|
78
|
+
- :multiply
|
79
|
+
- :divide
|
80
|
+
- :power
|
81
|
+
- :mod
|
82
|
+
- :add
|
83
|
+
- :subtract
|
84
|
+
- unary operators
|
85
|
+
- :positive
|
86
|
+
- :negative
|
data/lib/latex_eval.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative "./latex_eval/equation.rb"
|
2
|
+
require_relative "./latex_eval/postfix_notation.rb"
|
3
|
+
require_relative "./latex_eval/latex.rb"
|
4
|
+
|
5
|
+
module LatexEval
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def eval(latex, subs = {})
|
9
|
+
parsed_latex = LatexEval::Latex.new(latex).equation
|
10
|
+
parsed_notation = LatexEval::Equation.new(parsed_latex).postfix_notation
|
11
|
+
eval_latex = LatexEval::PostfixNotation.new(parsed_notation)
|
12
|
+
|
13
|
+
return eval_latex.eval(subs)
|
14
|
+
end
|
15
|
+
|
16
|
+
def postfix_notation(latex)
|
17
|
+
equation = LatexEval::Latex.new(latex).equation
|
18
|
+
return LatexEval::Equation.new(equation).postfix_notation
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module LatexEval
|
2
|
+
class Equation
|
3
|
+
|
4
|
+
attr_reader :binary_key, :equation, :unary_key
|
5
|
+
|
6
|
+
def initialize(equation)
|
7
|
+
@equation = equation
|
8
|
+
@binary_key = {
|
9
|
+
"+" => {
|
10
|
+
symbol: :add,
|
11
|
+
priority: 0,
|
12
|
+
right_priority: false
|
13
|
+
},
|
14
|
+
"-" => {
|
15
|
+
symbol: :subtract,
|
16
|
+
priority: 0,
|
17
|
+
right_priority: false
|
18
|
+
},
|
19
|
+
"*" => {
|
20
|
+
symbol: :multiply,
|
21
|
+
priority: 1,
|
22
|
+
right_priority: false
|
23
|
+
},
|
24
|
+
"/" => {
|
25
|
+
symbol: :divide,
|
26
|
+
priority: 1,
|
27
|
+
right_priority: false
|
28
|
+
},
|
29
|
+
"%" => {
|
30
|
+
symbol: :mod,
|
31
|
+
priority: 1,
|
32
|
+
right_priority: false
|
33
|
+
},
|
34
|
+
"^" => {
|
35
|
+
symbol: :power,
|
36
|
+
priority: 2,
|
37
|
+
right_priority: true
|
38
|
+
}
|
39
|
+
}
|
40
|
+
@unary_key = {
|
41
|
+
"-" => {
|
42
|
+
symbol: :negative,
|
43
|
+
},
|
44
|
+
"+" => {
|
45
|
+
symbol: :positive,
|
46
|
+
},
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def postfix_notation
|
51
|
+
out = []
|
52
|
+
bank = []
|
53
|
+
bracket = []
|
54
|
+
unary = []
|
55
|
+
|
56
|
+
# start with an assumed array
|
57
|
+
bank.push []
|
58
|
+
bracket.push []
|
59
|
+
unary.push []
|
60
|
+
|
61
|
+
equation.gsub(" ", "").split(/([%\)\(\^*+-\/])/).each do |value|
|
62
|
+
if value != ""
|
63
|
+
if value == "("
|
64
|
+
bank.push []
|
65
|
+
bracket.push []
|
66
|
+
unary.push []
|
67
|
+
elsif value == ")"
|
68
|
+
last = bracket.pop()
|
69
|
+
bracket.last.concat last
|
70
|
+
bracket.last.concat bank.pop().reverse.map { |e| binary_key[e][:symbol] }
|
71
|
+
bracket.last.concat unary.pop().reverse.map { |e| unary_key[e][:symbol] }
|
72
|
+
elsif unary_key.has_key? value and (bracket.last.empty? || bracket.last.length == bank.last.length)
|
73
|
+
unary.last.push value
|
74
|
+
elsif binary_key.has_key? value
|
75
|
+
num_popped = 0
|
76
|
+
bank.last.reverse_each do |b|
|
77
|
+
if (binary_key[b][:right_priority] ? binary_key[b][:priority] > binary_key[value][:priority] : binary_key[b][:priority] >= binary_key[value][:priority])
|
78
|
+
num_popped += 1
|
79
|
+
else
|
80
|
+
break
|
81
|
+
end
|
82
|
+
end
|
83
|
+
bracket.last.concat unary.pop().reverse.map { |e| unary_key[e][:symbol] }
|
84
|
+
unary.push []
|
85
|
+
bracket.last.concat bank.last.pop(num_popped).reverse.map { |e| binary_key[e][:symbol] }
|
86
|
+
bank.last.push value
|
87
|
+
else
|
88
|
+
if /[a-zA-Z]+/.match(value)
|
89
|
+
bracket.last.push value.to_sym
|
90
|
+
else
|
91
|
+
bracket.last.push value.to_f
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
out.concat bracket.pop()
|
98
|
+
out.concat unary.pop().reverse.map { |e| unary_key[e][:symbol] }
|
99
|
+
out.concat bank.pop().reverse.map { |e| binary_key[e][:symbol] }
|
100
|
+
|
101
|
+
return out
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module LatexEval
|
2
|
+
class Latex
|
3
|
+
attr_reader :latex, :greek_letters
|
4
|
+
|
5
|
+
def initialize(latex)
|
6
|
+
@latex = latex
|
7
|
+
@greek_letters = [
|
8
|
+
'Alpha',
|
9
|
+
'alpha',
|
10
|
+
'Beta',
|
11
|
+
'beta',
|
12
|
+
'Gamma',
|
13
|
+
'gamma',
|
14
|
+
'Delta',
|
15
|
+
'delta',
|
16
|
+
'Epsilon',
|
17
|
+
'epsilon',
|
18
|
+
'varepsilon',
|
19
|
+
'Zeta',
|
20
|
+
'zeta',
|
21
|
+
'Eta',
|
22
|
+
'eta',
|
23
|
+
'Theta',
|
24
|
+
'theta',
|
25
|
+
'vartheta',
|
26
|
+
'Iota',
|
27
|
+
'iota',
|
28
|
+
'Kappa',
|
29
|
+
'kappa',
|
30
|
+
'varkappa',
|
31
|
+
'Lambda',
|
32
|
+
'lambda',
|
33
|
+
'Mu',
|
34
|
+
'mu',
|
35
|
+
'Nu',
|
36
|
+
'nu',
|
37
|
+
'Xi',
|
38
|
+
'xi',
|
39
|
+
'Omicron',
|
40
|
+
'omicron',
|
41
|
+
'Pi',
|
42
|
+
'pi',
|
43
|
+
'varpi',
|
44
|
+
'Rho',
|
45
|
+
'rho',
|
46
|
+
'varrho',
|
47
|
+
'Sigma',
|
48
|
+
'sigma',
|
49
|
+
'varsigma',
|
50
|
+
'Tau',
|
51
|
+
'tau',
|
52
|
+
'Upsilon',
|
53
|
+
'upsilon',
|
54
|
+
'Phi',
|
55
|
+
'phi',
|
56
|
+
'varphi',
|
57
|
+
'Chi',
|
58
|
+
'chi',
|
59
|
+
'Psi',
|
60
|
+
'psi',
|
61
|
+
'Omega',
|
62
|
+
'omega',
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
def equation
|
67
|
+
parsed = latex
|
68
|
+
|
69
|
+
parsed.gsub!(/\\left/, "")
|
70
|
+
parsed.gsub!(/\\right/, "")
|
71
|
+
|
72
|
+
# fractions
|
73
|
+
regex = /\\d?frac{(.*)}{(.*)}/
|
74
|
+
while parsed.match(regex)
|
75
|
+
parsed.gsub!(regex, '((\1)/(\2))')
|
76
|
+
end
|
77
|
+
|
78
|
+
# sqrt
|
79
|
+
regex = /\\sqrt{(.*)}/
|
80
|
+
while parsed.match(regex)
|
81
|
+
parsed.gsub!(regex, '((\1)^(1/2))')
|
82
|
+
end
|
83
|
+
|
84
|
+
# nth root
|
85
|
+
regex = /\\sqrt(\[?(.*)(?=\])\]?)?{(.*)}/
|
86
|
+
while parsed.match(regex)
|
87
|
+
parsed.gsub!(regex, '((\3)^(1/(\2)))')
|
88
|
+
end
|
89
|
+
|
90
|
+
# \cdot and \times should be *
|
91
|
+
parsed.gsub!(/\\cdot/, "*")
|
92
|
+
parsed.gsub!(/\\times/, "*")
|
93
|
+
|
94
|
+
# remove remaining curly brackets
|
95
|
+
parsed.gsub!(/{/, "(")
|
96
|
+
parsed.gsub!(/}/, ")")
|
97
|
+
|
98
|
+
# cleanup variable names and multiplication
|
99
|
+
greek_letters.each do |letter|
|
100
|
+
parsed.gsub!(/(\\#{letter})/, ' \1 ')
|
101
|
+
end
|
102
|
+
|
103
|
+
# cleans up xyz to x*y*z
|
104
|
+
regex = /((?<!\\)\b)([0-9]?[A-Za-z])([A-Za-z])/
|
105
|
+
while parsed.match(regex)
|
106
|
+
parsed.gsub!(regex, '\2*\3')
|
107
|
+
end
|
108
|
+
|
109
|
+
parsed.gsub!(/([0-9])\s+\\([A-Za-z])/, '\1*\2')
|
110
|
+
parsed.gsub!(/([0-9])\s*?([A-Za-z])/, '\1*\2')
|
111
|
+
|
112
|
+
parsed.gsub!(/([A-Za-z])\s+\\([A-Za-z])/, '\1*\2')
|
113
|
+
parsed.gsub!(/([A-Za-z])\s+([A-Za-z])/, '\1*\2')
|
114
|
+
|
115
|
+
parsed.gsub!(/([A-Za-z])\s+([0-9])/, '\1*\2')
|
116
|
+
parsed.gsub!(/([A-Za-z])([0-9])/, '\1*\2')
|
117
|
+
|
118
|
+
parsed.gsub!(/(\))(\()/, '\1*\2')
|
119
|
+
|
120
|
+
parsed.gsub!(/\\/, "")
|
121
|
+
|
122
|
+
# cleanup spaces
|
123
|
+
parsed.gsub!(" ", "")
|
124
|
+
|
125
|
+
return parsed
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module LatexEval
|
2
|
+
class PostfixNotation
|
3
|
+
attr_reader :notation, :operations
|
4
|
+
|
5
|
+
def initialize(notation)
|
6
|
+
@notation = notation
|
7
|
+
@operations = {
|
8
|
+
add: {
|
9
|
+
args: 2,
|
10
|
+
operation: ->(a,b) { a + b },
|
11
|
+
},
|
12
|
+
subtract: {
|
13
|
+
args: 2,
|
14
|
+
operation: ->(a,b) { a - b },
|
15
|
+
},
|
16
|
+
multiply: {
|
17
|
+
args: 2,
|
18
|
+
operation: ->(a,b) { a * b },
|
19
|
+
},
|
20
|
+
divide: {
|
21
|
+
args: 2,
|
22
|
+
operation: ->(a,b) { a / b },
|
23
|
+
},
|
24
|
+
power: {
|
25
|
+
args: 2,
|
26
|
+
operation: ->(a,b) { a ** b },
|
27
|
+
},
|
28
|
+
mod: {
|
29
|
+
args: 2,
|
30
|
+
operation: ->(a,b) { a % b },
|
31
|
+
},
|
32
|
+
negative: {
|
33
|
+
args: 1,
|
34
|
+
operation: ->(a) { -a },
|
35
|
+
},
|
36
|
+
positive: {
|
37
|
+
args: 1,
|
38
|
+
operation: ->(a) { +a },
|
39
|
+
},
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def eval(subs = {})
|
44
|
+
stack = []
|
45
|
+
|
46
|
+
notation.each do |elem|
|
47
|
+
if elem.is_a? Symbol
|
48
|
+
if operations.has_key? elem
|
49
|
+
stack.push operations[elem][:operation].call(*stack.pop(operations[elem][:args])).to_f
|
50
|
+
else
|
51
|
+
stack.push subs[elem].to_f
|
52
|
+
end
|
53
|
+
else
|
54
|
+
stack.push elem.to_f
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
return stack.first
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative './../lib/latex_eval.rb'
|
3
|
+
|
4
|
+
class TestEquation < Minitest::Test
|
5
|
+
def test_that_parser_parses_addition
|
6
|
+
equation = "1 + 2"
|
7
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :add]
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_that_parser_parses_subtraction
|
11
|
+
equation = "1 - 2"
|
12
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :subtract]
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_that_parser_parses_multiplication
|
16
|
+
equation = "1 * 2"
|
17
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :multiply]
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_that_parser_parses_division
|
21
|
+
equation = "1 / 2"
|
22
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :divide]
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_that_parser_parses_powers
|
26
|
+
equation = "1 ^ 2"
|
27
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :power]
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_that_parser_respects_brackets
|
31
|
+
equation = "(1+2)^3"
|
32
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :add, 3, :power]
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_that_parser_respects_nested_brackets
|
36
|
+
equation = "(1+(2-4))^3"
|
37
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 4, :subtract, :add, 3, :power]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_that_parser_respects_separate_brackets
|
41
|
+
equation = "(1+(2-4))^(3 * 2)"
|
42
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 4, :subtract, :add, 3, 2, :multiply, :power]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_that_parser_respects_separate_brackets_v2
|
46
|
+
equation = "(1-(2-4))^(3 * 2)"
|
47
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 4, :subtract, :subtract, 3, 2, :multiply, :power]
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_that_parser_disregards_spaces
|
51
|
+
equation = "( 1 + 2 ) ^ 3"
|
52
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :add, 3, :power]
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_that_parser_recognizes_single_letter_variables
|
56
|
+
equation = "x + y + z"
|
57
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [:x, :y, :add, :z, :add]
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_that_parser_recognizes_multi_letter_variables
|
61
|
+
equation = "alpha + beta + gamma"
|
62
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [:alpha, :beta, :add, :gamma, :add]
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_that_parser_evaluates_multiply_divide_in_order_of_appearance
|
66
|
+
equation = "1 * 2 / 3"
|
67
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :multiply, 3, :divide]
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_that_parser_evaluates_add_subtract_in_order_of_appearance
|
71
|
+
equation = "1 + 2 - 3"
|
72
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, :add, 3, :subtract]
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_that_powers_are_given_proper_priority
|
76
|
+
equation = "3 ^ 2 ^ 2"
|
77
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [3, 2, 2, :power, :power]
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_that_parser_multiplication_priority_over_addition
|
81
|
+
equation = "1 + 2 * 3"
|
82
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :multiply, :add]
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_that_parser_multiplication_priority_over_subtraction
|
86
|
+
equation = "1 - 2 * 3"
|
87
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :multiply, :subtract]
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_that_parser_division_priority_over_addition
|
91
|
+
equation = "1 + 2 / 3"
|
92
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :divide, :add]
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_that_parser_division_priority_over_subtraction
|
96
|
+
equation = "1 - 2 / 3"
|
97
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :divide, :subtract]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_that_parser_power_priority_over_addition
|
101
|
+
equation = "1 + 2 ^ 3"
|
102
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :power, :add]
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_that_parser_power_priority_over_subtraction
|
106
|
+
equation = "1 - 2 ^ 3"
|
107
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :power, :subtract]
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_that_parser_power_priority_over_multiplication
|
111
|
+
equation = "1 * 2 ^ 3"
|
112
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :power, :multiply]
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_that_parser_power_priority_over_division
|
116
|
+
equation = "1 / 2 ^ 3"
|
117
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :power, :divide]
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_that_parser_mod_priority_over_addition
|
121
|
+
equation = "1 + 2 % 3"
|
122
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :mod, :add]
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_that_parser_mod_priority_over_subtraction
|
126
|
+
equation = "1 - 2 % 3"
|
127
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [1, 2, 3, :mod, :subtract]
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_that_negative_works
|
131
|
+
equation = "- 2"
|
132
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, :negative]
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_that_positive_works
|
136
|
+
equation = "+ 2"
|
137
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, :positive]
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_that_negative_works_inside_brackets
|
141
|
+
equation = "(-2)"
|
142
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, :negative]
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_that_negative_works_outside_brackets
|
146
|
+
equation = "-(2)"
|
147
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, :negative]
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_that_negative_works_with_others
|
151
|
+
equation = "-2+3"
|
152
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, :negative, 3, :add]
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_that_negative_works_with_multiple_negatives
|
156
|
+
equation = "--2"
|
157
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, :negative, :negative]
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_that_negative_works_with_multiplication_normal
|
161
|
+
equation = "2 * - 2"
|
162
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, 2, :negative, :multiply]
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_that_negative_works_with_multiple_negatives_2
|
166
|
+
equation = "2^(-2)"
|
167
|
+
assert_equal LatexEval::Equation.new(equation).postfix_notation, [2, 2, :negative, :power]
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative './../lib/latex_eval.rb'
|
3
|
+
|
4
|
+
class TestLatexEval < Minitest::Test
|
5
|
+
def test_it_all
|
6
|
+
latex = '\frac{1}{2}\cdot3\xi+4'
|
7
|
+
assert_equal LatexEval.eval(latex, {xi: 2}), 7
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_postfix_notation
|
11
|
+
latex = '1+3*2'
|
12
|
+
assert_equal LatexEval.postfix_notation(latex), [1, 3, 2, :multiply, :add]
|
13
|
+
end
|
14
|
+
end
|
data/test/latex_test.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative './../lib/latex_eval.rb'
|
3
|
+
|
4
|
+
class TestLatex < Minitest::Test
|
5
|
+
def test_that_latex_parser_parses_fractions
|
6
|
+
latex = '\frac{1}{2}'
|
7
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((1)/(2))'
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_that_latex_parser_parses_fractions_recursively
|
11
|
+
latex = '\frac{\frac{3}{4}}{2}'
|
12
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((((3)/(4)))/(2))'
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_that_latex_parser_parses_dfractions
|
16
|
+
latex = '\dfrac{1}{2}'
|
17
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((1)/(2))'
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_that_latex_parser_parses_dfractions_recursively
|
21
|
+
latex = '\dfrac{\dfrac{3}{4}}{2}'
|
22
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((((3)/(4)))/(2))'
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_that_latex_parser_parses_cdot
|
26
|
+
latex = '1\cdot2'
|
27
|
+
assert_equal LatexEval::Latex.new(latex).equation, '1*2'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_that_latex_parser_parses_times
|
31
|
+
latex = '1\times2'
|
32
|
+
assert_equal LatexEval::Latex.new(latex).equation, '1*2'
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_that_latex_parser_parses_powers
|
36
|
+
latex = '1^{23}'
|
37
|
+
assert_equal LatexEval::Latex.new(latex).equation, '1^(23)'
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_that_latex_parser_parses_variable_names
|
41
|
+
latex = '\xi'
|
42
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'xi'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_that_latex_parser_adds_missing_multiplication_before_variable
|
46
|
+
latex = '2\xi'
|
47
|
+
assert_equal LatexEval::Latex.new(latex).equation, '2*xi'
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_that_latex_parser_adds_missing_multiplication_after_variable
|
51
|
+
latex = '\xi2'
|
52
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'xi*2'
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_that_latex_parser_adds_missing_multiplication_between_variable
|
56
|
+
latex = '\alpha\beta'
|
57
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'alpha*beta'
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_that_latex_parser_adds_missing_multiplication_between_brackets
|
61
|
+
latex = '(1)(2)'
|
62
|
+
assert_equal LatexEval::Latex.new(latex).equation, '(1)*(2)'
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_that_latex_parser_parses_nth_root
|
66
|
+
latex = '\sqrt[3]{2}'
|
67
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((2)^(1/(3)))'
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_that_latex_parser_parses_sqrt
|
71
|
+
latex = '\sqrt{2}'
|
72
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((2)^(1/2))'
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_works_with_typical_variables
|
76
|
+
latex = '\xi x'
|
77
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'xi*x'
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_works_with_typical_variable
|
81
|
+
latex = '2x'
|
82
|
+
assert_equal LatexEval::Latex.new(latex).equation, '2*x'
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_works_with_typical_variable_spaces
|
86
|
+
latex = '2 x'
|
87
|
+
assert_equal LatexEval::Latex.new(latex).equation, '2*x'
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_works_with_typical_variable_multiple_spaces
|
91
|
+
latex = '2 x'
|
92
|
+
assert_equal LatexEval::Latex.new(latex).equation, '2*x'
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_works_with_left_and_right
|
96
|
+
latex = '\left(x + 2\right)'
|
97
|
+
assert_equal LatexEval::Latex.new(latex).equation, '(x+2)'
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_works_with_abs
|
101
|
+
latex = '2 % 3'
|
102
|
+
assert_equal LatexEval::Latex.new(latex).equation, '2%3'
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_works_with_abs_and_variables
|
106
|
+
latex = 'x % y'
|
107
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'x%y'
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_works_with_variable_spaces
|
111
|
+
latex = 'x y'
|
112
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'x*y'
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_works_with_latex_variables
|
116
|
+
latex = '\xix'
|
117
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'xi*x'
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_works_with_regular_variables
|
121
|
+
latex = 'xyz'
|
122
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'x*y*z'
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_works_with_regular_variables_and_weird_numbers
|
126
|
+
latex = 'x*2yz'
|
127
|
+
assert_equal LatexEval::Latex.new(latex).equation, 'x*2*y*z'
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_works_with_regular_variables_complex
|
131
|
+
latex = '\frac{2xy}{3}'
|
132
|
+
assert_equal LatexEval::Latex.new(latex).equation, '((2*x*y)/(3))'
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative './../lib/latex_eval.rb'
|
3
|
+
|
4
|
+
class TestPostfixNotation < Minitest::Test
|
5
|
+
def test_that_eval_evals_add
|
6
|
+
parsed = [3, 5, :add]
|
7
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, 8
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_that_eval_evals_subtract
|
11
|
+
parsed = [3, 5, :subtract]
|
12
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, -2
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_that_eval_evals_multiply
|
16
|
+
parsed = [3, 5, :multiply]
|
17
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, 15
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_that_eval_evals_divide
|
21
|
+
parsed = [3, 5, :divide]
|
22
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, 0.6
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_that_eval_evals_power
|
26
|
+
parsed = [3, 5, :power]
|
27
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, 243
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_that_eval_evals_variables
|
31
|
+
parsed = [:x, :y, :power]
|
32
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval({x: 13, y: 3}), 2197
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_that_negatives_work
|
36
|
+
parsed = [-2, -1, :subtract]
|
37
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, -1
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_that_uniary_negative_works
|
41
|
+
parsed = [-2, -1, :negative, :add]
|
42
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, -1
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_that_uniary_positive_works
|
46
|
+
parsed = [-2, -1, :positive, :add]
|
47
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, -3
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_that_modulus_works
|
51
|
+
parsed = [432, 123, :mod]
|
52
|
+
assert_equal LatexEval::PostfixNotation.new(parsed).eval, 63
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: latex_eval
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Dunn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.11'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.11.3
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '5.11'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.11.3
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rake
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '12.3'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '12.3'
|
47
|
+
description: This gem can be used to parse and then evaluate simple latex expressions.
|
48
|
+
email: jdunn45@alumni.uwo.ca
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- README.md
|
54
|
+
- lib/latex_eval.rb
|
55
|
+
- lib/latex_eval/equation.rb
|
56
|
+
- lib/latex_eval/latex.rb
|
57
|
+
- lib/latex_eval/postfix_notation.rb
|
58
|
+
- test/equation_test.rb
|
59
|
+
- test/latex_eval_test.rb
|
60
|
+
- test/latex_test.rb
|
61
|
+
- test/postfix_notation_test.rb
|
62
|
+
homepage: https://rubygems.org/gems/latex_eval
|
63
|
+
licenses:
|
64
|
+
- MIT
|
65
|
+
metadata:
|
66
|
+
source_code_uri: https://github.com/joshddunn/latex_eval
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 2.6.11
|
84
|
+
signing_key:
|
85
|
+
specification_version: 4
|
86
|
+
summary: Evaluate simple latex expressions.
|
87
|
+
test_files: []
|