require 'transducers'
class GameOfLife < Processing::App
T = Transducers
def random_data
T.transduce(T.map{ rand(1000) < ALIVE_START }, :<<, [], 0..row * column)
end
end
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Showing posts with label map. Show all posts
Showing posts with label map. Show all posts
Sunday, 12 October 2014
Transducers in ruby-processing
Transducers may be useful in ruby-processing for dealing with all sorts of algorithmic stuff. but in many cases if your brain can take it map, might be equally good. Here is example substituting a regular map with a transducer, I will have to see if I can find a more useful example:-
Labels:
map,
ruby-processing,
Transducers
Thursday, 14 August 2014
Experimental map1d method JRubyArt (ruby-processing development)
The recently updated JRubyArt has now removed the processing convenience functions that were deprecated in ruby-processing-2.5.1. Other functions such as map are retained, but I wondered would a map1d range method be a more ruby like alternative:-
PS: I have not tested whether Jordans findings re: ruby complex implementation still hold true (jruby truffle claims wicked fast mandelbrot calculations). Benchmarking is tricky with jvm warmup up time, I have replaced sqrt(real * real + imag * imag) (abs method) with hypot(real, imag), which should be more efficient...
# @param [float] val # @param [range(start1 .. end1)] r_in # @param [range(start2 .. end2)] r_out # @return [float] mapped value # def map1d(val, r_in, r_out) r_out.first + (r_out.last - r_out.first) * ((val - r_in.first).to_f / (r_in.last - r_in.first)) end # usage map1d(5, (0 .. 10), (10 .. 110)) exclude end is false puts map1d(5, (0 .. 10), (10 .. 110)) # output 60.0Here is the method in action
# Mandelbrot Set example # by Jordan Scales (http://jordanscales.com) # 27 Dec 2012 # Modified to use map1d (instead of map), and somewhat # optimized (update_pixels instead of set, and hypot for abs) # default size 900x600 # no need to loop def setup size 900, 600 load_pixels no_loop end # main drawing method def draw (0 ... 900).each do |x| (0 ... 600).each do |y| c = Complex.new(map1d(x, (0 .. 900), (-3 .. 1.5)), map1d(y, (0 .. 600), (-1.5 .. 1.5))) # mandel will return 0 to 20 (20 is strong) # map this to 0, 255 (and flip it) pixels[x + y * 900] = color(255 - map1d(mandel(c, 20), (0 .. 20), (0 .. 255)).to_i) end end update_pixels end # calculates the "accuracy" of a given point in the mandelbrot set # : how many iterations the number survives without becoming chaotic def mandel(z, max = 10) score = 0 c = z.clone while score < max # z = z^2 + c z.square z.add c break if z.abs > 2 score += 1 end score end # rolled my own Complex class # stripped of all functionality, except for what I needed (abs, square, add, to_s) # # Using this class, runs in ~12.5s on my MacBook Air # compared to ~22s using ruby's Complex struct class Complex attr_accessor :real, :imag def initialize(real, imag) @real = real @imag = imag end # square a complex number - overwriting it def square r = real * real - imag * imag i = 2 * real * imag @real = r @imag = i end # add a given complex number def add(c) @real += c.real @imag += c.imag end # compute the magnitude def abs hypot(real, imag) end def to_s "#{real} + #{imag}i" end end
PS: I have not tested whether Jordans findings re: ruby complex implementation still hold true (jruby truffle claims wicked fast mandelbrot calculations). Benchmarking is tricky with jvm warmup up time, I have replaced sqrt(real * real + imag * imag) (abs method) with hypot(real, imag), which should be more efficient...
Labels:
JRubyArt,
mandelbrot,
map,
map1d
Tuesday, 4 March 2014
Getting closer to "functional programming with ruby-processing"
In a previous blog I reported that Dan Shiffmans Nature of Code had been ported to ruby processing. So I took a look at the code, and could not help from meddling here is my modified version of the perceptron sketch:-
Here I am particulary pleased with the Perceptron feedforward code, that sums the weights using zip, map and inject. This code has a somewhat functional feel to it?
# The Nature of Code # http://natureofcode.com # Simple Perceptron Example # See: http://en.wikipedia.org/wiki/Perceptron class Perceptron attr_reader :weights # Perceptron is created with n weights and a learning constant def initialize(n, c) @weights = Array.new(n) { rand(-1.0 .. 1) } @c = c # learning constant end # Function to train the Perceptron # Weights are adjusted based on "desired" answer def train(inputs, desired) # Guess the result guess = feedforward(inputs) # Compute the factor for changing the weight based on the error # Error = desired output - guessed output # Note this can only be 0, -2, or 2 # Multiply by learning constant error = desired - guess # Adjust weights based on weightChange * input @weights.each_index{|i| @weights[i] += error * inputs[i]} end # Guess -1 or 1 based on input values def feedforward(inputs) # Sum all values sum = @weights.zip(inputs).map{|x, y| x * y}.inject(0){|x, y| x + y} # Result is sign of the sum, -1 or 1 activate(sum) end def activate(sum) sum > 0 ? 1 : -1 end end # A class to describe a training point # Has an x and y, a "bias" (1) and a known output # Could also add a variable for "guess" but not required here class Trainer attr_reader :inputs, :answer def initialize(x, y, a) @inputs = [x, y, 1] @answer = a end end # Code based on text "Artificial Intelligence", George Luger # The function to describe a line def f(x) 0.4 * x + 1 end def setup size(640, 360) # Coordinate space @xmin = -400 @ymin = -100 @xmax = 400 @ymax = 100 @count = 0 # The perceptron has 3 inputs -- x, y, and bias # Second value is "Learning Constant" @ptron = Perceptron.new(3, 0.00001) # Learning Constant is low just b/c it's fun to watch, this is not necessarily optimal #Create a random set of training points and calculate the "known" answer @training = Array.new(2000) do x = rand(@xmin .. @xmax) y = rand(@ymin .. @ymax) answer = y < f(x) ? -1 : 1 Trainer.new(x, y, answer) end smooth end def draw background(255) translate(width/2, height/2) # Draw the line stroke_weight(4) stroke(127) x1 = @xmin y1 = f(x1) x2 = @xmax y2 = f(x2) line(x1, y1, x2, y2) # Draw the line based on the current weights # Formula is weights[0]*x + weights[1]*y + weights[2] = 0 stroke(0) stroke_weight(1) weights = @ptron.weights x1 = @xmin y1 = (-weights[2] - weights[0]*x1) / weights[1] x2 = @xmax y2 = (-weights[2] - weights[0]*x2) / weights[1] line(x1, y1, x2, y2) # Train the Perceptron with one "training" point at a time @ptron.train(@training[@count].inputs, @training[@count].answer) @count = (@count + 1) % @training.size # Draw all the points based on what the Perceptron would "guess" # Does not use the "known" correct answer @count.times do |i| stroke(0) stroke_weight(1) fill(0) train = @training[i] guess = @ptron.feedforward(train.inputs) no_fill if guess > 0 ellipse(train.inputs[0], train.inputs[1], 8, 8) end end
Here I am particulary pleased with the Perceptron feedforward code, that sums the weights using zip, map and inject. This code has a somewhat functional feel to it?
Labels:
inject,
map,
ruby-processing,
zip
Subscribe to:
Posts (Atom)
Followers
About Me
- monkstone
- I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2
