biopsy 0.2.0 → 0.2.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: 4a78e571268545fdd69d110f2b789bb53fa5d100
4
- data.tar.gz: 3255fd3579a242fa6277c9b16d5128fe4d3c6250
3
+ metadata.gz: 3f45b9377c3de44caf8abf21b07576a6e89e0c03
4
+ data.tar.gz: 94e4a81fe98380482adc7b290f8067174684850d
5
5
  SHA512:
6
- metadata.gz: dd5c793e5af0042dd69066de1c96695e519d619a8738ad066baefc0d3015dc89ec6247d573090263f45ad3f78ea2bb8fa3df17945197d29bd48b23cee84556bc
7
- data.tar.gz: 6a9d2b2dcc4463c1ad8afe3311af4b3912b0263f53c7b1aa609a16319aa5c2348c62a3c48b4caaf7760fa6e0d18df1423644772d7bde2285e10b866f223e4aed
6
+ metadata.gz: 76d90535589d1f09f74bf424d7437a45855b1065b802bc3ba4d562cc30c1c8fd775583cd856e6de02fee919a9b34619875693a96b228ef686c7e658bb9b29ea5
7
+ data.tar.gz: 0dbc5e5d21297759affc2199ffff2fe90d25c1958a7380d531811bdded9fbe8caf8eb9fc0aed8b62ecb5d52d6f0f2e2292b480ae8a8e84c79f0e457f44f45c3a
data/README.md CHANGED
@@ -1,25 +1,43 @@
1
1
  biopsy
2
2
  ==========
3
3
 
