morphological_metrics 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.autotest +30 -30
- data/.gemtest +0 -0
- data/.minitest.rb +3 -3
- data/.travis.yml +10 -10
- data/Gemfile +0 -0
- data/Gemfile.lock +0 -0
- data/History.txt +6 -6
- data/Manifest.txt +27 -27
- data/README.rdoc +65 -66
- data/ROADMAP.txt +63 -63
- data/Rakefile +32 -32
- data/bin/mm +3 -3
- data/lib/mm/deltas.rb +35 -35
- data/lib/mm/metric.rb +180 -191
- data/lib/mm/pairs.rb +12 -11
- data/lib/mm/ratio.rb +145 -148
- data/lib/mm/scaling.rb +30 -27
- data/lib/mm/search.rb +81 -81
- data/lib/mm.rb +10 -11
- data/lib/shortcuts.yml +49 -49
- data/test/helpers.rb +19 -22
- data/test/mm/test_deltas.rb +5 -0
- data/test/mm/test_metric.rb +160 -168
- data/test/mm/test_mm.rb +5 -6
- data/test/mm/test_pairs.rb +24 -27
- data/test/mm/test_ratio.rb +130 -132
- data/test/mm/test_scaling.rb +3 -0
- data/test/mm/test_search.rb +83 -89
- metadata +4 -4
data/lib/mm/scaling.rb
CHANGED
@@ -1,27 +1,30 @@
|
|
1
|
-
module MM
|
2
|
-
module Scaling
|
3
|
-
# All of these functions require a sequence of distance pair evaluations of
|
4
|
-
# the given metric. They all output scaled versions.
|
5
|
-
|
6
|
-
# Scale to the max across both vector
|
7
|
-
def self.none pairs
|
8
|
-
pairs
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
1
|
+
module MM
|
2
|
+
module Scaling
|
3
|
+
# All of these functions require a sequence of distance pair evaluations of
|
4
|
+
# the given metric. They all output scaled versions.
|
5
|
+
|
6
|
+
# Scale to the max across both vector
|
7
|
+
def self.none pairs
|
8
|
+
pairs
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.absolute pairs
|
12
|
+
max = (pairs.map(&:max)).max
|
13
|
+
pairs.map {|x| x.map {|y| y.to_f / max}}
|
14
|
+
end
|
15
|
+
|
16
|
+
# Scale each vector to its own max
|
17
|
+
def self.relative pairs
|
18
|
+
maxes = pairs.map(&:max)
|
19
|
+
pairs.zip(maxes).map {|pair, max| pair.map {|x| x.to_f / max}}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Note: a bit hacky. But anything starting with "get_" should be considered
|
23
|
+
# a meta-scaling method. This method returns a Proc that has a particular
|
24
|
+
# scaling value hard-coded into it, for re-use and re-use.
|
25
|
+
def self.get_global max
|
26
|
+
->(pairs) {pairs.map {|x| x.map {|y| y.to_f / max}}}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/lib/mm/search.rb
CHANGED
@@ -1,81 +1,81 @@
|
|
1
|
-
module MM; end
|
2
|
-
|
3
|
-
# All you need to do is add an adjacent_points_function and cost_function
|
4
|
-
class MM::Search
|
5
|
-
attr_accessor :candidates, :delta, :starting_point, :path, :banned, :iterations
|
6
|
-
attr_writer :cost_function, :adjacent_points_function
|
7
|
-
|
8
|
-
def initialize starting_point, delta = 0.001
|
9
|
-
@starting_point = starting_point
|
10
|
-
@delta = delta
|
11
|
-
@current_point = @starting_point
|
12
|
-
@path = []
|
13
|
-
@banned = []
|
14
|
-
@iterations = 0
|
15
|
-
end
|
16
|
-
|
17
|
-
# Finds a vector beginning from the starting point
|
18
|
-
def find
|
19
|
-
find_from_point @starting_point
|
20
|
-
end
|
21
|
-
|
22
|
-
def find_from_point point
|
23
|
-
@iterations += 1
|
24
|
-
# The adjacent points are all sorted
|
25
|
-
# raise StopIteration if cost_function(point) > current_cost
|
26
|
-
add_to_path point
|
27
|
-
sorted_adjacent_points = get_sorted_adjacent_points
|
28
|
-
# If we've made it, return it.
|
29
|
-
if made_it?
|
30
|
-
@current_point
|
31
|
-
else
|
32
|
-
begin
|
33
|
-
find_from_point sorted_adjacent_points.next
|
34
|
-
rescue StopIteration => er
|
35
|
-
# When the list of adjacent points runs out, backtrack
|
36
|
-
backtrack
|
37
|
-
retry unless @current_point.nil?
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def add_to_path point
|
43
|
-
@current_point = point
|
44
|
-
@path << point
|
45
|
-
end
|
46
|
-
|
47
|
-
def backtrack
|
48
|
-
@banned << @path.pop
|
49
|
-
puts "Path: #{@path.size}, Banned: #{@banned.size}" if ENV["DEBUG_RB"] && ENV["DEBUG_RB"].to_i > 1
|
50
|
-
@current_point = @path.last
|
51
|
-
end
|
52
|
-
|
53
|
-
def calculate_cost candidates
|
54
|
-
candidates.map {|x| cost_function x}
|
55
|
-
end
|
56
|
-
|
57
|
-
def made_it?
|
58
|
-
current_cost < @delta
|
59
|
-
end
|
60
|
-
|
61
|
-
def cost_function *args
|
62
|
-
@cost_function.call(*args)
|
63
|
-
end
|
64
|
-
|
65
|
-
def current_cost
|
66
|
-
cost_function @current_point
|
67
|
-
end
|
68
|
-
|
69
|
-
def get_adjacent_points *args
|
70
|
-
@adjacent_points_function.call(@current_point, *args)
|
71
|
-
end
|
72
|
-
|
73
|
-
def get_sorted_adjacent_points *args
|
74
|
-
get_adjacent_points(*args)
|
75
|
-
.reject {|c| @path.include? c}
|
76
|
-
.reject {|c| @banned.include? c}
|
77
|
-
.sort_by {|x| cost_function x}
|
78
|
-
.to_enum
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
1
|
+
module MM; end
|
2
|
+
|
3
|
+
# All you need to do is add an adjacent_points_function and cost_function
|
4
|
+
class MM::Search
|
5
|
+
attr_accessor :candidates, :delta, :starting_point, :path, :banned, :iterations
|
6
|
+
attr_writer :cost_function, :adjacent_points_function
|
7
|
+
|
8
|
+
def initialize starting_point, delta = 0.001
|
9
|
+
@starting_point = starting_point
|
10
|
+
@delta = delta
|
11
|
+
@current_point = @starting_point
|
12
|
+
@path = []
|
13
|
+
@banned = []
|
14
|
+
@iterations = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
# Finds a vector beginning from the starting point
|
18
|
+
def find
|
19
|
+
find_from_point @starting_point
|
20
|
+
end
|
21
|
+
|
22
|
+
def find_from_point point
|
23
|
+
@iterations += 1
|
24
|
+
# The adjacent points are all sorted
|
25
|
+
# raise StopIteration if cost_function(point) > current_cost
|
26
|
+
add_to_path point
|
27
|
+
sorted_adjacent_points = get_sorted_adjacent_points
|
28
|
+
# If we've made it, return it.
|
29
|
+
if made_it?
|
30
|
+
@current_point
|
31
|
+
else
|
32
|
+
begin
|
33
|
+
find_from_point sorted_adjacent_points.next
|
34
|
+
rescue StopIteration => er
|
35
|
+
# When the list of adjacent points runs out, backtrack
|
36
|
+
backtrack
|
37
|
+
retry unless @current_point.nil?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_to_path point
|
43
|
+
@current_point = point
|
44
|
+
@path << point
|
45
|
+
end
|
46
|
+
|
47
|
+
def backtrack
|
48
|
+
@banned << @path.pop
|
49
|
+
puts "Path: #{@path.size}, Banned: #{@banned.size}" if ENV["DEBUG_RB"] && ENV["DEBUG_RB"].to_i > 1
|
50
|
+
@current_point = @path.last
|
51
|
+
end
|
52
|
+
|
53
|
+
def calculate_cost candidates
|
54
|
+
candidates.map {|x| cost_function x}
|
55
|
+
end
|
56
|
+
|
57
|
+
def made_it?
|
58
|
+
current_cost < @delta
|
59
|
+
end
|
60
|
+
|
61
|
+
def cost_function *args
|
62
|
+
@cost_function.call(*args)
|
63
|
+
end
|
64
|
+
|
65
|
+
def current_cost
|
66
|
+
cost_function @current_point
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_adjacent_points *args
|
70
|
+
@adjacent_points_function.call(@current_point, *args)
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_sorted_adjacent_points *args
|
74
|
+
get_adjacent_points(*args)
|
75
|
+
.reject {|c| @path.include? c}
|
76
|
+
.reject {|c| @banned.include? c}
|
77
|
+
.sort_by {|x| cost_function x}
|
78
|
+
.to_enum
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
data/lib/mm.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
|
-
module MM
|
2
|
-
VERSION = "1.2.0"
|
3
|
-
end
|
4
|
-
|
5
|
-
require 'mm/deltas'
|
6
|
-
require 'mm/metric'
|
7
|
-
require 'mm/pairs'
|
8
|
-
require 'mm/ratio'
|
9
|
-
require 'mm/scaling'
|
10
|
-
require 'mm/
|
11
|
-
|
1
|
+
module MM
|
2
|
+
VERSION = "1.2.0"
|
3
|
+
end
|
4
|
+
|
5
|
+
require 'mm/deltas'
|
6
|
+
require 'mm/metric'
|
7
|
+
require 'mm/pairs'
|
8
|
+
require 'mm/ratio'
|
9
|
+
require 'mm/scaling'
|
10
|
+
require 'mm/
|
data/lib/shortcuts.yml
CHANGED
@@ -1,49 +1,49 @@
|
|
1
|
-
:olm:
|
2
|
-
:ordered: true
|
3
|
-
:pair: :linear
|
4
|
-
:scale: :none
|
5
|
-
:intra_delta: :abs
|
6
|
-
:inter_delta: :abs
|
7
|
-
:ocm:
|
8
|
-
:ordered: true
|
9
|
-
:pair: :combinatorial
|
10
|
-
:scale: :none
|
11
|
-
:intra_delta: :abs
|
12
|
-
:inter_delta: :abs
|
13
|
-
:ulm:
|
14
|
-
:ordered: false
|
15
|
-
:pair: :linear
|
16
|
-
:scale: :none
|
17
|
-
:intra_delta: :abs
|
18
|
-
:inter_delta: :mean
|
19
|
-
:ucm:
|
20
|
-
:ordered: false
|
21
|
-
:pair: :combinatorial
|
22
|
-
:scale: :none
|
23
|
-
:intra_delta: :abs
|
24
|
-
:inter_delta: :mean
|
25
|
-
:old:
|
26
|
-
:ordered: true
|
27
|
-
:pair: :linear
|
28
|
-
:scale: :none
|
29
|
-
:intra_delta: :direction
|
30
|
-
:inter_delta: :abs
|
31
|
-
:ocd:
|
32
|
-
:ordered: true
|
33
|
-
:pair: :combinatorial
|
34
|
-
:scale: :none
|
35
|
-
:intra_delta: :direction
|
36
|
-
:inter_delta: :abs
|
37
|
-
:uld:
|
38
|
-
:ordered: false
|
39
|
-
:pair: :linear
|
40
|
-
:scale: :none
|
41
|
-
:intra_delta: :direction
|
42
|
-
:inter_delta: :mean
|
43
|
-
:ucd:
|
44
|
-
:ordered: false
|
45
|
-
:pair: :combinatorial
|
46
|
-
:scale: :none
|
47
|
-
:intra_delta: :direction
|
48
|
-
:inter_delta: :mean
|
49
|
-
|
1
|
+
:olm:
|
2
|
+
:ordered: true
|
3
|
+
:pair: :linear
|
4
|
+
:scale: :none
|
5
|
+
:intra_delta: :abs
|
6
|
+
:inter_delta: :abs
|
7
|
+
:ocm:
|
8
|
+
:ordered: true
|
9
|
+
:pair: :combinatorial
|
10
|
+
:scale: :none
|
11
|
+
:intra_delta: :abs
|
12
|
+
:inter_delta: :abs
|
13
|
+
:ulm:
|
14
|
+
:ordered: false
|
15
|
+
:pair: :linear
|
16
|
+
:scale: :none
|
17
|
+
:intra_delta: :abs
|
18
|
+
:inter_delta: :mean
|
19
|
+
:ucm:
|
20
|
+
:ordered: false
|
21
|
+
:pair: :combinatorial
|
22
|
+
:scale: :none
|
23
|
+
:intra_delta: :abs
|
24
|
+
:inter_delta: :mean
|
25
|
+
:old:
|
26
|
+
:ordered: true
|
27
|
+
:pair: :linear
|
28
|
+
:scale: :none
|
29
|
+
:intra_delta: :direction
|
30
|
+
:inter_delta: :abs
|
31
|
+
:ocd:
|
32
|
+
:ordered: true
|
33
|
+
:pair: :combinatorial
|
34
|
+
:scale: :none
|
35
|
+
:intra_delta: :direction
|
36
|
+
:inter_delta: :abs
|
37
|
+
:uld:
|
38
|
+
:ordered: false
|
39
|
+
:pair: :linear
|
40
|
+
:scale: :none
|
41
|
+
:intra_delta: :direction
|
42
|
+
:inter_delta: :mean
|
43
|
+
:ucd:
|
44
|
+
:ordered: false
|
45
|
+
:pair: :combinatorial
|
46
|
+
:scale: :none
|
47
|
+
:intra_delta: :direction
|
48
|
+
:inter_delta: :mean
|
49
|
+
|
data/test/helpers.rb
CHANGED
@@ -1,22 +1,19 @@
|
|
1
|
-
module TestHelpers
|
2
|
-
# Asserts that each item in exp matches each item in act
|
3
|
-
def assert_nested_in_delta exp, act, delta = 0.001, msg = nil
|
4
|
-
exp.zip(act) do |x|
|
5
|
-
if block_given?
|
6
|
-
yield x, delta, msg
|
7
|
-
else
|
8
|
-
assert_in_delta(*x, delta, msg)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Asserts that nested values 2-deep are within a certain delta
|
14
|
-
def assert_nested_in_delta_2_deep *args
|
15
|
-
assert_nested_in_delta(*args) do |x, delta, msg|
|
16
|
-
x[0].zip(x[1]) do |y|
|
17
|
-
assert_in_delta(*y, delta, msg)
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
1
|
+
module TestHelpers
|
2
|
+
# Asserts that each item in exp matches each item in act
|
3
|
+
def assert_nested_in_delta exp, act, delta = 0.001, msg = nil
|
4
|
+
exp.zip(act) do |x|
|
5
|
+
if block_given?
|
6
|
+
yield x, delta, msg
|
7
|
+
else
|
8
|
+
assert_in_delta(*x, delta, msg)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Asserts that nested values 2-deep are within a certain delta
|
14
|
+
def assert_nested_in_delta_2_deep *args
|
15
|
+
assert_nested_in_delta(*args) do |x, delta, msg|
|
16
|
+
x[0].zip(x[1]) do |y|
|
17
|
+
assert_in_delta(*y, delta, msg)
|
18
|
+
end
|
19
|
+
|
data/test/mm/test_deltas.rb
CHANGED
@@ -12,28 +12,33 @@ class TestMM::TestDeltas < Minitest::Test
|
|
12
12
|
result = input.map {|x| MM::Deltas.abs(x)}
|
13
13
|
assert_equal exp, result
|
14
14
|
end
|
15
|
+
|
15
16
|
def test_mean_inter_delta
|
16
17
|
input = [[5, 4, 3, 6], [12, 2, 11, 7]]
|
17
18
|
exp = [4.5, 8]
|
18
19
|
result = input.map {|x| MM::Deltas.mean(x)}
|
19
20
|
assert_equal exp, result
|
20
21
|
end
|
22
|
+
|
21
23
|
def test_distance_ordered_inter_delta
|
22
24
|
input = [[-1, -1], [1, 1], [-1, 1], [-1, -1]]
|
23
25
|
exp = [0, 0, 2, 0]
|
24
26
|
result = input.map {|x| MM::Deltas.abs(x)}
|
25
27
|
assert_equal exp, result
|
26
28
|
end
|
29
|
+
|
27
30
|
def test_tenney_ordered_intra_delta
|
28
31
|
input = [[Rational(1,1), Rational(3,2)], [Rational(3,2), Rational(5,4)]]
|
29
32
|
exp = [2.585, 4.907]
|
30
33
|
assert_nested_in_delta exp, input.map {|x| MM::Deltas.tenney(x)}
|
31
34
|
end
|
35
|
+
|
32
36
|
def test_log_ratio_ordered_intra_delta
|
33
37
|
input = [[Rational(1,1), Rational(3,2)], [Rational(3,2), Rational(5,4)]]
|
34
38
|
exp = [0.585, 0.263]
|
35
39
|
assert_nested_in_delta exp, input.map {|x| MM::Deltas.log_ratio(x)}
|
36
40
|
end
|
41
|
+
|
37
42
|
def test_ratio_ordered_intra_delta
|
38
43
|
input = [[Rational(1,1), Rational(3,2)], [Rational(3,2), Rational(5,4)]]
|
39
44
|
exp = [Rational(2,3), Rational(6,5)]
|