Sha256: fabee7e0b4987ed02548dc33b955ea0a8c37a1e0964ae1579e14b96ca69e3e2f

Contents?: true

Size: 1.85 KB

Versions: 1

Compression:

Stored size: 1.85 KB

Contents

# frozen_string_literal: true

require "delta_debug/version"

# https://www.st.cs.uni-saarland.de/papers/tse2002/tse2002.pdf
class DeltaDebug
  def initialize(harness, verbose: $DEBUG)
    @harness = harness
    @verbose = verbose
  end

  attr_reader :verbose

  def run_test(input)
    print "testing #{input.inspect} = " if verbose
    result = @harness.call(input)
    if verbose
      sign =
        if result
          "❌"
        elsif result.nil?
          "❔"
        else
          "✅"
        end
      puts sign
    end
    result
  end

  def ddmin(input)
    convert_input = ->(x) { x }
    if String === input
      input = input.chars
      convert_input = ->(x) { x.join }
    end

    is_failure = Hash.new do |h, k|
      h[k] = run_test(convert_input.call(k))
    end

    raise "given input passes test" unless is_failure[input]
    return [] if is_failure[[]]

    n = 2
    while input.length > 1
      #puts "trying #{input.inspect} n=#{n}" if verbose
      segments = split(input, n)
      if failing_segment = segments.detect { |x| is_failure[x] }
        input = failing_segment
        n = 2
        next
      end

      complements = complements(segments)
      if failing_complement = complements.detect { |x| is_failure[x] }
        input = failing_complement
        n -= 1
        next
      end

      if n < input.length
        n = [n*2, input.length].min
      else
        break
      end
    end

    convert_input.call(input)
  end

  def complements(segments)
    # Technically the complement of segments for n=2 is segments, but that's not useful as we would have already tested that
    return [] if segments.length == 2

    (segments.length).times.map do |n|
      [*segments[0, n], *segments[n+1, segments.length]].flatten(1)
    end
  end

  def split(input, n)
    step = (input.size + n - 1) / n
    input.each_slice(step).to_a
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
delta_debug-0.1.0 lib/delta_debug.rb