rb_maxima 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|