Skip to content

Commit

Permalink
Update documentation and refactor matcher messages.
Browse files Browse the repository at this point in the history
  • Loading branch information
kouno committed Aug 3, 2012
1 parent abf3e1a commit 46935e9
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 41 deletions.
12 changes: 12 additions & 0 deletions lib/big-o/complexity_base.rb
Expand Up @@ -164,7 +164,19 @@ def get_scale
# @yield [*args] function which needs to be measured
# @return [Numeric] measurement
def measure(*args, &b)
end

# Creates a descriptive string of the calculated complexity.
#
# @see Object#to_s
def to_s
"values: #{values_to_s} scale: #@scale total values: #{@result_set.size} on #{@options[:range].max}"
end

# Converts result set to a string.
#
# @return [String]
def values_to_s
end
end
end
18 changes: 2 additions & 16 deletions lib/big-o/matchers/match_complexity_level.rb
Expand Up @@ -5,24 +5,10 @@
end

failure_message_for_should do |complexity|
# since we are playing around with floating values,
# sorting the result_set helps minimising issues with addition of floats
result_set = complexity.result_set.sort
total = result_set.inject(0) { |sum, r| sum + r[1] }.to_f
"expected a complexity level of #{o_notation}, " +
"got scale: #{complexity.scale} min: #{result_set[0][1]} " +
"max: #{result_set[-1][1]} " +
"avg: #{total / result_set.size} " +
"total values: #{result_set.size} on #{complexity.options[:range]}"
"expected a complexity level of #{o_notation}, got (#{complexity.to_s})"
end

failure_message_for_should_not do |complexity|
result_set = complexity.result_set.sort
total = result_set.inject(0) { |sum, r| sum + r[1] }.to_f
"expected a complexity level over #{o_notation}, " +
"got scale: #{complexity.scale} min: #{result_set[0][1]} " +
"max: #{result_set[-1][1]} " +
"avg: #{total / result_set.size} " +
"total values: #{result_set.size} on #{complexity.options[:range]}"
"expected a complexity level over #{o_notation}, got (#{complexity.to_s})"
end
end
5 changes: 5 additions & 0 deletions lib/big-o/space_complexity.rb
Expand Up @@ -62,5 +62,10 @@ def watch_fork_memory(pid)
def memory_measure(pid)
`ps -o rss= -p #{pid}`.to_i
end

# @see ComplexityBase#values_to_s
def values_to_s
@result_set.values.to_s
end
end
end
25 changes: 15 additions & 10 deletions lib/big-o/time_complexity.rb
Expand Up @@ -15,15 +15,6 @@ def initialize(options = {})
super(tc_options.merge(options))
end

# Checks if the function can be measured and throw an error if it could not.
#
# @see ComplexityBase#process
def process
@scale ||= get_scale
raise InstantaneousExecutionError.new unless @scale > 0
super
end

# Measures the execution time that <code>fn</code> is using.
#
# @see ComplexityBase#measure
Expand All @@ -36,19 +27,33 @@ def measure(*args, &b)
BigDecimal.new(t1.utime.to_s) - BigDecimal.new(t0.utime.to_s)
end

# Gets scale.
#
# Implement tolerance for fast executing functions. Any function executing in less than
# 0.01 second will be scaled up by a factor of 10.
#
# @see ComplexityBase#get_scale
def get_scale
scale = super
while scale < BigDecimal.new('0.1')
while scale < BigDecimal.new('0.01')
increase_scale
scale = super
end

scale
end

# Increases scale.
#
# @return [void]
def increase_scale
raise InstantaneousExecutionError.new if @scale_increased_count >= @options[:scale_increase_limit]
@scale_increased_count += 1
end

# @see ComplexityBase#values_to_s
def values_to_s
@result_set.values.map(&:to_f).to_s
end
end
end
7 changes: 7 additions & 0 deletions spec/big-o/space_complexity_spec.rb
Expand Up @@ -6,6 +6,13 @@
@space_complexity = SpaceComplexity.new
end

it 'should implement value_to_s' do
@space_complexity.result_set = { 1 => 11_000,
2 => 12_000,
3 => 13_000 }
@space_complexity.values_to_s.should =~ /\A\[([0-9]+, ){2}[0-9]+\]\z/
end

