evoasm 0.0.2.pre7 → 0.1.0.pre2

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.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/.gdbinit +41 -0
  3. data/.gitignore +1 -2
  4. data/.gitmodules +3 -0
  5. data/.rubocop.yml +8 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.md +660 -0
  8. data/Makefile +1 -1
  9. data/README.md +17 -9
  10. data/Rakefile +39 -107
  11. data/bin/gdb +1 -1
  12. data/bin/gdb_loop +4 -0
  13. data/docs/FindingInstructions.md +17 -0
  14. data/docs/JIT.md +14 -0
  15. data/docs/SymbolicRegression.md +102 -0
  16. data/docs/Visualization.md +29 -0
  17. data/docs/examples/bit_insts.rb +44 -0
  18. data/docs/examples/jit.rb +26 -0
  19. data/docs/examples/loss.gif +0 -0
  20. data/docs/examples/program.png +0 -0
  21. data/docs/examples/sym_reg.rb +64 -0
  22. data/docs/examples/vis.rb +38 -0
  23. data/evoasm.gemspec +21 -15
  24. data/ext/evoasm_ext/Rakefile +3 -0
  25. data/ext/evoasm_ext/compile.rake +35 -0
  26. data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.c +226 -0
  27. data/ext/evoasm_ext/libevoasm/src/evoasm-alloc.h +84 -0
  28. data/ext/evoasm_ext/libevoasm/src/evoasm-arch.c +52 -0
  29. data/ext/evoasm_ext/libevoasm/src/evoasm-arch.h +101 -0
  30. data/ext/evoasm_ext/libevoasm/src/evoasm-bitmap.h +158 -0
  31. data/ext/evoasm_ext/libevoasm/src/evoasm-buf.c +204 -0
  32. data/ext/evoasm_ext/libevoasm/src/evoasm-buf.h +109 -0
  33. data/ext/evoasm_ext/libevoasm/src/evoasm-domain.c +124 -0
  34. data/ext/evoasm_ext/libevoasm/src/evoasm-domain.h +279 -0
  35. data/ext/evoasm_ext/libevoasm/src/evoasm-error.c +65 -0
  36. data/ext/evoasm_ext/libevoasm/src/evoasm-error.h +108 -0
  37. data/ext/evoasm_ext/{evoasm-log.c → libevoasm/src/evoasm-log.c} +36 -18
  38. data/ext/evoasm_ext/libevoasm/src/evoasm-log.h +93 -0
  39. data/ext/evoasm_ext/libevoasm/src/evoasm-param.c +22 -0
  40. data/ext/evoasm_ext/libevoasm/src/evoasm-param.h +33 -0
  41. data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.c +192 -0
  42. data/ext/evoasm_ext/libevoasm/src/evoasm-pop-params.h +60 -0
  43. data/ext/evoasm_ext/libevoasm/src/evoasm-pop.c +1323 -0
  44. data/ext/evoasm_ext/libevoasm/src/evoasm-pop.h +107 -0
  45. data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.c +116 -0
  46. data/ext/evoasm_ext/libevoasm/src/evoasm-program-io.h +60 -0
  47. data/ext/evoasm_ext/libevoasm/src/evoasm-program.c +1827 -0
  48. data/ext/evoasm_ext/libevoasm/src/evoasm-program.h +167 -0
  49. data/ext/evoasm_ext/libevoasm/src/evoasm-rand.c +65 -0
  50. data/ext/evoasm_ext/libevoasm/src/evoasm-rand.h +76 -0
  51. data/ext/evoasm_ext/libevoasm/src/evoasm-signal.c +106 -0
  52. data/ext/evoasm_ext/libevoasm/src/evoasm-signal.h +58 -0
  53. data/ext/evoasm_ext/libevoasm/src/evoasm-util.h +112 -0
  54. data/ext/evoasm_ext/libevoasm/src/evoasm-x64.c +925 -0
  55. data/ext/evoasm_ext/libevoasm/src/evoasm-x64.h +277 -0
  56. data/ext/evoasm_ext/libevoasm/src/evoasm.c +28 -0
  57. data/ext/evoasm_ext/libevoasm/src/evoasm.h +35 -0
  58. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-enums.h +2077 -0
  59. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.c +191203 -0
  60. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-insts.h +1713 -0
  61. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.c +348 -0
  62. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-misc.h +93 -0
  63. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.c +51 -0
  64. data/ext/evoasm_ext/libevoasm/src/gen/evoasm-x64-params.h +509 -0
  65. data/lib/evoasm.rb +28 -11
  66. data/lib/evoasm/buffer.rb +105 -0
  67. data/lib/evoasm/capstone.rb +100 -0
  68. data/lib/evoasm/domain.rb +116 -0
  69. data/lib/evoasm/error.rb +37 -16
  70. data/lib/evoasm/exception_error.rb +19 -0
  71. data/lib/evoasm/ffi_ext.rb +53 -0
  72. data/lib/evoasm/libevoasm.rb +286 -0
  73. data/lib/evoasm/libevoasm/x64_enums.rb +1967 -0
  74. data/lib/evoasm/parameter.rb +20 -0
  75. data/lib/evoasm/population.rb +145 -0
  76. data/lib/evoasm/population/parameters.rb +227 -0
  77. data/lib/evoasm/population/plotter.rb +89 -0
  78. data/lib/evoasm/prng.rb +64 -0
  79. data/lib/evoasm/program.rb +195 -12
  80. data/lib/evoasm/program/io.rb +144 -0
  81. data/lib/evoasm/test.rb +8 -0
  82. data/lib/evoasm/version.rb +1 -1
  83. data/lib/evoasm/x64.rb +115 -0
  84. data/lib/evoasm/x64/cpu_state.rb +95 -0
  85. data/lib/evoasm/x64/instruction.rb +109 -0
  86. data/lib/evoasm/x64/operand.rb +156 -0
  87. data/lib/evoasm/x64/parameters.rb +211 -0
  88. data/test/helpers/population_helper.rb +128 -0
  89. data/test/helpers/test_helper.rb +1 -0
  90. data/test/helpers/x64_helper.rb +24 -0
  91. data/test/integration/bitwise_reverse_test.rb +41 -0
  92. data/test/integration/gcd_test.rb +52 -0
  93. data/test/integration/popcnt_test.rb +46 -0
  94. data/test/integration/sym_reg_test.rb +68 -0
  95. data/test/unit/evoasm/buffer_test.rb +48 -0
  96. data/test/unit/evoasm/capstone_test.rb +18 -0
  97. data/test/unit/evoasm/domain_test.rb +55 -0
  98. data/test/unit/evoasm/population/parameters_test.rb +106 -0
  99. data/test/unit/evoasm/population_test.rb +96 -0
  100. data/test/unit/evoasm/prng_test.rb +47 -0
  101. data/test/unit/evoasm/x64/cpu_state_test.rb +73 -0
  102. data/test/unit/evoasm/x64/encoding_test.rb +320 -0
  103. data/test/unit/evoasm/x64/instruction_access_test.rb +177 -0
  104. data/test/unit/evoasm/x64/instruction_encoding_test.rb +780 -0
  105. data/test/unit/evoasm/x64/instruction_test.rb +62 -0
  106. data/test/unit/evoasm/x64/parameters_test.rb +65 -0
  107. data/test/unit/evoasm/x64_test.rb +52 -0
  108. metadata +195 -89
  109. data/Gemfile.rake +0 -8
  110. data/Gemfile.rake.lock +0 -51
  111. data/LICENSE.txt +0 -373
  112. data/data/tables/README.md +0 -19
  113. data/data/tables/x64.csv +0 -1684
  114. data/data/templates/evoasm-x64.c.erb +0 -319
  115. data/data/templates/evoasm-x64.h.erb +0 -126
  116. data/examples/abs.yml +0 -20
  117. data/examples/popcnt.yml +0 -17
  118. data/examples/sym_reg.yml +0 -26
  119. data/exe/evoasm-search +0 -13
  120. data/ext/evoasm_ext/evoasm-alloc.c +0 -145
  121. data/ext/evoasm_ext/evoasm-alloc.h +0 -59
  122. data/ext/evoasm_ext/evoasm-arch.c +0 -44
  123. data/ext/evoasm_ext/evoasm-arch.h +0 -161
  124. data/ext/evoasm_ext/evoasm-bitmap.h +0 -114
  125. data/ext/evoasm_ext/evoasm-buf.c +0 -130
  126. data/ext/evoasm_ext/evoasm-buf.h +0 -47
  127. data/ext/evoasm_ext/evoasm-error.c +0 -31
  128. data/ext/evoasm_ext/evoasm-error.h +0 -75
  129. data/ext/evoasm_ext/evoasm-free-list.c.tmpl +0 -121
  130. data/ext/evoasm_ext/evoasm-free-list.h.tmpl +0 -86
  131. data/ext/evoasm_ext/evoasm-log.h +0 -69
  132. data/ext/evoasm_ext/evoasm-misc.c +0 -23
  133. data/ext/evoasm_ext/evoasm-misc.h +0 -282
  134. data/ext/evoasm_ext/evoasm-param.h +0 -37
  135. data/ext/evoasm_ext/evoasm-search.c +0 -2145
  136. data/ext/evoasm_ext/evoasm-search.h +0 -214
  137. data/ext/evoasm_ext/evoasm-util.h +0 -40
  138. data/ext/evoasm_ext/evoasm-x64.c +0 -275624
  139. data/ext/evoasm_ext/evoasm-x64.h +0 -5436
  140. data/ext/evoasm_ext/evoasm.c +0 -7
  141. data/ext/evoasm_ext/evoasm.h +0 -23
  142. data/ext/evoasm_ext/evoasm_ext.c +0 -1757
  143. data/ext/evoasm_ext/extconf.rb +0 -31
  144. data/lib/evoasm/cli.rb +0 -6
  145. data/lib/evoasm/cli/search.rb +0 -127
  146. data/lib/evoasm/core_ext.rb +0 -1
  147. data/lib/evoasm/core_ext/array.rb +0 -9
  148. data/lib/evoasm/core_ext/integer.rb +0 -10
  149. data/lib/evoasm/core_ext/kwstruct.rb +0 -13
  150. data/lib/evoasm/core_ext/range.rb +0 -5
  151. data/lib/evoasm/examples.rb +0 -27
  152. data/lib/evoasm/gen.rb +0 -8
  153. data/lib/evoasm/gen/enum.rb +0 -169
  154. data/lib/evoasm/gen/name_util.rb +0 -80
  155. data/lib/evoasm/gen/state.rb +0 -176
  156. data/lib/evoasm/gen/state_dsl.rb +0 -152
  157. data/lib/evoasm/gen/strio.rb +0 -27
  158. data/lib/evoasm/gen/translator.rb +0 -1102
  159. data/lib/evoasm/gen/version.rb +0 -5
  160. data/lib/evoasm/gen/x64.rb +0 -237
  161. data/lib/evoasm/gen/x64/funcs.rb +0 -495
  162. data/lib/evoasm/gen/x64/inst.rb +0 -781
  163. data/lib/evoasm/search.rb +0 -40
  164. data/lib/evoasm/tasks/gen_task.rb +0 -86
  165. data/lib/evoasm/tasks/template_task.rb +0 -52
  166. data/test/test_helper.rb +0 -1
  167. data/test/x64/test_helper.rb +0 -19
  168. data/test/x64/x64_test.rb +0 -87
