I'm going through the EdgeCase Ruby Koans. In about_dice_project.rb, there's a test called "test_dice_values_should_change_between_rolls", which is straightforward:
def test_dice_values_should_change_between_rolls
dice = DiceSet.new
dice.roll(5)
first_time = dice.values
dice.roll(5)
second_time = dice.values
assert_not_equal first_time, second_time,
"Two rolls should not be equal"
end
Except for this comment that appears there:
# THINK ABOUT IT:
#
# If the rolls are random, then it is possible (although not
# likely) that two consecutive rolls are equal. What would be a
# better way to test this.
Which (obviously) got me thinking: what is the best way to reliably test something random like that (specifically, and generally)?
IMHO most answers so far have missed the point of the Koan question, with the exception of #Super_Dummy. Let me elaborate on my thinking...
Say that instead of dice, we were flipping coins. Add on another constraint of only using one coin in our set, and we have a minimum non-trivial set that can generate "random" results.
If we wanted to check that flipping the "coin set" [in this case a single coin] generated a different result each time, we would expect the values of each separate result to be the same 50% of the time, on a statistical basis. Running that unit test through n iterations for some large n will simply exercise the PRNG. It tells you nothing of substance about the actual equality or difference between the two results.
To put it another way, in this Koan we're not actually concerned with the values of each roll of the dice. We're really more concerned that the returned rolls are actually representations of different rolls. Checking that the returned values are different is only a first-order check.
Most of the time that will be sufficient - but very occasionally, randomness could cause your unit test to fail. That's not a Good Thing™.
If, in the case that two consecutive rolls return identical results, we should then check that the two results are actually represented by different objects. This would allow us to refactor the code in future [if that was needed], while being confident that the tests would still always catch any code that didn't behave correctly.
TL;DR?
def test_dice_values_should_change_between_rolls
dice = DiceSet.new
dice.roll(5)
first_time = dice.values
dice.roll(5)
second_time = dice.values
assert_not_equal [first_time, first_time.object_id],
[second_time, second_time.object_id], "Two rolls should not be equal"
# THINK ABOUT IT:
#
# If the rolls are random, then it is possible (although not
# likely) that two consecutive rolls are equal. What would be a
# better way to test this.
end
I'd say the best way to test anything that involves randomness is statistically. Run your dice function in a loop a million times, tabulate the results, and then run some hypothesis tests on the results. A million samples should give you enough statistical power that almost any deviations from correct code will be noticed. You are looking to demonstrate two statistical properties:
The probability of each value is what you intended it to be.
All rolls are mutually independent events.
You can test whether the frequencies of the dice rolls are approximately correct using Pearson's Chi-square test. If you're using a good random nunber generator, such as the Mersenne Twister (which is the default in the standard lib for most modern languages, though not for C and C++), and you're not using any saved state from previous rolls other than the Mersenne Twister generator itself, then your rolls are for all practical purposes independent of one another.
As another example of statistical testing of random functions, when I ported the NumPy random number generators to the D programming language, my test for whether the port was correct was to use the Kolmogorov-Smirnov test to see whether the numbers generated matched the probability distributions they were supposed to match.
There is no way to write a state-based test for randomness. They are contradictory, since state-based tests proceed by giving known inputs and checking output. If your input (random seed) is unknown, there is no way to test.
Luckily, you don't really want to test the implementation of rand for Ruby, so you can just stub it out with an expectation using mocha.
def test_roll
Kernel.expects(:rand).with(5).returns(1)
Diceset.new.roll(5)
end
It seems like there are 2 separate units here. First, a random number generator. Second, a "dice" abstraction that uses the (P)RNG.
If you want to unit test the dice abstraction, then mock out the PRNG calls, and make sure it calls them, and returns an appropriate value for the input you give, etc.
The PRNG is probably part of your library/framework/OS and so I wouldn't bother testing it. Maybe you'll want an integration test to see if it returns reasonable values, but that's a whole 'nother problem.
Instead of comparing values, compare object_id:
assert_not_equal first_time.object_id, second_time.object_id
This assumes that other tests will check for array of integers.
My solution was to allow a block to be passed to the roll function.
class DiceSet
def roll(n)
#values = (1..n).map { block_given? ? yield : rand(6) + 1 }
end
end
I can then pass my own RNG into the tests like this.
dice = DiceSet.net
dice.roll(5) { 1 }
first_result = dice.values
dice.roll(5) { 2 }
second_result = dice.values
assert_not_equal first_result, second_result
I don't know if that's really better, but it does abstract out the calls to the RNG. And it doesn't change the standard functionality.
Just create new array each time roll method called. This way you can use
assert_not_same first_time, second_time,
"Two rolls should not be equal"
to test object_id equality.
Yes, this test depends on implementation, but there is no way to test randomness.
Other approach is to use mocks as floyd suggested.
IMHO, randomness should be tested with dependency injection.
Jon Skeet answered to the general answer of how to test randomness here
I suggest you treat your source of randomness (a random number generator or whatever) as a dependency. Then you can test it with known inputs by providing either a fake RNG or one with a known seed. That removes the randomness from the test, while keeping it in the real code.
Example code of in our case may look something like this:
class DependentDiceSet
attr_accessor :values, :randomObject
def initialize(randomObject)
#randomObject = randomObject
end
def roll(count)
#values = Array.new(count) { #randomObject.userRand(1...6) }
end
end
class MyRandom
def userRand(values)
return 6
end
end
class RubyRandom
def userRand(values)
rand(values)
end
end
A user can inject any random behavior and test that the dice are rolled by that behavior. I implement ruby random behavior and another one that return always 6.
Usage:
randomDice = DependentDiceSet.new(RubyRandom.new)
sixDice = DependentDiceSet.new(MyRandom.new)
It seems a bit silly, to me. Are you supposed to be testing that the (psuedo) random number generator is generating random numbers? That's futile and pointless. If anything, you could test that dice.roll calls to your PRNG.
I solved the problem using recursion:
def roll times, prev_roll=[]
#values.clear
1.upto times do |n|
#values << rand(6) + 1
end
roll(times, prev_roll) if #values == prev_roll
end
And had to add a dup method to the test variable, so it doesn't pass the reference to my instance variable #values.
def test_dice_values_should_change_between_rolls
dice = DiceSet.new
dice.roll(5)
first_time = dice.values.dup
dice.roll(5, first_time)
second_time = dice.values
assert_not_equal first_time, second_time,
"Two rolls should not be equal"
end
rand is deterministic and depends on its seed. Use srand with a given number before the first roll and srand with a different number before the second roll. That would prevent repeating the series.
srand(1)
dice.roll(5)
first_time = dice.values
srand(2)
dice.roll(5)
second_time = dice.values
assert_not_equal first_time, second_time,
"Two rolls should not be equal"
i just created a new instance
def test_dice_values_should_change_between_rolls
dice1 = DiceSet.new
dice2 = DiceSet.new
dice1.roll(5)
first_time = dice1.values.dup
dice2.roll(5, first_time)
second_time = dice2.values
assert_not_equal first_time, second_time,
"Two rolls should not be equal"
end
The pragmatic approach is simply to test with a higher number of rolls. (The assumption being that this test is for two consecutive rolls of the same number).
likelihood of two 5 roll sets being the same => 6**5 => 1 in 7776
likelihood of two 30 roll sets being the same => 6**30 => 1 in 221073919720733357899776 (likelihood of hell freezing over)
This would be simple, performant and accurate [enough].
(We can't use object_id comparison since tests should be implementation agnostic and the implementation could be using the same array object by using Array#clear, or the object_id may have been reused, however unlikely)
I solved it by simply creating a new set of values for each dice anytime the 'roll' method is called:
def roll(n)
#numbers = []
n.times do
#numbers << rand(6)+1
end
end
Related
How to test in Ruby
if shuffle
some_array.shuffle.each { |val| puts "#{val}" }
end
Do I need to test shuffle or no since it is a Ruby method? Thanks.
Short answer: No.
You can trust that Ruby will do things correctly. It has a huge number of tests already.
Long answer: Yes.
You shouldn't be testing the shuffle method directly, but testing that your code produces the correct results.
Since your code uses puts this makes it very annoying to test. If you can write a method that returns values that can be printed, that's usually a lot better. When writing code always think about how you can test it.
If you're struggling with that, where the way to test something isn't clear, write the tests first and then write code to make them pass.
If it's imperative that your values be shuffled then you'll need to come up with a way of determining if they're sufficiently shuffled. This can be difficult since randomness is a fickle thing. There's a small but non-zero chance that shuffle does nothing to your data, that's how randomness works. This probability grows considerably the smaller your list is to the point where it's guaranteed to do nothing with just one element.
So if you can describe why the data should be shuffled, and what constitutes a good shuffling, then you can write a test for this.
Here's an example of how to do that:
gem 'test-unit'
require 'test/unit'
class MyShuffler
def initialize(data)
#data = data
end
def processed
#data.map do |e|
e.downcase
end.shuffle
end
end
Now you can use this like this:
shuffler = MyShuffler.new(%w[ a b c d e f ])
# Thin presentation layer here where we're just displaying each
# element. Test code for this is not strictly necessary.
shuffler.processed.each do |e|
puts e
end
Now you write test code for the data manipulation in isolation, not the presentation part:
gem 'test-unit'
require 'test/unit'
class MyShufflerTest < Test::Unit::TestCase
def test_processed
shuffler = MyShuffler.new(%w[ A B c Dee e f Gee ])
results = shuffler.processed
expected = %w[ a b c dee e f gee ]
assert_equal expected, results.sort
assert_not_equal expected, results
counts = Hash.new(0)
iterations = 100000
# Keep track of the number of times a particular element appears in
# the first entry of the array.
iterations.times do
counts[shuffler.processed[0]] += 1
end
expected_count = iterations / expected.length
# The count for any given element should be +/- 5% versus the expected
# count. The variance generally decreases with a larger number of
# iterations.
expected.each do |e|
assert (counts[e] - expected_count).abs < iterations * 0.05
end
end
end
You should not test randomness using unit test. A unit test should call a method and test the returned value (or object state) against an expected value. The problem with testing randomness is that there isn't an expected value for most of the things you'd like to test.
I've got an assignment where I have had to write a function, which takes two integers and returns it's bitwise product. Bitwise product equals to bitwise sum (&) of all numbers between these two.
For example: bitwise product of 251 and 253 is:
irb(main):164:0> 251 & 252
=> 248
irb(main):165:0> 252 & 253
=> 252
irb(main):166:0> 248 & 252
=> 248 # this a bitwise & of these two between 251 & 253
My function:
def solution(m,n)
(m..n).to_a.inject{|sum, x| sum &= x}
end
Test:
irb(main):160:0> (251..253).to_a.inject{|sum, x| sum &= x}
=> 248 #same result
The program's evaluation:
correctness 100%
performance 0%
Can anyone, please explain what is with performance of this function? Thanks in advance!
EDIT
Since performance is undefined here, can you provide an analysis of the function for, for example, really big inputs and criticise/suggest better/more efficient solution?
p.s. thx for comments guys, i will follow the recommendations!
Following up on my comment, you can experiment using Benchmark:
def solution(m,n)
(m..n).to_a.inject{|sum, x| sum &= x}
end
def solution2(m,n)
(m..n).reduce(:&)
end
n = 50000
Benchmark.bm(7) do |b|
b.report("orig:") { n.times do; solution(128,253); end }
b.report("new: ") { n.times do; solution2(128,253); end }
end
Here's what I get:
user system total real
orig: 1.560000 0.000000 1.560000 ( 1.557156)
new: 0.640000 0.000000 0.640000 ( 0.634063)
You appear not to have any choice but to do the above, experiment to find a faster algorithm, and run the test until you register on the performance meter.
The most obvious performance problem here is a conversion to array (to_a), it's not necassary. You can call reduce and inject (appear to be the same) an any Enumerable, Range includes it as well. Enumerable is basically everything that can produce a finite (it's arguable, but mostly true) sequence of elements. Range seems to fit, if treated as a set of integers.
In order to iterate over an array with elements in this range, you first create an array and fill it with elements (by iterating over Range). Then you iterate on the resulting array applying your operations. So you create an array for the purpose of iterating on it, fill it, use it, toss it away. And it takes quite a memory allocation to do that if the range is large.
The next one, which is not critical, but reduces the amount of code that you have, requires some knowledge on the internal implementation of operators in Ruby. When you write a&b you are actually doing a.&(b): calling a & method on a number.
The sum you get in the block is not really some sort of accumulator, you don't actually need to assign anything there, sum is an intermediate value, the result of adding a new element should actually be a return value. Since an assignment returns the assigned value, it works even this way. Proof of that is this:
(251..253).inject{|sum, x| sum & x } # => 248, as expected
...and it turns out, this block is trivial: take one value, call a method on it with another value. Since inject takes a pair of values on each iteration, you can just give it a method name and let it handle the situation. Method names in Ruby are typically referenced with symbols like this:
(251..253).inject(:&) # => 248, as expected
All right, about twice as less code, less actions done and less objects made, nevertheless same result.
def solution(m,n)
(m..n).inject(:&)
end
We haven't looked closely at inject. Can you beat inject performance-wise? It's unlikely, it's a C method and is used here exactly for its purpose, you can look it up easily using gems pry and pry-doc (install, launch pry and type in show-source Range#inject):
[11] pry(main)> show-source Range#inject
From: enum.c (C Method):
Owner: Enumerable
Visibility: public
Number of lines: 34
...a bunch of C code here
I need the mean to be 2, with starting at 1 up to 10,000 random numbers.
require 'distribution'
mean = 2
# generate a rng with exponential distribution
rng = Distribution::Exponential.rng(mean)
Well, I'm not much of a statistician, so I'm a little lost in the code here.
Can you tell me, then, is the first parameter to rng (it is named l) supposed to stand for "limit"?
If so, I don't really know, I'm getting the same sort of results that you must be getting, but again, I'm not a statistician or even a mathematician, I just like to code, so I am probably not of too much help.
EDIT: So, again, I dont really know what is going on or is supposed to be going on here. Here is what gives me a relatively close mean of 2 (I got this just by messing around with the l value):
require 'distribution'
rng=Distribution::Exponential.rng(0.5)
sum=0
1000.times { sum += rng.call }
sum /= 1000
puts sum
Seems to give a value generally between 1.9 and 2.1. Hope this helps :)
PRINT EACH VALUE:
require 'distribution'
rng = Distribution::Exponential.rng(0.5)
values = [] # we'll store each value in an array
# calculate the results
how_many = 1000 # let's store 1000 in a variable since we'll reuse the value
how_many.times { values << rng.call } # rng is now a Proc, so we use call to get our value
# print out the results
values.each_with_index { |v,i| puts "#{i+1}: #{v}" } # print each value one by one
puts
puts "Total sum: #{values.inject(&:+)}"
puts "Mean: #{values.inject(&:+)/how_many}"
Again, not sure if this is exactly "right" or what you're looking for, but it definitely seems to approach 2. Try a bigger number than 1000, like 100000.
I am trying to define Ruby classes for vectors and matrices. I intend to define two classes, MyVector and MyMatrix, with methods as hinted below. MyVector should represent a row vector, MyMatrix should represent a matrix, internally organized as an array of MyVector objects. Intended methods for MyVector:
#initialize method, that takes an array of integers as argument.
#length method, that returns the size of the vector.
#* method, taking argument a, that:
if a is a vector, returns the inner product, validating that the size of a matches the receiver.
if a is a matrix, then it returns the product of the receiver and the matrix, validating the size compatibility.
#to_s method, that returns a string representation of the receiver.
Methods for MyMatrix:
#initialize method, that takes an array of arrays as argument, converts the inner arrays into row vecotrs (MyVector class), and arranges them into a matrix.
#transpose method, that returns the receiver transposed.
#* method, that takes MyMatrix object argument and returns the matrix product, validating size compatibility of the argument.
#to_s method, that returns a string representation of the receiver.
This code I have written so far is below, but it doesn't work at all. I tried to define some method followed by the library class method (in matrix and vector class, they already define those method), but seem this way doesn't work because it always asks you to define something new. Could you please help me? Thanks!
class MyVector
def initialize (a)
if !(a.instance_of? Array)
raise "must be an array"
else
#array = a
end
end
def array
#array
end
def to_s
#array.to_s
end
def length
#array.length
end
def each2(a) #
raise Error, "Integer is not like Vector" if a.kind_of?(Integer)
Vector.Raise Error if length != a.length
return to_enum(:each2, a) unless block_given?
length.times do |i|
yield #array[i], a[i]
end
self
end
def * (a)
Vector.Raise Error if length != a.length
p = 0
each2(a) {|a1, a2|p += a1 * a2}
p
end
end
class MyMatrix
def initialize a
#array=Array.new(a.length)
i=0
while(i<a.length)
#array[i]=MyVector.new(a[i])
end
end
def to_s
#array.to_s
end
def transpose
size=vectors[0].length
arr= Array.new(size)
i=0
while i<size
a=Array.new(vector.length)
j=0
while j<a.length
a[j]=vectors[j].arr[i]
j+=1
end
arr[i]=a
i+=1
end
arr[i]=a
i+=1
end
def *m
if !(m instance_of? MyMatrix)
raise Error
a=Array.new(#array.length)
i=0
while (i<#array.length)
a[i]=#array[i]*m
i=i+1
end
end
end
end
A great question, and a great exercise for a newbie. As you might already know, Marc-André Lafortune has written the basic Matrix / Vector library, that is a part of Ruby standard library. While after the amount of effort that a programmer and mathematician, that Marc-André is, has put in the project, it is no longer possible to say that it sucks, it is also fair to say that stdlib matrix nowadays does not yet conform to that heavenly, dream-like quality that we expect of Ruby libraries.
My major criticism is that, just like you, Marc-André also makes a distinction between Vector and Matrix classes. This distinction shouldn't be: Vectors are simly matrices, whose second dimension is equal to 1. Separating Matrix and Vector leaves the user at loss as to which one to use, and that led me to banning Vector completely in the code that I write.
Neveretheless, it will be stdlib's matrix, that is going to be the answer to your post. If I understood it well, the question mark statement in your post seems to be:
"I tried to define some method ... but seem this way doesn't work because it always asks you to define something new. Could you please help me?"
In order to help you, I would answer: Start by using the matrix standard library. Simply type
require 'matrix'
In the next step, you will make a private copy of matrix library, that came with your Ruby installation, you will rename it to my_matrix, and require it no longer by require 'matrix', but by:
require './path/to/my/project/directory/my_matrix'
In the third step, you will start changing the behavior of the library that you just copied, and see when it breaks. Next, you will learn about unit testing, and learn to use stdlib's minitest. With that, you can define the desired behavior, and change the code until it meets the requirement.
In the 4th, 5th, ... nth step, you will be making a lot of big and small mistakes. And should your dedication to matrices and vectors in Ruby survive, you will be warmly welcome as a member of NMatrix team, the future grand version of representing matrices in Ruby.
I'd like to compare multiple variables for a case statement, and am currently thinking overriding the case equals operator (===) for Array is the best way to do it. Is this the best way?
Here is an example use case:
def deposit_apr deposit,apr
# deposit: can be nil or 2 length Array of [nil or Float, String]
# apr: can be nil or Float
case [deposit,apr]
when [[Float,String],Float]
puts "#{deposit[0]} #{deposit[1]}, #{apr*100.0}% APR"
when [[nil,String],Float]
puts "#{apr*100.0}% APR on deposits greater than 100 #{deposit[1]}"
when [[Float,String],nil]
puts "#{deposit[0]} #{deposit[1]}"
else
puts 'N/A'
end
end
The only problem is the Array case equals operator doesn't apply the case equal to the elements of the Array.
ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065)
N/A
It will if I override, but am not sure what I'd be breaking if I did:
class Array
def ===(other)
result = true
self.zip(other) {|bp,ap| result &&= bp === ap}
result
end
end
Now, it all works:
ruby-1.9.2-p0 > deposit_apr([656.00,'rupees'],0.065)
656.0 rupees, 6.5% APR
Am I missing something?
I found this question because I was looking to run a case statement on multiple variables, but, going through the following, came to the conclusion that needing to compare multiple variables might suggest that a different approach is needed. (I went back to my own code with this conclusion, and found that even a Hash is helping me write code that is easier to understand.)
Gems today use "no monkey patching" as a selling point. Overriding an operator is probably not the right approach. Monkey patching is great for experimentation, but it's too easy for things to go awry.
Also, there's a lot of type-checking. In a language that is designed for Duck Typing, this clearly indicates the need for a different approach. For example, what happens if I pass in integer values instead of floats? We'd get an 'N/A', even though that's not likely what we're looking for.
You'll notice that the example given in the question is difficult to read. We should be able to find a way to represent this logic more clearly to the reader (and to the writer, when they revisit the code again in a few months and have to puzzle out what's going on).
And finally, since there are multiple numbers with associated logic, it seems like there's at least one value object-type class (Deposit) that wants to be written.
For cleanliness, I'm going to assume that a nil APR can be considered a 0.0% APR.
class Deposit
def initialize(amount, unit='USD', options={})
#amount = amount.to_f # `nil` => 0.0
#unit = unit.to_s # Example assumes unit is always present
#apr = options.fetch(:apr, 0.0).to_f # `apr: nil` => 0.0
end
end
Once we have our Deposit object, we can implement the print logic without needing case statements at all.
class Deposit
# ... lines omitted
def to_s
string = "#{#amount} #{#unit}"
string << ", #{#apr * 100.0}% APR" if #apr > 0.0
string
end
end
d = Deposit.new(656.00, 'rupees', apr: 0.065)
d.to_s
# => "656.0 rupees, 6.5% APR"
e = Deposit.new(100, 'USD', apr: nil)
e.to_s
# => "100.0 USD"
f = Deposit.new(100, 'USD')
f.to_s
# => "100.0 USD"
Conclusion: If you're comparing multiple variables in a case statement, use that as a smell to suggest a deeper design issue. Multiple-variable cases might indicate that there's an object that wants to be created.
If you are worried about breaking something by changing Array behavior, and certainly that's a reasonable worry, then just put your revised operator in a subclass of Array.
it's definitely not the best way. even more - you should not redefine methods of standart classes as core functionality may depend on it - have fun debugging then.
defensive style is nice(with lot of type checks and whatnot) but it usually hurts performance and readability.
if you know that you will not pass anything else than bunch of floats and strings to that method - why do you need all those checks for?
IMO use exception catching and fix the source of problem, don't try to fix the problem somewhere in the middle