4
+ [![Gem Version](https://badge.fury.io/rb/biopsy.png)][gem]
5
+ [![Build Status](https://secure.travis-ci.org/Blahah/biopsy.png?branch=master)][travis]
6
+ [![Dependency Status](https://gemnasium.com/Blahah/biopsy.png?travis)][gemnasium]
7
+ [![Code Climate](https://codeclimate.com/github/Blahah/biopsy.png)][codeclimate]
8
+ [![Coverage Status](https://coveralls.io/repos/Blahah/biopsy/badge.png?branch=master)][coveralls]
9
+
10
+ [gem]: https://badge.fury.io/rb/biopsy
11
+ [travis]: https://travis-ci.org/Blahah/biopsy
12
+ [gemnasium]: https://gemnasium.com/Blahah/biopsy
13
+ [codeclimate]: https://codeclimate.com/github/Blahah/biopsy
14
+ [coveralls]: https://coveralls.io/r/Blahah/biopsy
15
+
4
16
  An automatic optimisation framework for programs and pipelines.
5
17
 
6
- Biopsy is a framework for optimising any program or pipeline which produces a measurable output. By reducing the settings of one or more programs to a parameter space, and by carefully choosing objective functions with which to measure the output of the program(s), biopsy can use a range of optimisation strategies to rapidly find the settings that perform the best. Combined with a strategy for subsampling the input data, this can lead to vast time and performance improvements.
18
+ Biopsy is a framework for optimising the settings of any program or pipeline which produces a measurable output. It is particularly intended for bioinformatics, where computational pipelines take a long time to run, making optimisation of parameters using crude methods unfeasible. Biopsy will use a range of discrete optimisation strategies to rapidly find the settings that perform the best.
19
+
20
+ It can handle parameter spaces of any size: if it is possible to try every parameter combination in the time you have available, Biopsy will do this. However, Biopsy really shines when handling large numbers of parameter combinations.
7
21
 
8
- A simple example of the power of this approach is *de-novo* transcriptome assembly. Typically, the assembly process takes many GB of data as input, uses many GB of RAM and takes many hours to complete. This prevents researchers from performing full parameter sweeps, and they are therefore forced to use word-of-mouth and very basic optimisation to choose assembler settings. [Assemblotron](https://github.com/Blahah/assemblotron), which uses the Biopsy framework, can fully optimise any *de-novo* assembler to produce the optimal assembly possible given a particular input. This typically takes little more time than running a single assembly.
22
+ ## Development status
23
+
24
+ This project is in early development and is not yet ready for deployment.
25
+ Please don't report issues or request documentation until we are ready for release. If you have a burning desire to use biopsy, get in touch: rds45@cam.ac.uk.
9
26
 
10
27
  ## Installation
11
28
 
12
29
  Make sure you have Ruby installed, then:
13
30
 
14
- `gem install biopsy --pre`
31
+ `gem install biopsy`
15
32
 
16
33
  ## Usage
17
34
 
18
35
  Detailed usage instructions are on the wiki. Here's a quick overview:
19
36
 
20
- 1. Define your optimisation target. This is a program or pipeline you want to optimise, and you define it by filling in a template [YAML file](http://en.wikipedia.org/wiki/YAML). Easy!
37
+ 1. Define your optimisation target. This is a program or pipeline you want to optimise, and you define it by filling in a template YAML file and wrapping your program in a tiny Ruby launcher.
21
38
  2. Define your objective function. This is a program that analyses the output of your program and gives it a score. You define it by writing a small amount of Ruby code. Don't worry - there's a template and detailed instructions on the wiki.
22
- 3. Run Biopsy, and wait while the experiment runs.
39
+ 3. Run Biopsy, and wait while the experiment runs. Maybe grab a cup of tea, read some [hacker news](http://news.ycombinator.com).
40
+ 4. Bask in the brilliance of your new optimal settings.
23
41
 
24
42
  ### Command line examples
25
43
 
@@ -27,36 +45,11 @@ Detailed usage instructions are on the wiki. Here's a quick overview:
27
45
  `biopsy list objectives`
28
46
  `biposy run --target test_target --objective test_objective --input test_file.txt --time-limit 24h`
29
47
 
30
- ## Development status
48
+ ### Optimisation algorithms
31
49
 
32
- [![Gem Version](https://badge.fury.io/rb/biopsy.png)][gem]
33
- [![Build Status](https://secure.travis-ci.org/Blahah/biopsy.png?branch=master)][travis]
34
- [![Dependency Status](https://gemnasium.com/Blahah/biopsy.png?travis)][gemnasium]
35
- [![Code Climate](https://codeclimate.com/github/Blahah/biopsy.png)][codeclimate]
36
- [![Coverage Status](https://coveralls.io/repos/Blahah/biopsy/badge.png?branch=master)][coveralls]
37
-
38
- [gem]: https://badge.fury.io/rb/biopsy
39
- [travis]: https://travis-ci.org/Blahah/biopsy
40
- [gemnasium]: https://gemnasium.com/Blahah/biopsy
41
- [codeclimate]: https://codeclimate.com/github/Blahah/biopsy
42
- [coveralls]: https://coveralls.io/r/Blahah/biopsy
43
-
44
- This project is in alpha development and is not yet ready for deployment.
45
- Please don't report issues or request documentation until we are ready for beta release (see below for estimated timeframe).
46
-
47
- ### Roadmap
48
-
49
- | Class | Code | Tests | Docs |
50
- | ------------ | :----: | ------: | -----: |
51
- | Settings | DONE | DONE | DONE |
52
- | Target | DONE | DONE | DONE |
53
- | Domain | DONE | DONE | DONE |
54
- | Experiment | DONE | DONE | DONE |
55
- | TabuSearch | DONE | - | - |
56
- | ParameterSweeper | DONE | - | - |
57
- | ObjectiveHandler | DONE | DONE | DONE |
58
-
59
- * ~ 20/24 tasks completed, ~83% done overall
50
+ 1. Parameter Sweeper - a simple combinatorial parameter sweep, with optional subsampling of the parameter space
51
+ 2. Tabu Search - a local search with a long memory that takes the consensus of multiple searchers
52
+ 3. SPEA2 - a high performance general-purpose genetic algorithm
60
53
 
61
54
  ### Documentation
62
55
 
@@ -68,3 +61,7 @@ This is *pre-release*, *pre-publication* academic software. In lieu of a paper t
68
61
  )](http://dx.doi.org/10.6084/m9.figshare.790660) if your use of the software leads to a publication.
69
62
 
70
63
  [![Analytics](https://ga-beacon.appspot.com/UA-46900280-1/Blahah/biopsy)](https://github.com/Blahah/biopsy)
64
+
65
+ ### Software using Biopsy
66
+
67
+ - [Assemblotron](https://github.com/Blahah/assemblotron) can fully optimise any *de-novo* transcriptome assembler to produce the optimal assembly possible given a particular input. This typically takes little more time than running a single assembly.
@@ -23,10 +23,11 @@ module Biopsy
23
23
 
24
24
  # Returns a new Experiment
25
25
  def initialize(target, options:{}, threads:4, start:nil, algorithm:nil,
26
- verbosity: :quiet)
26
+ timelimit:nil, verbosity: :quiet)
27
27
  @threads = threads
28
28
  @start = start
29
29
  @algorithm = algorithm
30
+ @timelimit = timelimit
30
31
  @verbosity = verbosity
31
32
  if target.is_a? Target
32
33
  @target = target
@@ -78,6 +79,7 @@ module Biopsy
78
79
  # are met. On completion, returns the best parameter
79
80
  # set.
80
81
  def run
82
+ start_time = Time.now
81
83
  in_progress = true
82
84
  @algorithm.setup @start
83
85
  @current_params = @start
@@ -92,16 +94,21 @@ module Biopsy
92
94
  best &&
93
95
  best.key?(:score) &&
94
96
  @best[:score] > best[:score]
95
- puts "found a new best score: #{@best[:score]} \
96
- for parameters #{ptext}"
97
+ unless @verbosity == :silent
98
+ puts "found a new best score: #{@best[:score]} "+
99
+ "for parameters #{ptext}"
100
+ end
97
101
  end
98
102
  # have we finished?
99
103
  in_progress = !@algorithm.finished?
104
+ if in_progress && !(@timelimit.nil?)
105
+ in_progress = (Time.now - start_time < @timelimit)
106
+ end
100
107
  end
101
108
  @algorithm.write_data if @algorithm.respond_to? :write_data
102
109
  unless @verbosity == :silent
103
- puts "found optimum score: #{@best[:score]} for parameters \
104
- #{@best[:parameters]} in #{@iteration_count} iterations."
110
+ puts "found optimum score: #{@best[:score]} for parameters "+
111
+ "#{@best[:parameters]} in #{@iteration_count} iterations."
105
112
  end
106
113
  return @best
107
114
  end
@@ -139,7 +146,7 @@ module Biopsy
139
146
  puts msg
140
147
  end
141
148
  end
142
-
149
+
143
150
  def cleanup
144
151
  # TODO: make this work
145
152
  # remove all but essential files
@@ -93,12 +93,6 @@ module Biopsy
93
93
  # objective function(s), with keys as the keys expected by the
94
94
  # objective function
95
95
  return objective.run(raw_output, output_files, threads)
96
- rescue
97
- error = "Error: objective function #{objective.class} does not "
98
- error << "implement the run() method\nPlease refer to the "
99
- error << "documentation for instructions on adding objective functions"
100
- # raise NotImplementedError.new("message")
101
- raise NotImplementedError, error
102
96
  end
103
97
 
104
98
  # Perform a euclidean distance dimension reduction of multiple objectives
@@ -2,13 +2,16 @@
2
2
  # options = {:settings => {...}, :parameters => {...}}
3
3
  #
4
4
  # Description:
5
- # ParameterSweeper generates all combinations of a hash of arrays (options[:parameters]).
6
- # The generated combinations are each passed in turn to the constructor which returns an execute command
7
- # incorporating the parameters, and finally the target program is run with each generated command.
5
+ # ParameterSweeper generates all combinations of a hash of arrays
6
+ # (options[:parameters]).
7
+ # The generated combinations are each passed in turn to the constructor
8
+ # which returns an execute command incorporating the parameters, and finally
9
+ # the target program is run with each generated command.
8
10
  #
9
- # The constructor will also have access to an unchanging settings hash (options[:settings])
10
- # constructor proc will be passed multipule hashes in format: {:settings => {...}, :parameters => {...}}
11
- # where the values in settings remain constant, and the values in parameters vary
11
+ # The constructor will also have access to an unchanging settings hash
12
+ # (options[:settings]) constructor proc will be passed multipule hashes in
13
+ # format: {:settings => {...}, :parameters => {...}} where the values in
14
+ # settings remain constant, and the values in parameters vary
12
15
 
13
16
  require 'pp'
14
17
  require 'fileutils'
@@ -17,32 +20,52 @@ require 'threach'
17
20
  require 'logger'
18
21
 
19
22
  module Biopsy
23
+
24
+ class Combinator
25
+
26
+ include Enumerable
27
+
28
+ def initialize parameters
29
+ @parameters = parameters
30
+ end
31
+
32
+ def generate_combinations(index, opts, &block)
33
+ if index == @parameters.length
34
+ block.call opts.clone
35
+ return
36
+ end
37
+ # recurse
38
+ key = @parameters.keys[index]
39
+ @parameters[key].each do |value|
40
+ opts[key] = value
41
+ generate_combinations(index + 1, opts, &block)
42
+ end
43
+ end
44
+
45
+ def each &block
46
+ generate_combinations(0, {}, &block)
47
+ end
48
+ end
49
+
20
50
  # options - is a hash of two hashes, :settings and :parameters
21
51
  # :ranges are arrays to be parameter sweeped
22
- # ---(single values may be present, these are also remain unchanged but are accessible within the parameters hash to the constructor)
52
+ # ---(single values may be present, these are also remain unchanged
53
+ # but are accessible within the parameters hash to the constructor)
23
54
  class ParameterSweeper
24
55
 
25
- attr_reader :combinations
56
+ attr_reader :combinator, :combinations, :best
26
57
 
27
- def initialize(ranges, threads:1, limit:1000)
58
+ def initialize(ranges)
28
59
  @ranges = ranges
29
- # parameter_counter: a count of input parameters to be used
30
- @parameter_counter = 1
31
- # input_combinations: an array of arrays of input parameters
32
- @combinations = []
33
- # if the number of threads is set, update the global variable, if not default to 1
34
- @threads = threads
35
- # set the limit to the number of parameters
36
- @limit = limit
37
- # convert all options to an array so it can be handled by the generate_combinations() method
60
+ # convert all options to an array so it can be handled by the
61
+ # generate_combinations() method
38
62
  # ..this is for users entering single values e.g 4 as a parameter
39
- @ranges.each { |key, value| value = [value] unless value.kind_of? Array }
40
- self.generate_combinations(0, {})
63
+ @ranges.each_value{ |value| value = [value] unless value.kind_of? Array }
41
64
  # restrict to a subsample?
42
-
43
- if @limit < @combinations.size
44
- @combinations = @combinations.sample @limit
45
- end
65
+ @combinations = 1
66
+ @ranges.each { |r| @combinations *= r[1].size }
67
+ @is_finished = false
68
+ @combinator = (Combinator.new @ranges).to_enum
46
69
  end
47
70
 
48
71
  def setup(*_args)
@@ -56,33 +79,23 @@ module Biopsy
56
79
  def run_one_iteration(parameters, score)
57
80
  @current = { :parameters => parameters, :score => score }
58
81
  self.update_best?
59
- @combinations.pop
60
- rescue
61
- nil
82
+ return @combinator.next
83
+ rescue
84
+ @is_finished = true
85
+ return nil
62
86
  end
63
87
 
64
88
  def update_best?
89
+ raise "best is nil. should run setup first" if @best.nil?
65
90
  if @best[:score].nil? || @current[:score] > @best[:score]
66
91
  @best = @current.clone
67
92
  end
68
93
  end
69
94
 
70
- # generate all the parameter combinations to be applied
71
- def generate_combinations(index, opts)
72
- if index == @ranges.length
73
- @combinations << opts.clone
74
- return
75
- end
76
- # recurse
77
- key = @ranges.keys[index]
78
- @ranges[key].each do |value|
79
- opts[key] = value
80
- generate_combinations(index + 1, opts)
81
- end
82
- end
83
-
84
- def best
85
- @best
95
+ def next
96
+ @combinator.next
97
+ rescue
98
+ nil
86
99
  end
87
100
 
88
101
  def knows_starting_point?
@@ -90,15 +103,15 @@ module Biopsy
90
103
  end
91
104
 
92
105
  def select_starting_point
93
- @combinations.pop
106
+ @combinator.next
94
107
  end
95
108
 
96
109
  def random_start_point
97
- @combinations.pop
110
+ @combinator.next
98
111
  end
99
112
 
100
113
  def finished?
101
- @combinations.empty?
114
+ @is_finished
102
115
  end
103
116
 
104
117
  # True if this algorithm chooses its own starting point
@@ -106,4 +119,4 @@ module Biopsy
106
119
  true
107
120
  end
108
121
  end
109
- end
122
+ end
@@ -6,7 +6,7 @@ module Biopsy
6
6
  module VERSION
7
7
  MAJOR = 0
8
8
  MINOR = 2
9
- PATCH = 0
9
+ PATCH = 1
10
10
 
11
11
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
12
12
  end
data/lib/biopsy.rb CHANGED
@@ -5,7 +5,7 @@ require "biopsy/experiment"
5
5
  require "biopsy/target"
6
6
  require "biopsy/objective_handler"
7
7
  require "biopsy/objective_function"
8
- require "biopsy/optimisers/genetic_algorithm"
8
+ require "biopsy/optimisers/spea2"
9
9
  require "biopsy/optimisers/tabu_search"
10
10
  require "biopsy/optimisers/parameter_sweeper"
11
- require "biopsy/objectives/fastest_optimum"
11
+ require "biopsy/objectives/fastest_optimum"
data/test/helper.rb CHANGED
@@ -57,14 +57,14 @@ class Helper
57
57
  opt: true,
58
58
  min: -40,
59
59
  max: 40,
60
- step: 2
60
+ step: 5
61
61
  },
62
62
  :b => {
63
63
  type: 'integer',
64
64
  opt: true,
65
65
  min: 0,
66
66
  max: 40,
67
- step: 2
67
+ step: 5
68
68
  },
69
69
  :c => {
70
70
  type: 'integer',
@@ -84,8 +84,9 @@ class Helper
84
84
  end
85
85
 
86
86
  # Create a valid target definition in the target dir
87
- def create_valid_target
87
+ def create_valid_target slow: false
88
88
  data = self.target_data
89
+ data[:slow] = slow
89
90
  name = 'target_test'
90
91
  @target_path = File.join(@target_dir, name + '.yml')
91
92
  self.yaml_dump data, @target_path
@@ -99,6 +100,9 @@ class TargetTest
99
100
  require 'yaml'
100
101
 
101
102
  def run(params)
103
+ if (params[:slow])
104
+ sleep 0.1
105
+ end
102
106
  File.open('output.txt', 'w') do |f|
103
107
  f.puts(params.to_yaml)
104
108
  end
@@ -139,6 +143,7 @@ class TestObjective < Biopsy::ObjectiveFunction
139
143
  a = input[:a].to_i
140
144
  b = input[:b].to_i
141
145
  c = input[:c].to_i
146
+
142
147
  value = - Math.sqrt((a-4)**2) - Math.sqrt((b-4)**2) - Math.sqrt((c-4)**2)
143
148
  {
144
149
  :optimum => @optimum,
@@ -49,7 +49,7 @@ class TestExperiment < Test::Unit::TestCase
49
49
  end
50
50
 
51
51
  should "respect user's choice of starting point" do
52
- s = {:a => 4, :b => 2}
52
+ s = {:a => 4, :b => 2}
53
53
  e = Biopsy::Experiment.new('target_test', start: s, verbosity: :silent)
54
54
  assert_equal s, e.start
55
55
  end
@@ -68,13 +68,29 @@ class TestExperiment < Test::Unit::TestCase
68
68
  end
69
69
  end
70
70
 
71
- should 'always finish running an experiment' do
72
- assert_equal false, true, 'not yet implemented'
71
+ should 'respect time limits' do
72
+ # create a slow target
73
+ target_name = @h.create_valid_target(slow: true)
74
+ @target = Biopsy::Target.new
75
+ @target.load_by_name target_name
76
+ limits = [0.1, 0.2, 0.5, 1]
77
+ limits.each do |limit|
78
+ e = Biopsy::Experiment.new('target_test',
79
+ verbosity: :silent, timelimit: limit)
80
+ start = Time.now
81
+ e.run
82
+ finish = Time.now
83
+ assert (finish - start) < (limit + 0.2)
84
+ end
85
+ # reset the target
86
+ target_name = @h.create_valid_target(slow: false)
87
+ @target = Biopsy::Target.new
88
+ @target.load_by_name target_name
73
89
  end
74
90
 
75
91
  should 'run really quickly when starting from the optimal parameters' do
76
92
  Dir.chdir @h.tmp_dir do
77
- s = {:a => 4, :b => 4, :c => 4}
93
+ s = {:a => 4, :b => 4, :c => 4}
78
94
  e = Biopsy::Experiment.new('target_test', start: s, verbosity: :silent)
79
95
  known_best = -4
80
96
  best_found = e.run[:score]
@@ -82,12 +98,12 @@ class TestExperiment < Test::Unit::TestCase
82
98
  end
83
99
  end
84
100
 
85
- should 'run using the parameter sweeper (with limit)' do
101
+ should 'run using the parameter sweeper' do
86
102
  Dir.chdir @h.tmp_dir do
87
- p = Biopsy::ParameterSweeper.new(@target.parameters, limit: 250)
103
+ p = Biopsy::ParameterSweeper.new(@target.parameters)
88
104
  e = Biopsy::Experiment.new('target_test', algorithm: p, verbosity: :silent)
89
- best_found = e.run[:score]
90
- assert best_found
105
+ best_found = e.run[:parameters]
106
+ assert_equal best_found, {:a=>4, :b=>4, :c=>4}
91
107
  end
92
108
  end
93
109
  end # Experiment context
@@ -7,16 +7,44 @@ class TestParameterSweeper < Test::Unit::TestCase
7
7
  setup do
8
8
  ranges = {:a => [1,2,3], :b => [1,2,3]}
9
9
  @sweep = Biopsy::ParameterSweeper.new(ranges)
10
+ @sweep.setup
10
11
  end
11
12
 
12
- should "generate a list of combinations" do
13
+ should "calculate number of combinations" do
13
14
  c = @sweep.combinations
14
- assert_equal c.size, 9
15
- assert_equal c, [{:a=>1, :b=>1}, {:a=>1, :b=>2}, {:a=>1, :b=>3},
15
+ assert_equal c, 9
16
+ end
17
+
18
+ should 'generate list of combinations' do
19
+ list=[]
20
+ 9.times do
21
+ list << @sweep.next
22
+ end
23
+ assert_equal list, [{:a=>1, :b=>1}, {:a=>1, :b=>2}, {:a=>1, :b=>3},
16
24
  {:a=>2, :b=>1}, {:a=>2, :b=>2}, {:a=>2, :b=>3},
17
25
  {:a=>3, :b=>1}, {:a=>3, :b=>2}, {:a=>3, :b=>3}]
18
26
  end
19
27
 
28
+ should "exit gracefully when you ask for too much" do
29
+ c = 1
30
+ 10.times do
31
+ c = @sweep.run_one_iteration(nil, 0)
32
+ end
33
+ assert_equal c, nil
34
+ end
35
+
36
+ should 'check if finished' do
37
+ assert_equal @sweep.finished?, false, "at the start"
38
+ 8.times do
39
+ @sweep.run_one_iteration(nil, 0)
40
+ end
41
+ assert_equal @sweep.finished?, false, "after 8"
42
+ @sweep.run_one_iteration(nil, 0)
43
+ assert_equal @sweep.finished?, false, "after 9"
44
+ @sweep.run_one_iteration(nil, 0)
45
+ assert_equal @sweep.finished?, true, "after 10"
46
+ end
47
+
20
48
  end # Experiment context
21
49
 
22
50
  end # TestExperiment
data/test/test_target.rb CHANGED
@@ -162,11 +162,12 @@ class TestTarget < Test::Unit::TestCase
162
162
  }
163
163
  @target.generate_parameters params
164
164
  assert_equal @target.parameters, {:a => ["yes", "no", "maybe"]}
165
- assert_equal @target.options, {:b=>{:type=>"integer", :opt=>false, :values=>0}}
165
+ assert_equal @target.options,
166
+ {:b=> { :type=>"integer", :opt=>false, :values=>0 } }
166
167
  end
167
168
 
168
- should "pass missing method calls to constructor iff \
169
- it directly defines them" do
169
+ should "pass missing method calls to constructor iff "+
170
+ "it directly defines them" do
170
171
  # this method is defined on the constructor in helper.rb
171
172
  assert_send([@target, :fake_method],
172
173
  'valid method not passed to constructor')
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: biopsy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
- - Richard Smith
7
+ - Richard Smith-Unna
8
+ - Parsa Akbari
9
+ - Chris Bournsell
8
10
  autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2014-04-26 00:00:00.000000000 Z
13
+ date: 2015-06-02 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: rake
@@ -16,56 +18,74 @@ dependencies:
16
18
  requirements:
17
19
  - - "~>"
18
20
  - !ruby/object:Gem::Version
19
- version: '10.1'
21
+ version: '10.4'
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 10.4.2
20
25
  type: :runtime
21
26
  prerelease: false
22
27
  version_requirements: !ruby/object:Gem::Requirement
23
28
  requirements:
24
29
  - - "~>"
25
30
  - !ruby/object:Gem::Version
26
- version: '10.1'
31
+ version: '10.4'
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 10.4.2
27
35
  - !ruby/object:Gem::Dependency
28
36
  name: threach
29
37
  requirement: !ruby/object:Gem::Requirement
30
38
  requirements:
31
- - - ">="
39
+ - - "~>"
32
40
  - !ruby/object:Gem::Version
33
- version: '0'
41
+ version: '0.2'
34
42
  type: :runtime
35
43
  prerelease: false
36
44
  version_requirements: !ruby/object:Gem::Requirement
37
45
  requirements:
38
- - - ">="
46
+ - - "~>"
39
47
  - !ruby/object:Gem::Version
40
- version: '0'
48
+ version: '0.2'
41
49
  - !ruby/object:Gem::Dependency
42
50
  name: rubystats
43
51
  requirement: !ruby/object:Gem::Requirement
44
52
  requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.2'
45
56
  - - ">="
46
57
  - !ruby/object:Gem::Version
47
- version: '0'
58
+ version: 0.2.3
48
59
  type: :runtime
49
60
  prerelease: false
50
61
  version_requirements: !ruby/object:Gem::Requirement
51
62
  requirements:
63
+ - - "~>"
64
+ - !ruby/object:Gem::Version
65
+ version: '0.2'
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '0'
68
+ version: 0.2.3
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: statsample
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
59
76
  - - ">="
60
77
  - !ruby/object:Gem::Version
61
- version: '0'
78
+ version: 1.4.3
62
79
  type: :runtime
63
80
  prerelease: false
64
81
  version_requirements: !ruby/object:Gem::Requirement
65
82
  requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.4'
66
86
  - - ">="
67
87
  - !ruby/object:Gem::Version
68
- version: '0'
88
+ version: 1.4.3
69
89
  - !ruby/object:Gem::Dependency
70
90
  name: minitest
71
91
  requirement: !ruby/object:Gem::Requirement
@@ -128,46 +148,45 @@ dependencies:
128
148
  requirements:
129
149
  - - "~>"
130
150
  - !ruby/object:Gem::Version
131
- version: 0.6.7
151
+ version: '0.8'
132
152
  type: :development
133
153
  prerelease: false
134
154
  version_requirements: !ruby/object:Gem::Requirement
135
155
  requirements:
136
156
  - - "~>"
137
157
  - !ruby/object:Gem::Version
138
- version: 0.6.7
158
+ version: '0.8'
139
159
  description:
140
160
  email: rds45@cam.ac.uk
141
161
  executables: []
142
162
  extensions: []
143
163
  extra_rdoc_files: []
144
164
  files:
165
+ - LICENSE.txt
166
+ - README.md
145
167
  - Rakefile
146
168
  - lib/biopsy.rb
147
- - lib/biopsy/version.rb
169
+ - lib/biopsy/base_extensions.rb
170
+ - lib/biopsy/experiment.rb
171
+ - lib/biopsy/objective_function.rb
148
172
  - lib/biopsy/objective_handler.rb
149
173
  - lib/biopsy/objectives/fastest_optimum.rb
150
- - lib/biopsy/settings.rb
151
- - lib/biopsy/optimisers/tabu_search.rb
152
- - lib/biopsy/optimisers/genetic_algorithm.rb
153
- - lib/biopsy/optimisers/spea2.rb
154
174
  - lib/biopsy/optimisers/parameter_sweeper.rb
155
- - lib/biopsy/objective_function.rb
175
+ - lib/biopsy/optimisers/spea2.rb
176
+ - lib/biopsy/optimisers/tabu_search.rb
177
+ - lib/biopsy/settings.rb
156
178
  - lib/biopsy/target.rb
157
- - lib/biopsy/base_extensions.rb
158
- - lib/biopsy/experiment.rb
159
- - test/test_parametersweep.rb
160
- - test/test_target.rb
161
- - test/test_hash.rb
162
- - test/test_string.rb
163
- - test/helper.rb
179
+ - lib/biopsy/version.rb
164
180
  - test/brokenconfig.yml
165
- - test/test_objective_handler.rb
181
+ - test/helper.rb
182
+ - test/test_experiment.rb
166
183
  - test/test_file.rb
184
+ - test/test_hash.rb
185
+ - test/test_objective_handler.rb
186
+ - test/test_parametersweep.rb
167
187
  - test/test_settings.rb
168
- - test/test_experiment.rb
169
- - README.md
170
- - LICENSE.txt
188
+ - test/test_string.rb
189
+ - test/test_target.rb
171
190
  homepage: https://github.com/Blahah/biopsy
172
191
  licenses: []
173
192
  metadata: {}
@@ -187,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
206
  version: '0'
188
207
  requirements: []
189
208
  rubyforge_project:
190
- rubygems_version: 2.1.4
209
+ rubygems_version: 2.2.2
191
210
  signing_key:
192
211
  specification_version: 4
193
212
  summary: framework for optimising any computational pipeline or program
@@ -1,244 +0,0 @@
1
- require 'csv'
2
- require 'pp'
3
-
4
- $global = 0
5
-
6
- module Biopsy
7
-
8
- class Generation
9
- attr_reader :best, :population_homogenosity
10
-
11
- def initialize (population_size, parameter_ranges)
12
- @population_homogenosity = 0
13
- @population_size = population_size
14
- @current_generation = []
15
- @ranges = parameter_ranges
16
- @MUTATION_RATE = 0.40
17
- @best = {
18
- :parameters => nil,
19
- :score => 0.0
20
- }
21
- end
22
-
23
- # insert the next chromosome into the generation
24
- def next_chromosome (chromosome)
25
- @current_generation += [chromosome]
26
- end
27
-
28
- def update_best? (current)
29
- @best = current if current[:score] > @best[:score]
30
- end
31
-
32
- # is the generation now full?
33
- def last?
34
- return @current_generation.length == @population_size
35
- end
36
-
37
- def run_generation
38
- #pp @current_generation if $global%100 == 0
39
- $global += 1
40
- #homogeneous_test
41
- selection_process
42
- crossover
43
-
44
- return @current_generation
45
- end
46
-
47
- ###################################
48
- # ----remainder stochastic sampling (stochastic universal sampling method)----
49
- # apply obj function on parameter_sets, rank parameter_sets by obj func score
50
- # scale obj func score to ranking where: highest rank=2, lowest rank=0
51
- # for each integer in rank reproduce += 1, for decimal allow random reproduction (based on size of decimal)
52
- def selection_process
53
- current_generation_temp = []
54
- #apply obj func on all params, store score in @current_generation[X][:score]
55
- @current_generation.each do |chromosome|
56
- current_generation_temp << {:parameters => chromosome[:parameters], :score => chromosome[:score]}
57
- end
58
- # sort @current_generation by objective function score (ASC), replace @current_generation w/ temporary array
59
- @current_generation = current_generation_temp.sort {|a, b| a[:score] <=> b[:score]}
60
- # the highest rank is 2.0, generate step_size (difference in rank between each element)
61
- step_size = 2.0/(@current_generation.length-1)
62
- # counter to be used when assigning rank
63
- counter = 0
64
- # next_generation temporary array, @current_generation is replaced by next_generation after loop
65
- next_generation = []
66
- # switch scores with ranks
67
- @current_generation.each do |chromosome|
68
- # rank (asc) is the order in which the element appears (counter) times step_size so that the max is 2
69
- rank = counter * step_size
70
- next_generation << {:parameters => chromosome[:parameters], :score => rank} if rank >= 1.0
71
- next_generation << {:parameters => chromosome[:parameters], :score => rank} if rank >= 2.0
72
- next_generation << {:parameters => chromosome[:parameters], :score => rank} if rand <= rank.modulo(1)
73
- counter += 1
74
- end
75
- # if population is too small
76
- while next_generation.length < @population_size
77
- select_chromosome = next_generation.sample(1)[0]
78
- next_generation << select_chromosome
79
- end
80
- while next_generation.length > @population_size
81
- select_chromosome_index = next_generation.index(next_generation.sample(1)[0])
82
- next_generation.delete_at(select_chromosome_index)
83
- end
84
- # sort @current_generation by objective function score (ASC), replace @current_generation w/ temporary array
85
- @current_generation = next_generation.sort {|a, b| a[:score] <=> b[:score]}
86
- return
87
- end
88
-
89
- def crossover
90
- def mating_process(mother, father)
91
- children = [{:parameters=>{}}, {:parameters=>{}}]
92
- mother[:parameters].each do |mother_key, mother_value|
93
- if rand <= 0.5
94
- children[0][:parameters][mother_key.to_sym] = mother_value
95
- children[1][:parameters][mother_key.to_sym] = father[:parameters][mother_key.to_sym]
96
- else
97
- children[0][:parameters][mother_key.to_sym] = father[:parameters][mother_key.to_sym]
98
- children[1][:parameters][mother_key.to_sym] = mother_value
99
- end
100
- end
101
- return children
102
- end
103
- # mate the best quarter with the best half
104
- best_quarter_num = (@current_generation.length.to_f/4.0).round
105
- best_half_num = best_quarter_num
106
-
107
- best_quarter = @current_generation[-best_quarter_num..-1]
108
- best_half = @current_generation[-(best_quarter_num+best_half_num)..-(best_quarter_num+1)]
109
- children = []
110
- best_quarter.each do |father|
111
- twins = mating_process(best_half.shuffle!.pop, father)
112
- children += twins.map{|value| value}
113
- end
114
- (0..(children.length-1)).each do |num|
115
- @current_generation.delete_at(0)
116
- end
117
- children.each do |child|
118
- if @MUTATION_RATE > rand
119
- children.delete_at(children.index(child))
120
- children += [generateMutation(child)]
121
- end
122
- end
123
-
124
- @current_generation += children
125
- return true
126
- end
127
-
128
- def generateMutation chromosome
129
- if !@mutation_wheel
130
- @mutation_wheel = [{}, 0]
131
- total_param_ranges = 0
132
- @ranges.each do |key, value|
133
- next if value.length <= 1
134
- total_param_ranges += value.length
135
- @mutation_wheel[0][key.to_sym] = total_param_ranges
136
- end
137
- @mutation_wheel[1] = total_param_ranges
138
- end
139
- mutation_location = rand(1..@mutation_wheel[1])
140
- temp_options_params = Marshal.load(Marshal.dump(@ranges))
141
- @mutation_wheel[0].each do |key, value|
142
- next if value < mutation_location
143
- temp_options_params[key.to_sym].delete(chromosome[:parameters][key.to_sym])
144
- chromosome[:parameters][key.to_sym] = temp_options_params[key.to_sym].sample(1)[0]
145
- break
146
- end
147
- return chromosome
148
- end
149
-
150
- def homogeneous_test
151
- homo_val = 0
152
- (0..(@current_generation.length-1)).each do |i|
153
- (i..(@current_generation.length-1)).each do |j|
154
- next if i == j
155
- @current_generation[i][:parameters].each do |key, val|
156
- homo_val += 1 if val == @current_generation[j][:parameters][key.to_sym]
157
- end
158
- end
159
- end
160
- n_value = @current_generation.length-1
161
- sum = (n_value/2)*(n_value+1)
162
- @population_homogenosity = (homo_val/(sum*@current_generation[0][:parameters].length).to_f)
163
- end
164
-
165
- def get_population
166
- if self.last?
167
- return @current_generation
168
- else
169
- return false
170
- end
171
- end
172
-
173
- end # Generation
174
-
175
-
176
- class GeneticAlgorithm
177
- attr_reader :current, :best, :generation_no, :get_homog
178
-
179
- def initialize (population_size, parameter_ranges)
180
- @ranges = parameter_ranges
181
- @population_size = population_size
182
- @current_generation = Generation.new(@population_size, @ranges)
183
- @best = {
184
- :parameters => nil,
185
- :score => 0.0
186
- }
187
- end
188
-
189
- def run
190
- nil
191
- end
192
-
193
- def run_one_iteration (parameters, score)
194
- @current = {:parameters => parameters, :score => score}
195
- # update best score?
196
- self.update_best? @current
197
- # push next chromosome to GA, generation will compute if population size is full
198
- return self.next_candidate @current
199
- # update tabu list
200
- #self.update_tabu
201
- #@current
202
- end
203
-
204
- def update_best? (current)
205
- # ... runs an identical method in GenerationHandler
206
- @current_generation.update_best? current
207
- @best = current if current[:score] > @best[:score]
208
- end
209
-
210
- def next_candidate (chromosome)
211
- # .. will run update ga if @current_generation.last? is true
212
- @current_generation.next_chromosome(chromosome)
213
-
214
- if @current_generation.last?
215
- return self.update_ga
216
- end
217
- return @current
218
- end
219
-
220
- def update_ga
221
- # ... will run to next generation
222
- store = @current_generation.run_generation
223
- @current_generation.homogeneous_test
224
- @get_homog = @current_generation.population_homogenosity
225
- @current_generation = Generation.new(@population_size, @ranges)
226
- return store
227
- end
228
-
229
- def finished?
230
- false
231
- end
232
-
233
- ##############################
234
- def generate_chromosome
235
- return Hash[@ranges.map { |param, range| [param, range.sample] }]
236
- end
237
-
238
- def get_population
239
- return @current_generation.get_population
240
- end
241
-
242
- end # GeneticAlgorithm
243
-
244
- end # Biopsy