Skip to content

Commit 1350fa5

Browse files
authored
Sample code without deprecated modules (#480)
* sample/pi Remove shebang and `include BigMath` * Rewrite sample/linear.rb using gem matrix instead of bigdecimal/ludcmp * Implement sample/nlsolve.rb without deprecated bigdecimal/newton
1 parent d2c4196 commit 1350fa5

File tree

3 files changed

+122
-68
lines changed

3 files changed

+122
-68
lines changed

sample/linear.rb

Lines changed: 73 additions & 35 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
#
@@ -13,62 +12,101 @@
1312

1413
# :stopdoc:
1514
require "bigdecimal"
16-
require "bigdecimal/ludcmp"
1715

18-
#
19-
# NOTE:
20-
# Change following BigDecimal.limit() if needed.
21-
BigDecimal.limit(100)
22-
#
16+
# Requires gem matrix
17+
require "matrix"
18+
19+
class PrecisionSpecifiedValue
20+
# NOTE:
21+
# Change following PREC if needed.
22+
23+
attr_reader :value
24+
def initialize(value, prec)
25+
@value = BigDecimal(value)
26+
@prec = prec
27+
end
28+
29+
def unwrap(value)
30+
PrecisionSpecifiedValue === value ? value.value : value
31+
end
32+
33+
def coerce(other)
34+
[self.class.new(unwrap(other), @prec), self]
35+
end
36+
37+
def abs
38+
self.class.new(@value.abs, @prec)
39+
end
40+
41+
def >(other)
42+
@value > unwrap(other)
43+
end
44+
45+
def <(other)
46+
@value < unwrap(other)
47+
end
48+
49+
def -(other)
50+
self.class.new(@value.sub(unwrap(other), @prec), @prec)
51+
end
52+
53+
def +(other)
54+
self.class.new(@value.add(unwrap(other), @prec), @prec)
55+
end
56+
57+
def *(other)
58+
self.class.new(@value.mult(unwrap(other), @prec), @prec)
59+
end
60+
61+
def quo(other)
62+
self.class.new(@value.div(unwrap(other), @prec), @prec)
63+
end
64+
end
65+
66+
return if __FILE__ != $0
2367

24-
include LUSolve
2568
def rd_order(na)
26-
printf("Number of equations ?") if(na <= 0)
27-
n = ARGF.gets().to_i
69+
printf("Number of equations ?") if(na <= 0)
70+
ARGF.gets().to_i
2871
end
2972

30-
na = ARGV.size
31-
zero = BigDecimal("0.0")
32-
one = BigDecimal("1.0")
73+
na = ARGV.size
3374

3475
while (n=rd_order(na))>0
3576
a = []
36-
as= []
3777
b = []
3878
if na <= 0
3979
# Read data from console.
4080
printf("\nEnter coefficient matrix element A[i,j]\n")
4181
for i in 0...n do
42-
for j in 0...n do
82+
a << n.times.map do |j|
4383
printf("A[%d,%d]? ",i,j); s = ARGF.gets
44-
a << BigDecimal(s)
45-
as << BigDecimal(s)
84+
BigDecimal(s)
4685
end
4786
printf("Contatant vector element b[%d] ? ",i)
4887
b << BigDecimal(ARGF.gets)
4988
end
5089
else
51-
# Read data from specified file.
52-
printf("Coefficient matrix and constant vector.\n")
53-
for i in 0...n do
54-
s = ARGF.gets
55-
printf("%d) %s",i,s)
56-
s = s.split
57-
for j in 0...n do
58-
a << BigDecimal(s[j])
59-
as << BigDecimal(s[j])
60-
end
61-
b << BigDecimal(s[n])
62-
end
90+
# Read data from specified file.
91+
printf("Coefficient matrix and constant vector.\n")
92+
for i in 0...n do
93+
s = ARGF.gets
94+
printf("%d) %s",i,s)
95+
s = s.split
96+
a << n.times.map {|j| BigDecimal(s[j]) }
97+
b << BigDecimal(s[n])
98+
end
6399
end
64-
x = lusolve(a,b,ludecomp(a,n,zero,one),zero)
100+
101+
prec = 100
102+
matrix = Matrix[*a.map {|row| row.map {|v| PrecisionSpecifiedValue.new(v, prec) } }]
103+
vector = b.map {|v| PrecisionSpecifiedValue.new(v, prec) }
104+
x = matrix.lup.solve(vector).map(&:value)
105+
65106
printf("Answer(x[i] & (A*x-b)[i]) follows\n")
66107
for i in 0...n do
67108
printf("x[%d]=%s ",i,x[i].to_s)
68-
s = zero
69-
for j in 0...n do
70-
s = s + as[i*n+j]*x[j]
71-
end
72-
printf(" & %s\n",(s-b[i]).to_s)
109+
diff = a[i].zip(x).sum {|aij, xj| aij*xj }.sub(b[i], 10)
110+
printf(" & %s\n", diff.to_s)
73111
end
74112
end

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:)

sample/pi.rb

Lines changed: 1 addition & 4 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
#
@@ -11,11 +10,9 @@
1110
require "bigdecimal"
1211
require "bigdecimal/math.rb"
1312

14-
include BigMath
15-
1613
if ARGV.size == 1
1714
print "PI("+ARGV[0]+"):\n"
18-
p PI(ARGV[0].to_i)
15+
p BigMath.PI(ARGV[0].to_i)
1916
else
2017
print "TRY: ruby pi.rb 1000 \n"
2118
end

0 commit comments

Comments
 (0)