Navigation Menu

Skip to content

Commit

Permalink
Numerous bug fixes, plus a merge of the following:
Browse files Browse the repository at this point in the history
    added an example exploring differences between random scripts
    fixed a bug in Proxy#^quote
    Fixed a bug in List#fold_down
    Fixed a bug in Iterator#union
    fixed a bug in Iterator#step with empty contents
    deep refactoring of Iterator class
    List#each creates an Iterator
    Decimal#count creates an Iterator
    added by_element behavior to Iterators
    bug fix when counting ticks of certain nested Interpreters
    caught a bug in Binder#deep_copy
    Proxy#^greedy=
    caught a misplaced Duck module method
  • Loading branch information
Vaguery committed Feb 25, 2012
1 parent 01d11d1 commit b94f3a6
Show file tree
Hide file tree
Showing 53 changed files with 792 additions and 159 deletions.
75 changes: 75 additions & 0 deletions examples/random_scripts.rb
@@ -0,0 +1,75 @@
#encoding: utf-8
require_relative '../lib/duck'
require 'timeout'
include Duck

############
# A simple experiment in the diversity of Duck scripts.
#
# We generate Duck scripts from random tokens, run them with different inputs 'x'
# to observe how many act differently with just the change in inputs value.


######
# some conveniences, first:

ARITHMETIC_TOKENS = ["+","-","*","/","inc","dec","if"] + ['k','f','x'] * 5
ALL_MESSAGES =
[Assembler,Binder,Bool,Closure,Collector,
Decimal,Error,Int,Interpreter,Item,Iterator,List,Local,
Message,Number,Pipe,Proxy,Script,Span,Variable].inject([]) {|messages,klass| (messages | klass.recognized_messages)}

@everything =
ALL_MESSAGES + ['m','k','b','f','x'] * 10

def random_tokens(how_many,source_list)
tokens = how_many.times.collect do
t = source_list.sample
case
when t=="k" # some random integer
val = "#{(0..9).to_a.sample}"
rand < 0.5 ? val : "-#{val}"
when t=="m" # some random local message
"_#{('a'..'z').to_a.sample}"
when t=="b" # some random boolean
rand < 0.5 ? "T" : "F"
when t=="f" # some random float
val = "#{(0..9).to_a.sample}.#{(0..9).to_a.sample}"
rand < 0.5 ? val : "-#{val}"
else # just what it says
t.to_s
end
end
end


def random_script(how_many, source_list=@everything)
parts = random_tokens(how_many, source_list)
parts.join(" ")
end

############
#
# We generate 500 random 50-token scripts
# set variable :x1 and :x2
# run each script, and count the number of ticks execution takes,
# and report the top two Number values present on the interpreter when it's done


puts "trial, ticks(x1), ticks(x2), y1(x1), y1(x2), y2(x1), y2(x2)"
(0..500).each do |i|
pts = 100
x1 = 16
x2 = 19
script = random_script(pts)
begin
Timeout::timeout(120) do
random_one = interpreter(script:script, binder:{x:int(x1)}).run
random_two = interpreter(script:script, binder:{x:int(x2)}).run
puts"#{i}: #{random_one.ticks}, #{random_two.ticks}, #{random_one.emit!(Number)||'nil'}, #{random_two.emit!(Number)||'nil'}, #{random_one.emit!(Number)||'nil'}, #{random_two.emit!(Number)||'nil'}"
end
rescue Exception => e
puts "ERROR:#{e.message} -- #{e.backtrace} #{script.inspect}"
raise
end
end
10 changes: 5 additions & 5 deletions examples/trivial_gp.rb
Expand Up @@ -117,8 +117,8 @@ def evaluate(x_y_pairs_hash={},out_file = nil)
NUMBERLESS_TOKENS = ["+","-","*","/","inc","dec"]+['x']*4 # EXERCISE (one hand tied)
ALL_MESSAGES =
[Assembler,Binder,Bool,Closure,Collector,
Decimal,Error,Int,Interpreter,Item,List,
Message,Number,Pipe,Script,Variable].inject([]) {|messages,klass| (messages | klass.recognized_messages)}
Decimal,Error,Int,Interpreter,Item,Iterator,List,Local,
Message,Number,Pipe,Proxy,Script,Span,Variable].inject([]) {|messages,klass| (messages | klass.recognized_messages)}