it 'should raise an exception if timeout is reached and no result was found' do
@space_complexity.options[:timeout] = 0.001
@space_complexity.options[:fn] = lambda { |_| simulate_memory_space(1) }
Expand Down
25 changes: 16 additions & 9 deletions spec/big-o/time_complexity_spec.rb
Expand Up @@ -9,6 +9,13 @@
MIN_TIME = 0.01
AVG_TIME = 0.02

it 'should implement value_to_s' do
@time_complexity.result_set = { 1 => BigDecimal.new('0.0002'),
2 => BigDecimal.new('0.0004'),
3 => BigDecimal.new('0.0006') }
@time_complexity.values_to_s.should =~ /\A\[([0-9.]+, ){2}[0-9.]+\]\z/
end

it 'should raise an exception if timeout is reached and no result was found' do
@time_complexity.options[:timeout] = 0.001
@time_complexity.options[:fn] = proc { simulate_utime_processing(1) }
Expand Down Expand Up @@ -61,30 +68,30 @@
end
end

describe 'very small execution time functions (0.01 second and below)' do
it 'should still be valid in case of O(n**2)' do
describe 'with very small execution time functions (0.01 second and below)' do
it 'should still be valid for execution time close to ~0.01 second in case of O(n**2)' do
@time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(MIN_TIME * n**2) }
@time_complexity.should match_complexity_level 'O(n**2)', lambda { |n| n**2 }
@time_complexity.should_not match_complexity_level 'O(n log(n))', lambda { |n| n * Math::log(n) }
@time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
end

it 'should still be valid in case of O(n)' do
it 'should still be valid for execution time close to ~0.01 second in case of O(n)' do
@time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(MIN_TIME * n) }
@time_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
@time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
end

it 'should still be valid for execution time close to ~0.001 second' do
@time_complexity.options[:fn] = lambda { |n| simulate_utime_processing(BigDecimal.new('0.001') * n) }
it 'should still be valid for execution time under <0.001 second in case of O(n)' do
@time_complexity.options[:fn] = lambda { |n| a = 0; n.times do; a += 1 end }
@time_complexity.should match_complexity_level 'O(n)', lambda { |n| n }
@time_complexity.should_not match_complexity_level 'O(1)', lambda { |_| 1 }
end

it 'should throw an error if execution time is not measurable for n = 1 (execution time under ~0.001 second)' do
# no calculation, execution time should be instant.
@time_complexity.options[:fn] = lambda { |_| 1 }
lambda { @time_complexity.process }.should raise_error(InstantaneousExecutionError)
it 'should still be valid for execution time under <0.001 second in case of O(1)' do
@time_complexity.options[:fn] = lambda { |_| a = 1 }
@time_complexity.options[:approximation] = 0.2
@time_complexity.should match_complexity_level 'O(1)', lambda { |_| 1 }
end
end
end
12 changes: 6 additions & 6 deletions spec/matchers/match_complexity_level_spec.rb
Expand Up @@ -24,9 +24,9 @@
it "should provide a descriptive error message" do
@matcher.matches?(@test_complexity)
@matcher.failure_message_for_should.should =~ /\Aexpected a complexity level of O\(1\)/
@matcher.failure_message_for_should.should =~ /got scale: [0-9.]+ min: [0-9.]+/
@matcher.failure_message_for_should.should =~ /max: [0-9.]+ avg: [0-9.]+/
@matcher.failure_message_for_should.should =~ /total values: [0-9]+ on 1\.\.20\Z/
@matcher.failure_message_for_should.should =~ /scale: [0-9.]+/
@matcher.failure_message_for_should.should =~ /\[[0-9E., ]+\]+/
@matcher.failure_message_for_should.should =~ /total values: [0-9]+ on 20/
end
end

Expand All @@ -38,9 +38,9 @@
it "should provide a descriptive error message" do
@matcher.matches?(@test_complexity)
@matcher.failure_message_for_should_not.should =~ /\Aexpected a complexity level over O\(n\)/
@matcher.failure_message_for_should_not.should =~ /got scale: [0-9.]+ min: [0-9.]+/
@matcher.failure_message_for_should_not.should =~ /max: [0-9.]+ avg: [0-9.]+/
@matcher.failure_message_for_should_not.should =~ /total values: [0-9]+ on 1\.\.20\Z/
@matcher.failure_message_for_should_not.should =~ /scale: [0-9E.]+/
@matcher.failure_message_for_should_not.should =~ /\[[0-9E., ]+\]+/
@matcher.failure_message_for_should_not.should =~ /total values: [0-9]+ on 20/
end
end
end

0 comments on commit 46935e9

Please sign in to comment.