goalseek 0.1.0 → 0.1.1

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
  SHA1:
3
- metadata.gz: 747c7855df771b99e8a14ae0d7dda32bda5216c4
4
- data.tar.gz: 64351ed03ddb34be21d332a3eeaef5f60505e51c
3
+ metadata.gz: ef1c7fc4ff85d9cb3a5033fa6f9b18c856f60bd5
4
+ data.tar.gz: f7e85129e6e10ddc37b0e67c56dec035503922e1
5
5
  SHA512:
6
- metadata.gz: 3a6def3a9b3e69033c550fbbe666de917335c53eab464ed94a0fea65b634cf8af2bb6be4de47294e76da6e2dfd8e4703dd2d95aadb29c671aee383858820e200
7
- data.tar.gz: eca9ff2df3c75ce9b552cd9a0e71e5133ef45fc50d46b94654e5350fed2787a10dab7990f3acc452d3763ea2eb3796f1e62d2f08aa07eda8b676157f37f8a729
6
+ metadata.gz: 68a6ac63ae127ec11ac432ef84f4ee67cf5d99b45c48c70c28effc703d4fdd49f2cfbffe9931201f8fa7e6f5bd44d9d407d9a8cbae5535a985b22b09f5f7dabe
7
+ data.tar.gz: db959a50069beae15e00a9c8cd633b630894f136e9fd8f8ffaad25ad2f5b6e29209fc7c94c55f29a4b69a503638b7c9fa2819ddc6e79856e11df53fe2696c00b
data/README.md CHANGED
@@ -30,7 +30,22 @@ Or install it yourself as:
30
30
 
31
31
  ## Usage
32
32
 
33
- TODO: Write usage instructions here
33
+ This is a simple example of a linear search on a qubic function.
34
+
35
+ Bounds are automatically determined if they are within -10^10 to 10^10. Iterations are limited to 1000 by default.
36
+
37
+ ```ruby
38
+ begin
39
+ goalseeker = GoalSeek::LinearSearch.new(Proc.new() { |x| x ** 3 });
40
+ result = goalseeker.seek(27) # returns 3.0
41
+ rescue GoalSeek::InvalidBoundError
42
+ puts "Function does not cross target value within interval (-10^10, 10^10)"
43
+ rescue GoalSeek::InvalidFunctionError
44
+ puts "Provided block is not callable"
45
+ end
46
+ ```
47
+
48
+ For more examples, please have a look at the specs.
34
49
 
35
50
  ## Development
36
51
 
@@ -1,4 +1,5 @@
1
1
  require 'goalseek/version'
2
+ require 'goalseek/linear_search'
2
3
 
3
4
  module GoalSeek
4
5
  class InvalidBoundError < Exception
@@ -6,83 +7,4 @@ module GoalSeek
6
7
 
7
8
  class InvalidFunctionError < Exception
8
9
  end
9
-
10
- class GoalSeek
11
-
12
- # block is an f(x) function
13
- def initialize(f)
14
- @f = f
15
- end
16
-
17
- def seek(goal, options = {})
18
- @goal = goal.to_f
19
-
20
- options = {
21
- tolerance: 0,
22
- max_iterations: 1000
23
- }.merge(options)
24
-
25
- min_max = get_min_max(options[:lower_bound], options[:upper_bound])
26
- lower, upper = min_max[0], min_max[1]
27
-
28
- iterate(lower, upper, options[:tolerance], options[:max_iterations])
29
- end
30
-
31
- def iterate(lower, upper, tolerance, max_iterations, iterations = 1)
32
- new_bound = (lower + upper) / 2
33
-
34
- begin
35
- new_value = @f.call(new_bound)
36
- rescue NoMethodError
37
- raise InvalidFunctionError
38
- end
39
-
40
- if iterations == max_iterations || new_value === @goal
41
- return new_bound
42
- elsif new_value < @goal
43
- return iterate(new_bound, upper, tolerance, max_iterations, iterations + 1)
44
- elsif new_value > @goal
45
- return iterate(lower, new_bound, tolerance, max_iterations, iterations + 1)
46
- end
47
- end
48
-
49
- def get_min_max(a, b)
50
- x = nil, y = nil
51
-
52
- # Use given bounds if present
53
- if a && b
54
- x = a.to_f
55
- y = b.to_f
56
-
57
- if check_bounds(x, y)
58
- [x, y]
59
- elsif check_bounds(y, x)
60
- [y, x]
61
- else
62
- raise InvalidBoundError
63
- end
64
- end
65
-
66
- # Try exponential bound expansion from 0 to 10^10
67
- (0..10).each do |i|
68
- if check_bounds(0.0, 10.0 ** i)
69
- return [0.0, 10.0 ** i]
70
- end
71
- end
72
-
73
- # Try exponential bound expansion from -x to x
74
- (0..10).each do |i|
75
- if check_bounds(-10.0 ** i, 10.0 ** i)
76
- return [-10.0 ** i, 10.0 ** i]
77
- end
78
- end
79
-
80
- # Fall back to raising if no working bound could be found
81
- raise InvalidBoundError
82
- end
83
-
84
- def check_bounds(x, y)
85
- (@f.call(x) < @goal) && (@f.call(y) > @goal) || (@f.call(y) < @goal) && (@f.call(x) > @goal)
86
- end
87
- end
88
10
  end