@experiment_tokens = ALL_MESSAGES + SIMPLE_TOKENS

Expand All @@ -140,10 +140,10 @@ def random_tokens(how_many,source_list)
end


pop_size = 100
pop_size = 50
updates = pop_size*3
cycles = 500
standard_length = 100
standard_length = 40
population = pop_size.times.collect {Answer.new(random_tokens(standard_length,@experiment_tokens))}

File.open("./data/scores.csv", "w") do |tracefile|
Expand Down Expand Up @@ -180,7 +180,7 @@ def random_tokens(how_many,source_list)
mom, dad = population[mom_index], population[dad_index]

# EXERCISE (recombination)
crossover1,crossover2 = mom.crossover_result(dad, false)
crossover1,crossover2 = mom.crossover_result(dad)
baby1 = Answer.new(crossover1).mutant(3,@experiment_tokens) # EXERCISE (ontological creep)
baby2 = Answer.new(crossover2).mutant(3,@experiment_tokens)

Expand Down
4 changes: 1 addition & 3 deletions lib/assembler_class.rb
Expand Up @@ -85,9 +85,7 @@ def count_a_tick


def give_ticks
recorded_ticks = @ticks
@ticks = 0
return recorded_ticks
return @ticks
end


Expand Down
11 changes: 9 additions & 2 deletions lib/binder_class.rb
Expand Up @@ -2,13 +2,20 @@
module Duck
class Binder < List
attr_accessor :contents



def initialize(contents=[])
@contents = contents
@needs = []
end


def deep_copy
Binder.new( @contents.collect {|item| item.deep_copy})
end



def recognize_message?(string)
mine_and_theirs = contents_recognize_message?(string) || Binder.recognized_messages.include?(string.intern)
end
Expand Down Expand Up @@ -38,7 +45,7 @@ def index_of_next_respondent_to(msg)
def produce_respondent(msg)
which = index_of_next_respondent_to(msg.intern)
if which.nil?
result = personally_recognizes?(msg) ? self : nil
result = personally_recognizes?(msg) ? self.deep_copy : nil
else
if @contents[which].kind_of?(Binder)
result = @contents[which].produce_respondent(msg)
Expand Down
5 changes: 5 additions & 0 deletions lib/bool_class.rb
Expand Up @@ -54,5 +54,10 @@ def to_s
duck_handle :to_int do
Int.new(@value ? 1 : 0)
end


duck_handle :to_script do
Script.new(@value ? 'T' : 'F')
end
end
end
22 changes: 17 additions & 5 deletions lib/decimal_class.rb
@@ -1,10 +1,9 @@
#encoding: utf-8

def decimal(value)
Decimal.new(value)
end

module Duck
def decimal(value)
Decimal.new(value)
end

class Decimal < Number
def to_s
"#{@value}"
Expand Down Expand Up @@ -38,6 +37,19 @@ def to_s
end


duck_handle :count do
Iterator.new(start:0.0, end:@value, inc:1.0,:response => :index).run
end


duck_handle :count_by do
Closure.new(["neg"], "#{self.inspect}.count_by(?)") do |number|
Iterator.new(start:0.0, end:@value, inc:number.value.to_f, :response => :index).run
end
end



duck_handle :rand do
case
when @value > 0.0
Expand Down
31 changes: 21 additions & 10 deletions lib/int_class.rb
@@ -1,11 +1,10 @@
#encoding: utf-8

def int(value)
Int.new(value)
end


module Duck

def int(value)
Int.new(value)
end

class Int < Number
def type_cast_result(arg, operator)
arg.class == Decimal ?
Expand Down Expand Up @@ -58,12 +57,24 @@ def to_s
i = self.value
Closure.new(["be"],"#{i} of ?") do |item|
item.to_s.length * i <= @@result_size_limit ?
i.times.collect {|i| item.clone} :
i.times.collect {|i| item.deep_copy} :
Error.new("OVERSIZED RESULT")
end
end




duck_handle :count do
Iterator.new(start:0, end:@value, inc:1,:response => :index).run
end


