require File.dirname(__FILE__) + '/../spec_helper' require File.dirname(__FILE__) + '/constraint_helper' class SortSampleProblem < Gecode::Model attr :vars attr :sorted attr :indices def initialize @vars = int_var_array(4, 10..19) @sorted = int_var_array(4, 10..19) @indices = int_var_array(4, 0..9) # To make it more interesting @vars.must_be.distinct branch_on @vars end end describe Gecode::Constraints::IntEnum::Sort, ' (without :as and :order)' do before do @model = SortSampleProblem.new @vars = @model.vars @sorted = @model.sorted @invoke_options = lambda do |hash| @vars.must_be.sorted(hash) @model.solve! end @expect_options = option_expectation do |strength, kind, reif_var| if reif_var.nil? Gecode::Raw.should_receive(:rel).exactly(@vars.size - 1).times.with( an_instance_of(Gecode::Raw::Space), an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::IRT_LQ, an_instance_of(Gecode::Raw::IntVar), strength, kind) else Gecode::Raw.should_receive(:rel).once.with( an_instance_of(Gecode::Raw::Space), anything, an_instance_of(Gecode::Raw::BoolVarArray), anything, anything, anything) Gecode::Raw.should_receive(:rel).exactly(@vars.size - 1).times.with( an_instance_of(Gecode::Raw::Space), an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::IRT_LQ, an_instance_of(Gecode::Raw::IntVar), an_instance_of(Gecode::Raw::BoolVar), strength, kind) end end end it 'should translate into n relation constraints' do @expect_options.call({}) @invoke_options.call({}) end it 'should constraint variables to be sorted' do @vars.must_be.sorted values = @model.solve!.vars.values values.should == values.sort end it 'should allow negation' do @vars.must_not_be.sorted @model.solve! values = @vars.values values.should_not == values.sort end it_should_behave_like 'reifiable constraint' end describe Gecode::Constraints::IntEnum::Sort, ' (with :as)' do before do @model = SortSampleProblem.new @vars = @model.vars @sorted = @model.sorted # Make it a bit more interesting. @vars[0].must > @vars[3] + 1 @invoke_options = lambda do |hash| @vars.must_be.sorted hash.update(:as => @sorted) @model.solve! end @expect_options = option_expectation do |strength, kind, reif_var| Gecode::Raw.should_receive(:sorted).once.with( an_instance_of(Gecode::Raw::Space), an_instance_of(Gecode::Raw::IntVarArray), an_instance_of(Gecode::Raw::IntVarArray), strength, kind) end end it 'should translate into a sortedness constraints' do @expect_options.call({}) @invoke_options.call({}) end it 'should constraint variables to be sorted' do @vars.must_be.sorted(:as => @sorted) @model.solve! values = @sorted.values values.should == values.sort end it 'should not allow targets that are not int var enums' do lambda{ @vars.must_be.sorted(:as => 'hello') }.should raise_error(TypeError) end it 'should not allow negation' do lambda{ @vars.must_not_be.sorted(:as => @sorted) }.should raise_error( Gecode::MissingConstraintError) end it_should_behave_like 'non-reifiable constraint' end describe Gecode::Constraints::IntEnum::Sort, ' (with :order)' do before do @model = SortSampleProblem.new @vars = @model.vars @sorted = @model.sorted @indices = @model.indices # Make it a bit more interesting. @vars[0].must > @vars[3] + 1 @invoke_options = lambda do |hash| @vars.must_be.sorted hash.update(:order => @indices, :as => @sorted) @model.solve! end @expect_options = option_expectation do |strength, kind, reif_var| Gecode::Raw.should_receive(:sorted).once.with( an_instance_of(Gecode::Raw::Space), an_instance_of(Gecode::Raw::IntVarArray), an_instance_of(Gecode::Raw::IntVarArray), an_instance_of(Gecode::Raw::IntVarArray), strength, kind) end end it 'should translate into a sortedness constraints' do @expect_options.call({}) @invoke_options.call({}) end it 'should translate into a sortedness constraints, even without a target' do @expect_options.call({}) @vars.must_be.sorted(:order => @indices) @model.solve! end it 'should constraint variables to be sorted with the specified indices' do @vars.must_be.sorted(:as => @sorted, :order => @indices) @model.solve! sorted_values = @sorted.values sorted_values.should == sorted_values.sort expected_indices = @vars.map{ |v| sorted_values.index(v.value) } @indices.values.should == expected_indices end it 'should not allow targets that are not int var enums' do lambda do @vars.must_be.sorted(:as => 'hello', :order => @indices) end.should raise_error(TypeError) end it 'should not allow order that are not int var enums' do lambda do @vars.must_be.sorted(:as => @sorted, :order => 'hello') end.should raise_error(TypeError) end it 'should not allow negation' do lambda do @vars.must_not_be.sorted(:as => @sorted, :order => @indices) end.should raise_error(Gecode::MissingConstraintError) end it_should_behave_like 'non-reifiable constraint' end