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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2001c84271ebb26844cf1217d8e5ae5c7844987c65d4fe14723700996e45d6a
4
- data.tar.gz: 579008bc8d879af91514e27597a6887c9cbcb9aebfac62091b4354ce0e304b0c
3
+ metadata.gz: d7f8a7781dde39239a581fe9e88b9d127b93bdd7225bb027b361950c84f7ad6a
4
+ data.tar.gz: 5393dfa5952b36216eb717a7b47c00ac8cc144f96815c60675f29ef68fa224be
5
5
  SHA512:
6
- metadata.gz: 4bee94b71cc6bb0e107c2f0408d88a6fada488868cdf4c25d005f5275f4ef212e1a75ea8212fea9a301daa703c0fb8849b0e9189a4a4e97cd7baadf702cae969
7
- data.tar.gz: 46afece761a21a62d9d7d018317d2ca74470fe2069028c7af4d767ae2ced93a56ce2dd90da91c2a5c48fd3d0c7dbc830aa6bbe958fbe6d2f9b87df2d66036be2
6
+ metadata.gz: 9d195381e9231e60d11f5dc9b2f814e69a4478e79e2fd45185e459b3866c6e626c22c1b4c0741e63984f8ee68939589acd1ec1077dc91ae93032a9a46392d83d
7
+ data.tar.gz: 287a8b6257429192fb76706750eecbe1a1eade21a0d55da9dce3f8f586bd31a9d8da6ba45e845382d93f172ca20aaf54904db26a38b0afdbe0b518059fe86932
@@ -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
- expression = _apply_unary_operations(expression, *unary_operations, **unary_operations_options)
37
+
38
38
 
39
39
  variable = Maxima.mformat(variable_or_variables)
40
- expression = Maxima.mformat(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["DEBUG"])
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
@@ -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]+)?)((?:\*)?(?:%)?i)?/
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 is_imaginary
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
@@ -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
- def self.cobyla(minimize_function, variables, constraint_function, initial_guess)
7
- Command.output(variables => Unit) do |c|
8
- initial_guess = mformat(initial_guess)
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
- c.dependencies << "cobyla"
11
+ # c.dependencies << "cobyla"
11
12
 
12
- c.let :output, "fmin_cobyla(#{minimize_function}, #{mformat(variables)}, #{initial_guess},constraints = #{constraint_function})"
13
- c.let variables, "sublis(output[1], #{variables})"
14
- end
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.interpolate(array)
18
- Command.output(lagrangian: Function) do |c|
18
+ def self.lagrangian_interpolation(array)
19
+ Command.output(function: Function) do |c|
19
20
  c.dependencies << "interpol"
20
- c.let :array, array.to_a
21
- c.let_simplified :lagrangian, "lagrange(array)"
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, Symbol
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, variable.real, variable.imag)
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
- .with_options(real_only: real_only)
132
- .output(output: Unit) do |c|
133
- variables = mformat(Array(variables_to_solve_for))
134
- equations = mformat(Array(equations))
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
@@ -17,10 +17,8 @@ module Maxima
17
17
 
18
18
  def <=>(other)
19
19
  case other
20
- when ::Float
21
- @real <=> other
22
- when Float
23
- @real <=> other.real
20
+ when ::Float, Float
21
+ @real <=> other.to_f
24
22
  else
25
23
  -1
26
24
  end
@@ -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(&:x)
51
+ sum = points.sum(&:last)
47
52
  Histogram.new(
48
- points.map do |point|
49
- Point.new(
50
- point.x,
51
- point.y.fdiv(sum)
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
- def to_a
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 |(one, two)|
67
- sum += two
68
- [one, sum]
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
@@ -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
- constant_variables = degrees.times.map { |degree| "c#{degree}" }
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
- free_polynomial.join(" + "),
46
- variables
41
+ polynomials.join(" + "),
42
+ constant_variables
47
43
  ]
48
44
  end
49
45
  end
@@ -3,22 +3,22 @@ module Maxima
3
3
 
4
4
  attr_accessor :numerator, :denominator
5
5
 
6
- def initialize(string, numerator, denominator, title = nil)
7
- super(string, title)
6
+ def initialize(numerator, denominator, **options)
7
+ super(**options)
8
8
  @numerator = numerator
9
9
  @denominator = denominator
10
10
  end
11
11
 
12
- REGEX = /(\d+)\/(\d+)/
13
- def self.parse(input_string)
14
- _, numerator, denominator = REGEX.match(input_string).to_a
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 nil if numerator.nil? || denominator.nil?
16
+ return if numerator.nil? || denominator.nil?
17
17
 
18
18
  if numerator == 0
19
- Float.new(input_string, 0)
19
+ Float.new(0, maxima_output: maxima_output)
20
20
  else
21
- Rational.new(input_string, numerator.to_i, denominator.to_i)
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Maxima
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0"
3
3
  end
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: 0.1.0
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-18 00:00:00.000000000 Z
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! `rb_maxima` allows a ruby developer to directly leverage
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 `Maxima`!
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 `Maxima`
187
+ summary: A gem that allows for mathematical calculations using the open source Maxima
188
188
  library!
189
189
  test_files: []