duck_handle :count_by do
Closure.new(["inc"],"#{self.inspect}.count_by(?)") do |increment|
Iterator.new(start:0, end:@value, inc:increment.value, :response => :index).run
end
end


duck_handle :dec do
Int.new @value - 1
end
Expand All @@ -89,7 +100,7 @@ def to_s
duck_handle :times_do do
Closure.new(["be"], "#{self.inspect}.times_do(?)") do |item|
@value > 0 ?
[Iterator.new(start:0, end:@value, contents:[item]), Message.new("run")] :
Iterator.new(start:0, end:@value, contents:[item]).run :
self
end
end
Expand Down
8 changes: 1 addition & 7 deletions lib/interpreter_class.rb
Expand Up @@ -193,12 +193,7 @@ def trace_used_as_arg(position)
def trace_uses_arg(position)
write_to_trace " ... grabbed the #{@contents[position].class} #{@contents[position].inspect}" unless position.nil?
end


def trace_entire_buffer
write_to_trace " ... the buffer is now #{@buffer.inspect}"
end




def trace_pushed_item(item)
Expand All @@ -215,7 +210,6 @@ def process_next_buffer_item
unless buffer.empty?
count_a_tick
@staged_item = @buffer.delete_at(0)
trace_entire_buffer if @trace
trace_staging if @trace
next_arg_position = next_contents_index_wanted_by(@staged_item)
if next_arg_position.nil?
Expand Down
52 changes: 46 additions & 6 deletions lib/iterator_class.rb
Expand Up @@ -8,6 +8,7 @@ class Iterator < List
attr_accessor :index
attr_accessor :contents
attr_accessor :min_value, :max_value
attr_accessor :response

def initialize(args = {})
default_args = {start:0, end:0, inc:1, index:nil}
Expand All @@ -23,6 +24,7 @@ def initialize(args = {})
end
@index = args[:index] || @start
@contents = args[:contents] || []
@response = args[:response] || :contents
@min_value,@max_value = [@start,@end].minmax
@needs = []
end
Expand All @@ -34,36 +36,74 @@ def deep_copy
end:@end,
inc:@inc,
index:@index,
contents:@contents.collect {|item| item.deep_copy}
contents:@contents.collect {|item| item.deep_copy},
response:@response,
)
end


def to_s
"(#{@start}..#{@index}..#{@end})=>#{@contents.inspect}"
rounded_index = @index.kind_of?(Float) ? "~(#{@index.round(3)})" : "#{@index}"
return "(#{@start}..#{rounded_index}..#{@end})=>#{@contents}"
end


def index_in_range?
@start < @end ?
@min_value <= @index && @index < @max_value :
@min_value < @index && @index <= @max_value
end


def reset_index_within_range
if !index_in_range?
@index = @min_value if @index < @min_value
@index = @max_value if @index >= @max_value
end
end


def output_value
case @response
when :element
output = @contents.empty? ? [] : [@contents[@index % @contents.length].deep_copy]
when :index
output = @index.kind_of?(Float) ? [Decimal.new(@index)] : [Int.new(@index)]
else
output = @contents.collect {|item| item.deep_copy}
end
return output
end


# DUCK HANDLERS


duck_handle : do
Closure.new(["shatter"], "#{self.inspect} ∪ ?") do |listy_thing|
aggregated = listy_thing.contents + @contents
result_iterator = self.deep_copy
aggregated = listy_thing.contents + result_iterator.contents
unionized = aggregated.uniq {|element| element.inspect}
@contents = unionized
result_iterator.contents = unionized
result_iterator
end
end


duck_handle :again do
if index_in_range?
output_array = self.output_value
output_array.unshift(self)
else
reset_index_within_range
self
end
end


duck_handle :index= do
Closure.new(["neg"], "#{self.inspect}.index=?") do |int|
@index = int.value
self
end
end
Expand Down Expand Up @@ -119,9 +159,9 @@ def reset_index_within_range

duck_handle :step do
if index_in_range?
output = @contents.collect {|item| item.deep_copy}
output_array = self.output_value
@index += @actual_inc
output.unshift(self)
output_array.unshift(self)
else
reset_index_within_range
self
Expand Down

0 comments on commit b94f3a6

Please sign in to comment.