@@ -0,0 +1,77 @@
1
+ module GoalSeek
2
+ class LinearSearch
3
+ # block is an f(x) function
4
+ def initialize(f)
5
+ @f = f
6
+ end
7
+
8
+ def seek(goal, options = {})
9
+ @goal = goal.to_f
10
+
11
+ options = {
12
+ tolerance: 0,
13
+ max_iterations: 1000
14
+ }.merge(options)
15
+
16
+ min_max = get_min_max(options[:lower_bound], options[:upper_bound])
17
+ lower, upper = min_max[0], min_max[1]
18
+
19
+ iterate(lower, upper, options[:tolerance], options[:max_iterations])
20
+ end
21
+
22
+ def iterate(lower, upper, tolerance, max_iterations, iterations = 1)
23
+ new_bound = (lower + upper) / 2
24
+
25
+ begin
26
+ new_value = @f.call(new_bound)
27
+ rescue NoMethodError
28
+ raise InvalidFunctionError
29
+ end
30
+
31
+ if iterations == max_iterations || new_value === @goal
32
+ return new_bound
33
+ elsif new_value < @goal
34
+ return iterate(new_bound, upper, tolerance, max_iterations, iterations + 1)
35
+ elsif new_value > @goal
36
+ return iterate(lower, new_bound, tolerance, max_iterations, iterations + 1)
37
+ end
38
+ end
39
+
40
+ def get_min_max(a, b)
41
+ # Use given bounds if present
42
+ if a && b
43
+ x = a.to_f
44
+ y = b.to_f
45
+
46
+ if check_bounds(x, y)
47
+ [x, y]
48
+ elsif check_bounds(y, x)
49
+ [y, x]
50
+ else
51
+ raise InvalidBoundError
52
+ end
53
+ end
54
+
55
+ # Try exponential bound expansion from 0 to 10^10
56
+ (0..10).each do |i|
57
+ if check_bounds(0.0, 10.0 ** i)
58
+ return [0.0, 10.0 ** i]
59
+ end
60
+ end
61
+
62
+ # Try exponential bound expansion from -x to x
63
+ (0..10).each do |i|
64
+ if check_bounds(-10.0 ** i, 10.0 ** i)
65
+ return [-10.0 ** i, 10.0 ** i]
66
+ end
67
+ end
68
+
69
+ # Fall back to raising if no working bound could be found
70
+ raise InvalidBoundError
71
+ end
72
+
73
+ def check_bounds(x, y)
74
+ (@f.call(x) < @goal) && (@f.call(y) > @goal) || (@f.call(y) < @goal) && (@f.call(x) > @goal)
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module GoalSeek
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goalseek
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pascal Ehlert
@@ -72,6 +72,7 @@ files:
72
72
  - bin/setup
73
73
  - goalseek.gemspec
74
74
  - lib/goalseek.rb
75
+ - lib/goalseek/linear_search.rb
75
76
  - lib/goalseek/version.rb
76
77
  homepage: https://github.com/pehlert/goalseek
77
78
  licenses: