Skip to content

Commit 74197be

Browse files
committed
Implement sample/nlsolve.rb without deprecated bigdecimal/newton
1 parent 09969a5 commit 74197be

File tree

2 files changed

+52
-31
lines changed

2 files changed

+52
-31
lines changed

sample/linear.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# :stopdoc:
1414
require "bigdecimal"
1515

16-
# Requires gem "matrix"
16+
# Requires gem matrix
1717
require "matrix"
1818

1919
class PrecisionSpecifiedValue
@@ -63,9 +63,11 @@ def quo(other)
6363
end
6464
end
6565

66+
return if __FILE__ != $0
67+
6668
def rd_order(na)
6769
printf("Number of equations ?") if(na <= 0)
68-
n = ARGF.gets().to_i
70+
ARGF.gets().to_i
6971
end
7072

7173
na = ARGV.size

sample/nlsolve.rb

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#!/usr/local/bin/ruby
21
# frozen_string_literal: false
32

43
#
@@ -7,34 +6,54 @@
76
#
87

98
require "bigdecimal"
10-
require "bigdecimal/newton"
11-
include Newton
12-
13-
class Function # :nodoc: all
14-
def initialize()
15-
@zero = BigDecimal("0.0")
16-
@one = BigDecimal("1.0")
17-
@two = BigDecimal("2.0")
18-
@ten = BigDecimal("10.0")
19-
@eps = BigDecimal("1.0e-16")
20-
end
21-
def zero;@zero;end
22-
def one ;@one ;end
23-
def two ;@two ;end
24-
def ten ;@ten ;end
25-
def eps ;@eps ;end
26-
def values(x) # <= defines functions solved
27-
f = []
28-
f1 = x[0]*x[0] + x[1]*x[1] - @two # f1 = x**2 + y**2 - 2 => 0
29-
f2 = x[0] - x[1] # f2 = x - y => 0
30-
f <<= f1
31-
f <<= f2
32-
f
9+
require_relative "linear"
10+
11+
# Requires gem matrix
12+
require "matrix"
13+
14+
# :stopdoc:
15+
16+
def func((x, y)) # defines functions solved
17+
[
18+
x**2 + y**2 - 2,
19+
(x - 1)**2 + (y + 1)**2 - 3
20+
]
21+
end
22+
23+
def jacobian(x, f, delta, prec)
24+
dim = x.size
25+
dim.times.map do |i|
26+
xplus = Array.new(dim) {|j| x[i] + (j == i ? delta : 0) }
27+
xminus = Array.new(dim) {|j| x[i] - (j == i ? delta : 0) }
28+
yplus = f.call(xplus)
29+
yminus = f.call(xminus)
30+
yplus.zip(yminus).map {|p, m| (p - m).div(2 * delta, prec) }
31+
end.transpose
32+
end
33+
34+
def nlsolve(initial_x, prec:, max_iteration: 100, &f)
35+
initial_x = initial_x.map {|v| BigDecimal(v) }
36+
x = initial_x
37+
delta = BigDecimal(0.01)
38+
calc_prec = prec + 10
39+
max_iteration.times do |iteration|
40+
# Newton step
41+
jacobian = jacobian(x, f, delta, calc_prec)
42+
matrix = Matrix[*jacobian.map {|row| row.map {|v| PrecisionSpecifiedValue.new(v, calc_prec) } }]
43+
y = f.call(x)
44+
vector = y.map {|v| PrecisionSpecifiedValue.new(v, calc_prec) }
45+
dx = matrix.lup.solve(vector).map(&:value)
46+
x_prev = x
47+
x = x.zip(dx).map {|xi, di| xi.sub(di, prec) }
48+
movement = x_prev.zip(x).map {|xn, xi| (xn - xi).abs }.max
49+
delta = [movement, delta].min.mult(1, 10)
50+
break if movement.zero? || movement.exponent < -prec
3351
end
52+
x
3453
end
3554

36-
f = BigDecimal.limit(100)
37-
f = Function.new
38-
x = [f.zero,f.zero] # Initial values
39-
n = nlsolve(f,x)
40-
p x
55+
initial_value = [1, 1]
56+
ans = nlsolve(initial_value, prec: 100) {|x| func(x) }
57+
diff = func(ans).map {|v| v.mult(1, 10) }
58+
p(ans:)
59+
p(diff:)

0 commit comments

Comments
 (0)