[Puzzle] How to do parameter variation?

G

Gary Boone

Suppose you want to do several runs of a program or function, varying
the parameters each time. You start with a hash of parameter lists:

params = { speed=>[1,2,3], beta=>[0.1, 0.002, 0.4], x=>['a', 'b'] }

Given this set, you'll call the test function 18 times:

test_function( {speed=>1, beta=>0.1, x=>'a'} )
test_function( {speed=>1, beta=>0.1, x=>'b'} )
test_function( {speed=>1, beta=>0.002, x=>'a'} )
... etc

So the puzzle is how to take the original params list and generate a
list of all the combinations of the parameters? The resulting parameter
sets will be passed one at a time to the function as shown above.

Notes:
- I used hashes and lists to explain the problem. Maybe there's a better
way.
- You don't know how many parameters will be given.
- The number of values for each parameter is unknown in advance.
- The parameters have different types, as shown above. Each parameter's
values are all the same type, though.
 
G

Gregory Seidman

On Thu, Dec 07, 2006 at 04:25:43PM +0900, Gary Boone wrote:
}
} Suppose you want to do several runs of a program or function, varying
} the parameters each time. You start with a hash of parameter lists:
}
} params = { speed=>[1,2,3], beta=>[0.1, 0.002, 0.4], x=>['a', 'b'] }
}
} Given this set, you'll call the test function 18 times:
}
} test_function( {speed=>1, beta=>0.1, x=>'a'} )
} test_function( {speed=>1, beta=>0.1, x=>'b'} )
} test_function( {speed=>1, beta=>0.002, x=>'a'} )
} ... etc
}
} So the puzzle is how to take the original params list and generate a
} list of all the combinations of the parameters? The resulting parameter
} sets will be passed one at a time to the function as shown above.
}
} Notes:
} - I used hashes and lists to explain the problem. Maybe there's a better
} way.
} - You don't know how many parameters will be given.
} - The number of values for each parameter is unknown in advance.
} - The parameters have different types, as shown above. Each parameter's
} values are all the same type, though.

params = { :speed => [1,2,3], :beta => [0.1, 0.002, 0.4], :x => ['a', 'b'] }

all = params.inject([{}]) do |perms,(k,list)|
perms.inject([]) do |expanded,base|
list.each do |v|
expanded << base.merge(k => v)
end
expanded
end
end

require 'yaml'
puts all.size
puts all.to_yaml

--Greg
 
J

James Edward Gray II

Suppose you want to do several runs of a program or function, varying
the parameters each time. You start with a hash of parameter lists:

params = { speed=>[1,2,3], beta=>[0.1, 0.002, 0.4], x=>['a',
'b'] }

Given this set, you'll call the test function 18 times:

test_function( {speed=>1, beta=>0.1, x=>'a'} )
test_function( {speed=>1, beta=>0.1, x=>'b'} )
test_function( {speed=>1, beta=>0.002, x=>'a'} )
... etc

See if this gives you some ideas:

#!/usr/bin/env ruby -w

def call_with(meth, params, selected = Hash.new)
params = params.dup
key = params.keys.sort_by { |k| k.to_s }.first
choices = params.delete(key)

choices.each do |choice|
selected = selected.merge(key => choice)
if params.empty?
send(meth, selected)
else
call_with(meth, params, selected)
end
end
end

def print_args(args)
p args
end

call_with :print_args, :speed => [1, 2, 3],
:beta => [0.1, 0.002, 0.4],
:x => ["a", "b"]
# >> {:speed=>1, :beta=>0.1, :x=>"a"}
# >> {:speed=>1, :beta=>0.1, :x=>"b"}
# >> {:speed=>2, :beta=>0.1, :x=>"a"}
# >> {:speed=>2, :beta=>0.1, :x=>"b"}
# >> {:speed=>3, :beta=>0.1, :x=>"a"}
# >> {:speed=>3, :beta=>0.1, :x=>"b"}
# >> {:speed=>1, :beta=>0.002, :x=>"a"}
# >> {:speed=>1, :beta=>0.002, :x=>"b"}
# >> {:speed=>2, :beta=>0.002, :x=>"a"}
# >> {:speed=>2, :beta=>0.002, :x=>"b"}
# >> {:speed=>3, :beta=>0.002, :x=>"a"}
# >> {:speed=>3, :beta=>0.002, :x=>"b"}
# >> {:speed=>1, :beta=>0.4, :x=>"a"}
# >> {:speed=>1, :beta=>0.4, :x=>"b"}
# >> {:speed=>2, :beta=>0.4, :x=>"a"}
# >> {:speed=>2, :beta=>0.4, :x=>"b"}
# >> {:speed=>3, :beta=>0.4, :x=>"a"}
# >> {:speed=>3, :beta=>0.4, :x=>"b"}

James Edward Gray II
 
G

Gary Boone

Cool. While I study the others, here's my solution. Looks like it's
similar to Greg's.

--Gary


# expand_hash_lists
#
# note that accumulating lists must be passed in as the first argument
#
def expand_hash_lists(a1, a2)
a1.inject([]){|acc,f| a2.inject(acc){|a,b| a << +
(f.is_a?(Hash)?[f]:f)}}
end

if __FILE__ == $0

# tests of expand_hash_lists
ah=[{'a'=>1}, {'a'=>2}, {'a'=>3}]
bh=[{'b'=>21}, {'b'=>22}, {'b'=>23}]
ch=[{'c'=>31}, {'c'=>32}, {'c'=>33}]
dh=[{'d'=>41}, {'d'=>42}, {'d'=>43}]

abh = expand_hash_lists(ah, bh)
abch = expand_hash_lists(abh, ch)
p expand_hash_lists(abch, dh).inspect

# Additional tests
p "----"
p [[{'a'=>1}], [{'b'=>2}]].inject{|acc, vl| expand_hash_lists(acc,
vl)}.inspect
p "----"
p [[{'a'=>1}, {'a'=>3}], [{'b'=>2}]].inject{|acc, vl|
expand_hash_lists(acc, vl)}.inspect
p "----"
p [[{'a'=>1}, {'a'=>3}], [{'b'=>2}, {'b'=>4}]].inject{|acc, vl|
expand_hash_lists(acc, vl)}.inspect
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top