rb_maxima 0.1.0 → 1.0.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 +4 -4
- data/lib/maxima/command.rb +8 -6
- data/lib/maxima/complex.rb +5 -13
- data/lib/maxima/core.rb +30 -23
- data/lib/maxima/float.rb +2 -4
- data/lib/maxima/histogram.rb +24 -13
- data/lib/maxima/polynomial.rb +13 -17
- data/lib/maxima/rational.rb +17 -8
- data/lib/maxima/unit.rb +0 -8
- data/lib/maxima/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7f8a7781dde39239a581fe9e88b9d127b93bdd7225bb027b361950c84f7ad6a
|
4
|
+
data.tar.gz: 5393dfa5952b36216eb717a7b47c00ac8cc144f96815c60675f29ef68fa224be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d195381e9231e60d11f5dc9b2f814e69a4478e79e2fd45185e459b3866c6e626c22c1b4c0741e63984f8ee68939589acd1ec1077dc91ae93032a9a46392d83d
|
7
|
+
data.tar.gz: 287a8b6257429192fb76706750eecbe1a1eade21a0d55da9dce3f8f586bd31a9d8da6ba45e845382d93f172ca20aaf54904db26a38b0afdbe0b518059fe86932
|
data/lib/maxima/command.rb
CHANGED
@@ -13,7 +13,7 @@ module Maxima
|
|
13
13
|
Command.new()
|
14
14
|
.with_options(
|
15
15
|
use_fast_arrays: true,
|
16
|
-
float: true
|
16
|
+
float: true
|
17
17
|
).tap do |c|
|
18
18
|
yield c
|
19
19
|
end.output_variables(*v)
|
@@ -34,10 +34,10 @@ module Maxima
|
|
34
34
|
|
35
35
|
def let(variable_or_variables, expression, *unary_operations, **unary_operations_options)
|
36
36
|
add_variable(variable_or_variables)
|
37
|
-
|
37
|
+
|
38
38
|
|
39
39
|
variable = Maxima.mformat(variable_or_variables)
|
40
|
-
expression =
|
40
|
+
expression = _apply_unary_operations(expression, *unary_operations, **unary_operations_options)
|
41
41
|
|
42
42
|
_let(variable, expression)
|
43
43
|
end
|
@@ -69,26 +69,28 @@ module Maxima
|
|
69
69
|
|
70
70
|
[
|
71
71
|
unary_operations.map { |unary_operation| "#{unary_operation}(" },
|
72
|
-
expression,
|
72
|
+
Maxima.mformat(expression),
|
73
73
|
")" * unary_operations.count
|
74
74
|
].join()
|
75
75
|
end
|
76
76
|
|
77
77
|
OPTIONS = {
|
78
78
|
float: -> (enabled) { "float: #{enabled}" },
|
79
|
-
use_fast_arrays: -> (enabled) { "use_fast_arrays: #{enabled}" }
|
79
|
+
use_fast_arrays: -> (enabled) { "use_fast_arrays: #{enabled}" },
|
80
|
+
real_only: -> (enabled) { "realonly: #{enabled}" }
|
80
81
|
}
|
81
82
|
|
82
83
|
def options_commands()
|
83
84
|
[].each do |commands|
|
84
85
|
@options.each do |option, configuration|
|
86
|
+
# warn that option is not applicable
|
85
87
|
next unless OPTIONS[option]
|
86
88
|
commands << OPTIONS[option].call(configuration)
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
def run_shell(extract_variables = nil, debug: ENV["
|
93
|
+
def run_shell(extract_variables = nil, debug: ENV["DEBUG_RB_MAXIMA"])
|
92
94
|
inputs = [*dependencies_input, *options_commands(), *@commands]
|
93
95
|
|
94
96
|
inputs << "grind(#{extract_variables.join(', ')})" if extract_variables
|
data/lib/maxima/complex.rb
CHANGED
@@ -14,7 +14,7 @@ module Maxima
|
|
14
14
|
end
|
15
15
|
|
16
16
|
WHITESPACE_OR_PARENTHESES_REGEX = /(\s|\(|\))/
|
17
|
-
COMPLEX_REGEX = /(-?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)((?:\*)?(?:%)
|
17
|
+
COMPLEX_REGEX = /(-?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)((?:\*)?(?:%)?\s*i)?|((?:\s*)-?%i)/
|
18
18
|
|
19
19
|
def self.parse(maxima_output)
|
20
20
|
maxima_output = maxima_output.to_s unless maxima_output.is_a?(String)
|
@@ -23,8 +23,10 @@ module Maxima
|
|
23
23
|
real = 0
|
24
24
|
imaginary = 0
|
25
25
|
|
26
|
-
string.scan(COMPLEX_REGEX) do |(float, is_imaginary)|
|
27
|
-
if
|
26
|
+
string.scan(COMPLEX_REGEX) do |(float, is_imaginary, is_just_imaginary_one)|
|
27
|
+
if is_just_imaginary_one
|
28
|
+
imaginary += (is_just_imaginary_one.start_with? "-") ? -1 : 1
|
29
|
+
elsif is_imaginary
|
28
30
|
imaginary += float.to_f
|
29
31
|
else
|
30
32
|
real += float.to_f
|
@@ -38,15 +40,6 @@ module Maxima
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
def pretty_to_s
|
42
|
-
if real == 0
|
43
|
-
"#{@imaginary}i"
|
44
|
-
else
|
45
|
-
operand = @real.positive? ? '+' : '-'
|
46
|
-
"#{@imaginary}i #{operand} #{@real.abs}"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
43
|
def to_maxima_input
|
51
44
|
return "#{@imaginary} * %i" if real == 0
|
52
45
|
|
@@ -59,7 +52,6 @@ module Maxima
|
|
59
52
|
end
|
60
53
|
|
61
54
|
# Definitions are somewhat contrived and not per se mathematically accurate.
|
62
|
-
|
63
55
|
def positive?
|
64
56
|
!negative?
|
65
57
|
end
|
data/lib/maxima/core.rb
CHANGED
@@ -3,22 +3,23 @@ module Maxima
|
|
3
3
|
Maxima::Function.new("((#{Maxima.mformat(e_1)}) #{bin_op} (#{Maxima.mformat(e_2)}))")
|
4
4
|
end
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
## Alternative minimization function that needs it's own testing etc.
|
7
|
+
# def self.cobyla(minimize_function, variables, constraint_function, initial_guess)
|
8
|
+
# Command.output(variables => Unit) do |c|
|
9
|
+
# initial_guess = mformat(initial_guess)
|
9
10
|
|
10
|
-
|
11
|
+
# c.dependencies << "cobyla"
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
13
|
+
# c.let :output, "fmin_cobyla(#{minimize_function}, #{mformat(variables)}, #{initial_guess},constraints = #{constraint_function})"
|
14
|
+
# c.let variables, "sublis(output[1], #{variables})"
|
15
|
+
# end
|
16
|
+
# end
|
16
17
|
|
17
|
-
def self.
|
18
|
-
Command.output(
|
18
|
+
def self.lagrangian_interpolation(array)
|
19
|
+
Command.output(function: Function) do |c|
|
19
20
|
c.dependencies << "interpol"
|
20
|
-
c.let :array, array
|
21
|
-
c.let_simplified :
|
21
|
+
c.let :array, array
|
22
|
+
c.let_simplified :function, "lagrange(array)"
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
@@ -90,6 +91,7 @@ module Maxima
|
|
90
91
|
|
91
92
|
def self.lagrangian(minimize_function, variables, constraint_function, initial_guess, iterations: 5)
|
92
93
|
Command.output(variables => Unit) do |c|
|
94
|
+
variables = mformat(variables)
|
93
95
|
initial_guess = mformat(initial_guess)
|
94
96
|
constraint_function = mformat(Array(constraint_function))
|
95
97
|
optional_args = mformat(niter: iterations)
|
@@ -104,34 +106,39 @@ module Maxima
|
|
104
106
|
|
105
107
|
def self.mformat(variable)
|
106
108
|
case variable
|
107
|
-
when String
|
109
|
+
when String
|
108
110
|
variable # the only truly `valid` input is a string
|
109
111
|
when Hash
|
110
112
|
variable.map do |key,value|
|
111
113
|
"#{mformat(key)} = #{mformat(value)}"
|
112
114
|
end.join(", ")
|
113
|
-
when Array
|
114
|
-
"[" + variable.map { |v| mformat(v) }.join(",") + "]"
|
115
|
+
when Array, Histogram
|
116
|
+
"[" + variable.to_a.map { |v| mformat(v) }.join(",") + "]"
|
115
117
|
when ::Complex
|
116
|
-
mformat Complex.new(variable
|
118
|
+
mformat Complex.new(variable.real, variable.imag)
|
117
119
|
when Numeric
|
118
120
|
mformat Float(variable)
|
119
121
|
when Complex, Float, Function
|
120
122
|
variable.to_maxima_input
|
121
123
|
when nil
|
122
124
|
throw :cannot_format_nil
|
123
|
-
else
|
124
|
-
variable
|
125
|
+
else # Symbol, etc.
|
126
|
+
variable.to_s
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
128
130
|
def self.solve_polynomial(equations, variables_to_solve_for, ignore: nil, real_only: false)
|
131
|
+
variables_to_solve_for = Array(variables_to_solve_for)
|
132
|
+
equations = Array(equations)
|
133
|
+
|
134
|
+
throw :all_equations_must_include_equivalence unless equations.all? { |e| e.include?("=") }
|
135
|
+
|
129
136
|
# regex match extract
|
130
|
-
output = Command
|
131
|
-
|
132
|
-
|
133
|
-
variables = mformat(
|
134
|
-
equations = mformat(
|
137
|
+
output = Command.output(output: Unit) do |c|
|
138
|
+
c.with_options(real_only: real_only)
|
139
|
+
|
140
|
+
variables = mformat(variables_to_solve_for)
|
141
|
+
equations = mformat(equations)
|
135
142
|
|
136
143
|
c.let :output, "algsys(#{equations},#{variables})"
|
137
144
|
end
|
data/lib/maxima/float.rb
CHANGED
data/lib/maxima/histogram.rb
CHANGED
@@ -40,32 +40,34 @@ module Maxima
|
|
40
40
|
@points = points
|
41
41
|
end
|
42
42
|
|
43
|
+
def to_a
|
44
|
+
@points
|
45
|
+
end
|
46
|
+
|
47
|
+
# PDF
|
43
48
|
def to_percentage()
|
44
49
|
@to_percentage ||=
|
45
50
|
begin
|
46
|
-
sum = points.sum(&:
|
51
|
+
sum = points.sum(&:last)
|
47
52
|
Histogram.new(
|
48
|
-
points.map do |
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
+
points.map do |(x,y)|
|
54
|
+
[
|
55
|
+
x,
|
56
|
+
y.fdiv(sum)
|
57
|
+
]
|
53
58
|
end
|
54
59
|
)
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
58
|
-
|
59
|
-
@points
|
60
|
-
end
|
61
|
-
|
63
|
+
# literal CDF
|
62
64
|
def integral()
|
63
65
|
begin
|
64
66
|
sum = 0
|
65
67
|
Histogram.new(
|
66
|
-
points.map do |(
|
67
|
-
sum +=
|
68
|
-
[
|
68
|
+
points.map do |(x, y)|
|
69
|
+
sum += y
|
70
|
+
[x, sum]
|
69
71
|
end
|
70
72
|
)
|
71
73
|
end
|
@@ -74,5 +76,14 @@ module Maxima
|
|
74
76
|
def to_gnu_plot()
|
75
77
|
[*points.map(&:to_a).transpose, w: "points"]
|
76
78
|
end
|
79
|
+
|
80
|
+
def <=>(other)
|
81
|
+
case other
|
82
|
+
when Array, Histogram
|
83
|
+
self.to_a <=> other.to_a
|
84
|
+
else
|
85
|
+
-1
|
86
|
+
end
|
87
|
+
end
|
77
88
|
end
|
78
89
|
end
|
data/lib/maxima/polynomial.rb
CHANGED
@@ -3,6 +3,7 @@ module Maxima
|
|
3
3
|
|
4
4
|
def self.fit(histogram, degrees)
|
5
5
|
throw :degrees_must_be_zero_or_positive if degrees < 0
|
6
|
+
degrees += 1
|
6
7
|
|
7
8
|
equation_string, variables = polynomial_equation(degrees)
|
8
9
|
results = Maxima.lsquares_estimation(histogram.to_a, [:x, :y], "y = #{equation_string}", variables)
|
@@ -13,37 +14,32 @@ module Maxima
|
|
13
14
|
end
|
14
15
|
|
15
16
|
{
|
16
|
-
function: Maxima::Function.new(equation_string),
|
17
|
+
function: Maxima::Function.new(equation_string).simplified,
|
17
18
|
mse: mse
|
18
19
|
}
|
19
20
|
end
|
20
21
|
|
21
|
-
def self.fit_function(min, max, x: "x")
|
22
|
-
Enumerator.new do |e|
|
23
|
-
(min..max).each do |degrees|
|
24
|
-
equation_string, variables = polynomial_equation(degrees, f_of: x)
|
25
|
-
e.<<(equation_string, variables)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
22
|
def self.polynomial_equation(degrees, f_of: "x")
|
31
|
-
|
23
|
+
polynomials = []
|
24
|
+
constant_variables = []
|
25
|
+
|
26
|
+
degrees.times.each do |degree|
|
27
|
+
constant_variable = "c#{degree}"
|
28
|
+
constant_variables << constant_variable
|
32
29
|
|
33
|
-
free_polynomial = constant_variables.each do |degree|
|
34
30
|
case degree
|
35
31
|
when 0
|
36
|
-
"(#{constant_variable})"
|
32
|
+
polynomials << "(#{constant_variable})"
|
37
33
|
when 1
|
38
|
-
"(#{constant_variable}) * #{f_of}"
|
34
|
+
polynomials << "(#{constant_variable}) * #{f_of}"
|
39
35
|
else
|
40
|
-
"(#{constant_variable}) * #{f_of} ^ #{degree}"
|
36
|
+
polynomials << "(#{constant_variable}) * #{f_of} ^ #{degree}"
|
41
37
|
end
|
42
38
|
end
|
43
39
|
|
44
40
|
[
|
45
|
-
|
46
|
-
|
41
|
+
polynomials.join(" + "),
|
42
|
+
constant_variables
|
47
43
|
]
|
48
44
|
end
|
49
45
|
end
|
data/lib/maxima/rational.rb
CHANGED
@@ -3,22 +3,22 @@ module Maxima
|
|
3
3
|
|
4
4
|
attr_accessor :numerator, :denominator
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
super(
|
6
|
+
def initialize(numerator, denominator, **options)
|
7
|
+
super(**options)
|
8
8
|
@numerator = numerator
|
9
9
|
@denominator = denominator
|
10
10
|
end
|
11
11
|
|
12
|
-
REGEX =
|
13
|
-
def self.parse(
|
14
|
-
_, numerator, denominator = REGEX.match(
|
12
|
+
REGEX = /\s*(\d+)\s*\/\s*(\d+)\s*/
|
13
|
+
def self.parse(maxima_output)
|
14
|
+
_, numerator, denominator = REGEX.match(maxima_output).to_a
|
15
15
|
|
16
|
-
return
|
16
|
+
return if numerator.nil? || denominator.nil?
|
17
17
|
|
18
18
|
if numerator == 0
|
19
|
-
Float.new(
|
19
|
+
Float.new(0, maxima_output: maxima_output)
|
20
20
|
else
|
21
|
-
Rational.new(
|
21
|
+
Rational.new(numerator.to_f, denominator.to_f, maxima_output: maxima_output)
|
22
22
|
end
|
23
23
|
rescue StandardError
|
24
24
|
nil
|
@@ -35,5 +35,14 @@ module Maxima
|
|
35
35
|
def to_f
|
36
36
|
@to_f ||= numerator.fdiv(denominator)
|
37
37
|
end
|
38
|
+
|
39
|
+
def <=>(other)
|
40
|
+
case other
|
41
|
+
when ::Float, ::Rational, Float, Rational
|
42
|
+
self.to_f <=> other.to_f
|
43
|
+
else
|
44
|
+
-1
|
45
|
+
end
|
46
|
+
end
|
38
47
|
end
|
39
48
|
end
|
data/lib/maxima/unit.rb
CHANGED
@@ -37,10 +37,6 @@ module Maxima
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
# def absolute_difference(other)
|
41
|
-
# Function.new("abs(#{self - other})")
|
42
|
-
# end
|
43
|
-
|
44
40
|
def simplified
|
45
41
|
@simplified ||= through_maxima(:expand)
|
46
42
|
end
|
@@ -52,10 +48,6 @@ module Maxima
|
|
52
48
|
end[:itself]
|
53
49
|
end
|
54
50
|
|
55
|
-
def simplified!
|
56
|
-
simplified.to_s
|
57
|
-
end
|
58
|
-
|
59
51
|
def to_maxima_input
|
60
52
|
to_s
|
61
53
|
end
|
data/lib/maxima/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rb_maxima
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Ackerman
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -139,9 +139,9 @@ dependencies:
|
|
139
139
|
description: Ruby developers have, for as long as I can remember, had a disheveled
|
140
140
|
heap of scientific and mathematical libraries - many of which operate in pure ruby
|
141
141
|
code. Given a problem we either kludge together some cobbled mess or turn to Python/R/etc.
|
142
|
-
And to this I say no more!
|
142
|
+
And to this I say no more! rb_maxima allows a ruby developer to directly leverage
|
143
143
|
the unbridled power of the open source, lisp powered, computer algebra system that
|
144
|
-
is
|
144
|
+
is Maxima!
|
145
145
|
email:
|
146
146
|
- daniel.joseph.ackerman@gmail.com
|
147
147
|
executables: []
|
@@ -161,7 +161,7 @@ files:
|
|
161
161
|
- lib/maxima/rational.rb
|
162
162
|
- lib/maxima/unit.rb
|
163
163
|
- lib/maxima/version.rb
|
164
|
-
homepage:
|
164
|
+
homepage: https://github.com/Danieth/rb_maxima
|
165
165
|
licenses:
|
166
166
|
- MIT
|
167
167
|
metadata: {}
|
@@ -184,6 +184,6 @@ rubyforge_project:
|
|
184
184
|
rubygems_version: 2.7.3
|
185
185
|
signing_key:
|
186
186
|
specification_version: 4
|
187
|
-
summary: A gem that allows for mathematical calculations using the open source
|
187
|
+
summary: A gem that allows for mathematical calculations using the open source Maxima
|
188
188
|
library!
|
189
189
|
test_files: []
|