@@ -0,0 +1,20 @@
1
+ require 'evoasm/domain'
2
+
3
+ module Evoasm
4
+ # Base class for all parameters.
5
+ class Parameter < FFI::Pointer
6
+
7
+ # @return [Integer] a numeric identifier for this parameter
8
+ def id
9
+ Libevoasm.param_get_id self
10
+ end
11
+
12
+ # @return [Domain] the domain associated with this parameter
13
+ def domain
14
+ domain = Domain.wrap Libevoasm.param_get_domain(self)
15
+ domain.autorelease = false
16
+
17
+ domain
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,145 @@
1
+ require 'evoasm/error'
2
+ require 'ffi'
3
+
4
+ module Evoasm
5
+ class Population < FFI::AutoPointer
6
+
7
+ # @return [Population::Parameters] population parameters
8
+ attr_reader :parameters
9
+
10
+ # @!visibility private
11
+ def self.release(ptr)
12
+ Libevoasm.pop_destroy(ptr)
13
+ Libevoasm.pop_free(ptr)
14
+ end
15
+
16
+ # @param parameters [Population::Parameters] the population parameters
17
+ # @param architecture [Symbol] architecture, currently only +:x64+ is supported
18
+ def initialize(parameters, architecture = Evoasm.architecture)
19
+ @parameters = parameters
20
+
21
+ ptr = Libevoasm.pop_alloc
22
+ unless Libevoasm.pop_init ptr, architecture, @parameters
23
+ raise Error.last
24
+ end
25
+
26
+ super(ptr)
27
+ end
28
+
29
+ # Evaluates all programs and kernels in the population
30
+ # @return [void]
31
+ def evaluate
32
+ unless Libevoasm.pop_eval self
33
+ raise Error.last
34
+ end
35
+ end
36
+
37
+ # Seeds the population with random individuals
38
+ # @return [void]
39
+ def seed
40
+ Libevoasm.pop_seed self
41
+ end
42
+
43
+ # @return [Float] the loss of the best program found so far
44
+ # @see #best_program
45
+ def best_loss
46
+ Libevoasm.pop_get_best_loss self
47
+ end
48
+
49
+ # @return [Program] the best program found so far
50
+ def best_program
51
+ program = Program.new
52
+ unless Libevoasm.pop_load_best_program self, program
53
+ raise Error.last
54
+ end
55
+
56
+ program
57
+ end
58
+
59
+ # @!visibility private
60
+ def loss_samples
61
+ Array.new(@parameters.deme_count) do |deme_index|
62
+ data_ptr_ptr = FFI::MemoryPointer.new :pointer, 1
63
+ len = Libevoasm.pop_get_loss_samples self, deme_index, data_ptr_ptr
64
+ data_ptr = data_ptr_ptr.read_pointer
65
+ data_ptr.read_array_of_float len
66
+ end
67
+ end
68
+
69
+ # Gives a five-number summary for each deme, program and kernel.
70
+ # @return [Array] a 2-dimensional array of summaries.
71
+ def summary(flat: false)
72
+ summary_len = Libevoasm.pop_summary_len self
73
+ summary_ptr = FFI::MemoryPointer.new :float, summary_len
74
+ unless Libevoasm.pop_calc_summary self, summary_ptr
75
+ raise Error.last
76
+ end
77
+
78
+ summary = summary_ptr.read_array_of_float(summary_len).each_slice(summary_len / @parameters.deme_count).to_a
79
+ unless flat
80
+ summary.map!{|deme_summary| deme_summary.each_slice(5).to_a}
81
+ end
82
+
83
+ summary
84
+ end
85
+
86
+ # Execute a single generational cycle
87
+ # @return [void]
88
+ def next_generation!
89
+ Libevoasm.pop_next_gen self
90
+ end
91
+
92
+ # Stops the process started by {#run}
93
+ # @return [void]
94
+ def stop
95
+ @stop = true
96
+ end
97
+
98
+ # Plots the loss function
99
+ # @return [void]
100
+ def plot(filename = nil)
101
+ @plotter ||= Plotter.new self, filename
102
+ @plotter.update
103
+ @plotter.plot
104
+ end
105
+
106
+ # Starts the evolutionary process on this population
107
+ # @param loss [Float] stop process if a program is found whose loss is less or equal than the specified loss
108
+ # @param min_generations [Integer] minimum number of generations to run
109
+ # @param max_generations [Integer] maximum number of generations to run
110
+ # @param seed [Bool] whether the population should be seeded before starting
111
+ # @yield [self]
112
+ # @yieldreturn a truthy value to stop the process
113
+ # @return [Program] the best program found
114
+
115
+ def run(loss: nil, min_generations: nil, max_generations: 10, seed: true, &block)
116
+ self.seed if seed
117
+ best_program = nil
118
+ best_loss = nil
119
+ generation = 1
120
+
121
+ loop do
122
+ evaluate
123
+
124
+ best_program = self.best_program
125
+ best_loss = self.best_loss
126
+
127
+ block[self]
128
+
129
+ break if @stop
130
+ min_generations_reached = min_generations.nil? || generation >= min_generations
131
+ break if min_generations_reached && loss && best_loss <= loss
132
+ break if generation >= max_generations
133
+
134
+ next_generation!
135
+ generation += 1
136
+ end
137
+
138
+ @stop = false
139
+ return best_program, best_loss
140
+ end
141
+ end
142
+ end
143
+
144
+ require 'evoasm/population/parameters'
145
+ require 'evoasm/population/plotter'
@@ -0,0 +1,227 @@
1
+ require 'evoasm/prng'
2
+ require 'evoasm/program/io'
3
+ require 'evoasm/domain'
4
+
5
+ module Evoasm
6
+ class Population
7
+
8
+ class Parameters < FFI::AutoPointer
9
+
10
+ # @!visibility private
11
+ def self.release(ptr)
12
+ Libevoasm.pop_params_free ptr
13
+ end
14
+
15
+ # @return [Program::Input] input examples
16
+ attr_reader :input
17
+
18
+ # @return [Program::Output] output examples
19
+ attr_reader :output
20
+
21
+ # @param architecture [Symbol] the machine architecture (currently only +:x64+ is supported)
22
+ # @yield [self]
23
+ def initialize(architecture = Evoasm.architecture, &block)
24
+ ptr = Libevoasm.pop_params_alloc
25
+ Libevoasm.pop_params_init ptr
26
+
27
+ case architecture
28
+ when :x64
29
+ @inst_id_enum_type = Libevoasm.enum_type :x64_inst_id
30
+ @param_id_enum_type = Libevoasm.enum_type :x64_param_id
31
+ else
32
+ raise "unknown architecture #{architecture}"
33
+ end
34
+
35
+ super(ptr)
36
+
37
+ self.seed = PRNG::DEFAULT_SEED
38
+
39
+ if block
40
+ block[self]
41
+ end
42
+ end
43
+
44
+ # @!attribute mutation_rate
45
+ # @return [Float 0..1] the mutation rate
46
+ def mutation_rate
47
+ Libevoasm.pop_params_get_mut_rate(self)
48
+ end
49
+
50
+ def mutation_rate=(mutation_rate)
51
+ Libevoasm.pop_params_set_mut_rate self, mutation_rate
52
+ end
53
+
54
+ # @!attribute deme_size
55
+ # @return [Integer] the number of individuals per deme
56
+ def deme_size
57
+ Libevoasm.pop_params_get_deme_size self
58
+ end
59
+
60
+ def deme_size=(deme_size)
61
+ Libevoasm.pop_params_set_deme_size self, deme_size
62
+ end
63
+
64
+ # @!attribute deme_count
65
+ # @return [Integer] the number of demes in the population
66
+ def deme_count
67
+ Libevoasm.pop_params_get_n_demes self
68
+ end
69
+
70
+ def deme_count=(deme_count)
71
+ Libevoasm.pop_params_set_n_demes self, deme_count
72
+ end
73
+
74
+ # @!attribute parameters
75
+ # @return [Array<Symbol>] the list of architecture-dependent instruction parameters to use
76
+ def parameters
77
+ Array.new(Libevoasm.pop_params_get_n_params self) do |index|
78
+ parameters_enum_type[Libevoasm.pop_params_get_param(self, index)]
79
+ end
80
+ end
81
+
82
+ def parameters=(parameter_names)
83
+ parameter_names.each_with_index do |parameter_name, index|
84
+ Libevoasm.pop_params_set_param(self, index, parameters_enum_type[parameter_name])
85
+ end
86
+ Libevoasm.pop_params_set_n_params(self, parameter_names.size)
87
+ end
88
+
89
+ # @!attribute domains
90
+ # @return [Hash{Symbol => Array, Range}] a hash whose values indicate user-defined domains for the parameters given as keys
91
+ def domains
92
+ parameters.map do |parameter_name|
93
+ domain_ptr = Libevoasm.pop_params_get_domain(self, parameter_name)
94
+ domain = @domains.find { |domain| domain == domain_ptr }
95
+ [parameter_name, domain]
96
+ end.to_h
97
+ end
98
+
99
+ def domains=(domains_hash)
100
+ domains = []
101
+ domains_hash.each do |parameter_name, domain_value|
102
+ domain = Domain.for domain_value
103
+ success = Libevoasm.pop_params_set_domain(self, parameter_name, domain)
104
+ if !success
105
+ raise ArgumentError, "no such parameter #{parameter_name}"
106
+ end
107
+ domains << domain
108
+ end
109
+
110
+ # keep reference to prevent disposal by GC
111
+ @domains = domains
112
+ end
113
+
114
+ # @!visibility private
115
+ def deme_height
116
+ Libevoasm.pop_params_get_deme_height self
117
+ end
118
+
119
+ # @!attribute seed
120
+ # @return [Array<Integer>] the seed for the random number generator
121
+ def seed
122
+ Array.new(PRNG::SEED_SIZE) do |index|
123
+ Libevoasm.pop_params_get_seed(self, index)
124
+ end
125
+ end
126
+
127
+ def seed=(seed)
128
+ if seed.size != PRNG::SEED_SIZE
129
+ raise ArgumentError, 'invalid seed size'
130
+ end
131
+
132
+ seed.each_with_index do |seed_value, index|
133
+ Libevoasm.pop_params_set_seed(self, index, seed_value)
134
+ end
135
+ end
136
+
137
+ # Validate the parameters
138
+ # @raise [Error] if the parameters are invalid
139
+ def validate!
140
+ unless Libevoasm.pop_params_validate(self)
141
+ raise Error.last
142
+ end
143
+ end
144
+
145
+ # @!attribute instructions
146
+ # @return [Symbol, Instruction] the list of instructions to use
147
+ def instructions
148
+ Array.new(Libevoasm.pop_params_get_n_insts self) do |index|
149
+ @inst_id_enum_type[Libevoasm.pop_params_get_inst(self, index)]
150
+ end
151
+ end
152
+ def instructions=(instructions)
153
+ instructions.each_with_index do |instruction, index|
154
+ name =
155
+ if instruction.is_a? Symbol
156
+ instruction
157
+ else
158
+ instruction.name
159
+ end
160
+ Libevoasm.pop_params_set_inst(self, index, name)
161
+ end
162
+ Libevoasm.pop_params_set_n_insts(self, instructions.size)
163
+ end
164
+
165
+ # @!attribute kernel_size
166
+ # @return [Integer] the size of program kernels (number of instructions per kernel)
167
+ def kernel_size
168
+ Libevoasm.pop_params_get_kernel_size self
169
+ end
170
+
171
+ def kernel_size=(kernel_size)
172
+ Libevoasm.pop_params_set_kernel_size self, kernel_size
173
+ end
174
+
175
+ # @!attribute program_size
176
+ # @return [Integer] the size of programs (number of kernels per program)
177
+ def program_size
178
+ Libevoasm.pop_params_get_program_size self
179
+ end
180
+
181
+ def program_size=(program_size)
182
+ Libevoasm.pop_params_set_program_size self, program_size
183
+ end
184
+
185
+ # @!attribute recur_limit
186
+ # @return [Integer] the size of programs (number of kernels per program)
187
+ def recur_limit
188
+ Libevoasm.pop_params_get_recur_limit self
189
+ end
190
+
191
+ def recur_limit=(recur_limit)
192
+ Libevoasm.pop_params_set_recur_limit self, recur_limit
193
+ end
194
+
195
+ # @!attribute examples
196
+ # @return [Hash] shorthand to set expected program input and output
197
+ # @see #input
198
+ # @see #output
199
+ def examples
200
+ input.zip(output).to_h
201
+ end
202
+
203
+ def examples=(examples)
204
+ input_examples = examples.keys.map { |k| Array(k) }
205
+ output_examples = examples.values.map { |k| Array(k) }
206
+
207
+ self.input = Program::Input.new input_examples
208
+ self.output = Program::Output.new output_examples
209
+ end
210
+
211
+ def input=(input)
212
+ @input = input
213
+ Libevoasm.pop_params_set_program_input self, input
214
+ end
215
+
216
+ def output=(output)
217
+ @output = output
218
+ Libevoasm.pop_params_set_program_output self, output
219
+ end
220
+
221
+ private
222
+ def parameters_enum_type
223
+ @param_id_enum_type
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,89 @@
1
+ module Evoasm
2
+ class Population
3
+
4
+ # Visualizes the population loss functions using {http://gnuplot.sourceforge.net Gnuplot}
5
+ class Plotter
6
+ MAX_SAMPLE_COUNT = 1024
7
+
8
+ # @!visibility private
9
+ def self.__open__
10
+ @pipe ||= IO.popen('gnuplot -persist', 'w')
11
+ end
12
+
13
+ # @param population [Population] the population to plot
14
+ def initialize(population, filename = nil)
15
+ @population = population
16
+
17
+ @pipe = self.class.__open__
18
+ #@pipe = File.open('/tmp/test.txt', 'w')
19
+
20
+ if filename
21
+ case filename
22
+ when /\.gif$/
23
+ @pipe.puts 'set term gif animate delay 20 size 1280, 1024 crop'
24
+ @pipe.puts %Q{set output "#{filename}"}
25
+ else
26
+ raise ArgumentError, "unknown output filetype"
27
+ end
28
+ end
29
+
30
+ @pipe.puts 'set xtics'
31
+ @pipe.puts 'set ytics'
32
+ @pipe.puts 'set grid'
33
+ @pipe.puts 'set style fill transparent solid 0.2 noborder'
34
+ @pipe.puts 'set datafile missing "Infinity"'
35
+ @pipe.puts 'set lmargin 0.5'
36
+ @pipe.puts 'set rmargin 0.5'
37
+ @pipe.puts 'set tmargin 0.5'
38
+ @pipe.puts 'set bmargin 0.5'
39
+ end
40
+
41
+ # Updates data points
42
+ # @return [nil]
43
+ def update
44
+ @data ||= Array.new(@population.parameters.deme_count) { Array.new(@population.parameters.deme_height) { [] } }
45
+ summary = @population.summary
46
+
47
+ summary.each_with_index do |deme_summary, deme_index|
48
+ deme_summary.each_with_index do |layer_summary, layer_index|
49
+ samples = @data[deme_index][layer_index]
50
+ samples[samples.size % MAX_SAMPLE_COUNT] = layer_summary
51
+ end
52
+ end
53
+ end
54
+
55
+ # Plots (or replots) the current data points
56
+ # @return [nil]
57
+ def plot
58
+ @pipe.puts "set multiplot layout #{@data[0].size}, #{@data.size}"
59
+
60
+ key = true
61
+
62
+ @data.each do |deme_summary|
63
+ deme_summary.each do |layer_summary|
64
+ @pipe.puts "set key #{key ? 'on' : 'off'}"
65
+ key = false
66
+ @pipe.write %Q{plot '-' using 1:2:3 with filledcurves title 'IQR',}
67
+ @pipe.write %Q{ '-' using 1:2 with lp title 'Min',}
68
+ @pipe.puts %Q{ '-' using 1:2 with lp lt 1 pt 5 ps 1.5 lw 2 title 'Median'}
69
+
70
+ layer_summary.each_with_index do |sample, sample_index|
71
+ @pipe.puts "#{sample_index} #{sample[1]} #{sample[3]}"
72
+ end
73
+ @pipe.puts 'e'
74
+ layer_summary.each_with_index do |sample, sample_index|
75
+ @pipe.puts "#{sample_index} #{sample[0]}"
76
+ end
77
+ @pipe.puts 'e'
78
+ layer_summary.each_with_index do |sample, sample_index|
79
+ @pipe.puts "#{sample_index} #{sample[2]}"
80
+ end
81
+ @pipe.puts 'e'
82
+ end
83
+ end
84
+ @pipe.puts "unset multiplot"
85
+ @pipe.flush
86
+ end
87
+ end
88
+ end
89
+ end