gecoder-with-gecode 0.8.2 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +14 -0
- data/ext/gecoder.cpp +181 -0
- data/ext/gecoder.h +94 -0
- data/ext/vararray.cpp +3 -3
- data/lib/gecoder/bindings/bindings.rb +104 -46
- data/lib/gecoder/interface/binding_changes.rb +1 -301
- data/lib/gecoder/interface/branch.rb +15 -11
- data/lib/gecoder/interface/constraints.rb +38 -0
- data/lib/gecoder/interface/constraints/bool/boolean.rb +56 -52
- data/lib/gecoder/interface/constraints/bool/channel.rb +1 -16
- data/lib/gecoder/interface/constraints/bool_enum/channel.rb +13 -8
- data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +48 -0
- data/lib/gecoder/interface/constraints/extensional_regexp.rb +101 -0
- data/lib/gecoder/interface/constraints/int/channel.rb +1 -13
- data/lib/gecoder/interface/constraints/int_enum/channel.rb +15 -35
- data/lib/gecoder/interface/constraints/int_enum/extensional.rb +130 -0
- data/lib/gecoder/interface/constraints/set/channel.rb +54 -0
- data/lib/gecoder/interface/constraints/set_enum/channel.rb +37 -6
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +1 -0
- data/lib/gecoder/interface/model.rb +110 -85
- data/lib/gecoder/interface/variables.rb +3 -21
- data/lib/gecoder/version.rb +1 -1
- data/specs/branch.rb +16 -1
- data/specs/constraints/bool_enum_relation.rb +6 -6
- data/specs/constraints/boolean.rb +31 -25
- data/specs/constraints/channel.rb +102 -4
- data/specs/constraints/extensional.rb +185 -2
- data/specs/constraints/reification_sugar.rb +2 -46
- data/specs/model.rb +85 -7
- data/tasks/dependencies.txt +1 -0
- data/vendor/rust/rust/class.rb +33 -35
- data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +1 -1
- data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +10 -1
- metadata +707 -706
- data/example/raw_bindings.rb +0 -44
- data/ext/missing.cpp +0 -328
- data/ext/missing.h +0 -120
- data/specs/binding_changes.rb +0 -76
@@ -1,23 +1,8 @@
|
|
1
1
|
module Gecode::Constraints::Bool
|
2
2
|
class Expression
|
3
|
-
alias_method :pre_channel_equals, :==
|
4
|
-
|
5
3
|
# Constrains the boolean variable to be equal to the specified integer
|
6
4
|
# variable.
|
7
|
-
|
8
|
-
unless @params[:lhs].kind_of?(Gecode::FreeBoolVar) and
|
9
|
-
int.kind_of?(Gecode::FreeIntVar)
|
10
|
-
return pre_channel_equals(int, options)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Provide commutivity to the corresponding int variable constraint.
|
14
|
-
if @params[:negate]
|
15
|
-
int.must_not.equal(@params[:lhs], options)
|
16
|
-
else
|
17
|
-
int.must.equal(@params[:lhs], options)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
5
|
+
provide_commutivity(:==){ |rhs, _| rhs.kind_of?(Gecode::FreeIntVar) }
|
21
6
|
alias_comparison_methods
|
22
7
|
end
|
23
8
|
end
|
@@ -6,7 +6,7 @@ module Gecode::Constraints::BoolEnum
|
|
6
6
|
#
|
7
7
|
# [:offset] Specifies an offset for the integer variable. If the offset is
|
8
8
|
# set to k then the integer variable takes value i+k exactly
|
9
|
-
# when the variable at index i in the boolean
|
9
|
+
# when the variable at index i in the boolean enumeration is true
|
10
10
|
# and the rest are false.
|
11
11
|
def channel(int_var, options = {})
|
12
12
|
if @params[:negate]
|
@@ -25,28 +25,33 @@ module Gecode::Constraints::BoolEnum
|
|
25
25
|
@params.update(Gecode::Constraints::Util.decode_options(options))
|
26
26
|
@model.add_constraint Channel::ChannelConstraint.new(@model, @params)
|
27
27
|
end
|
28
|
+
|
29
|
+
# Adds a channel constraint on the variables in the enum with the specified
|
30
|
+
# set variable.
|
31
|
+
provide_commutivity(:channel){ |rhs, _| rhs.kind_of? Gecode::FreeSetVar }
|
28
32
|
end
|
29
33
|
|
30
34
|
# A module that gathers the classes and modules used in channel constraints
|
31
35
|
# involving one boolean enum and one integer variable.
|
32
36
|
module Channel #:nodoc:
|
33
|
-
# Describes a channel constraint that "channels" an
|
37
|
+
# Describes a channel constraint that "channels" an enumeration of
|
34
38
|
# boolean variables with an integer variable. This constrains the integer
|
35
39
|
# variable to take value i exactly when the variable at index i in the
|
36
40
|
# boolean enumeration is true and the others are false.
|
37
41
|
#
|
38
|
-
# Neither reification nor negation is supported.
|
42
|
+
# Neither reification nor negation is supported. The int variable
|
43
|
+
# and the enumeration can be interchanged.
|
39
44
|
#
|
40
45
|
# == Examples
|
41
46
|
#
|
42
|
-
# # Constrains the enumeration called +
|
47
|
+
# # Constrains the enumeration called +option_is_selected+ to be false in the
|
43
48
|
# # first four positions and have exactly one true variable in the other.
|
44
|
-
#
|
49
|
+
# option_is_selected.must.channel selected_option_index
|
45
50
|
# selected_option_index.must_be > 3
|
46
51
|
#
|
47
|
-
# # Constrains the enumeration called +
|
52
|
+
# # Constrains the enumeration called +option_is_selected+ to be false in the
|
48
53
|
# # first five positions and have exactly one true variable in the other.
|
49
|
-
#
|
54
|
+
# selected_option_index.must.channel(option_is_selected, :offset => 1)
|
50
55
|
# selected_option_index.must_be > 3
|
51
56
|
class ChannelConstraint < Gecode::Constraints::Constraint
|
52
57
|
def post
|
@@ -56,4 +61,4 @@ module Gecode::Constraints::BoolEnum
|
|
56
61
|
end
|
57
62
|
end
|
58
63
|
end
|
59
|
-
end
|
64
|
+
end
|
@@ -25,6 +25,27 @@ module Gecode::Constraints::BoolEnum
|
|
25
25
|
@model.add_constraint Extensional::TupleConstraint.new(@model,
|
26
26
|
@params.update(Gecode::Constraints::Util.decode_options(options)))
|
27
27
|
end
|
28
|
+
|
29
|
+
# Adds a constraint that forces the enumeration to match the
|
30
|
+
# specified regular expression over the boolean domain. The regular
|
31
|
+
# expression is expressed using arrays and boolean values (or
|
32
|
+
# integers). See BoolEnum::Extensional::RegexpConstraint for more information
|
33
|
+
# and examples of such regexps.
|
34
|
+
def match(regexp, options = {})
|
35
|
+
if @params[:negate]
|
36
|
+
raise Gecode::MissingConstraintError, 'A negated regexp constraint ' +
|
37
|
+
'is not implemented.'
|
38
|
+
end
|
39
|
+
unless options[:reify].nil?
|
40
|
+
raise ArgumentError, 'Reification is not supported by the regexp ' +
|
41
|
+
'constraint.'
|
42
|
+
end
|
43
|
+
|
44
|
+
@params[:regexp] =
|
45
|
+
Gecode::Constraints::Util::Extensional.parse_regexp regexp
|
46
|
+
@params.update Gecode::Constraints::Util.decode_options(options)
|
47
|
+
@model.add_constraint Extensional::RegexpConstraint.new(@model, @params)
|
48
|
+
end
|
28
49
|
end
|
29
50
|
|
30
51
|
# A module that gathers the classes and modules used in extensional
|
@@ -60,5 +81,32 @@ module Gecode::Constraints::BoolEnum
|
|
60
81
|
*propagation_options)
|
61
82
|
end
|
62
83
|
end
|
84
|
+
|
85
|
+
# Describes a regexp constraint, which constrains the enumeration of
|
86
|
+
# boolean variables to match a specified regexp in the boolean
|
87
|
+
# domain. Neither negation nor reification is supported.
|
88
|
+
#
|
89
|
+
# The regular expressions are specified as described in
|
90
|
+
# IntEnum::Extensional::RegexpConstraint but true and false can be
|
91
|
+
# used instead of integers.
|
92
|
+
#
|
93
|
+
# == Example
|
94
|
+
#
|
95
|
+
# # Constrains the two boolean variables in +bools+ to be false
|
96
|
+
# # and true respectively.
|
97
|
+
# bools.must.match [false, true]
|
98
|
+
#
|
99
|
+
# # Constrains the boolean variables in +bools+ to be false,
|
100
|
+
# # except for three consecutive variables which should be true
|
101
|
+
# # followed by false followed by true.
|
102
|
+
# bools.must.match [repeat(false), true, false, true, repeat(false)]]
|
103
|
+
#
|
104
|
+
class RegexpConstraint < Gecode::Constraints::Constraint
|
105
|
+
def post
|
106
|
+
lhs, regexp = @params.values_at(:lhs, :regexp)
|
107
|
+
Gecode::Raw::extensional(@model.active_space, lhs.to_bool_var_array,
|
108
|
+
regexp, *propagation_options)
|
109
|
+
end
|
110
|
+
end
|
63
111
|
end
|
64
112
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Gecode
|
2
|
+
class Model
|
3
|
+
# Specifies an integer regexp that matches +regexp+ repeated between
|
4
|
+
# +at_least+ and +at_most+ times (inclusive). If +at_most+ is
|
5
|
+
# omitted then no upper bound is placed. If both +at_least+ and
|
6
|
+
# +at_most+ are omitted then no bounds are placed.
|
7
|
+
#
|
8
|
+
# See Constraints::IntEnum::Extensional::RegexpConstraint for the
|
9
|
+
# allowed syntax of +regexp+.
|
10
|
+
def repeat(regexp, at_least = nil, at_most = nil)
|
11
|
+
unless at_least.nil? or at_least.kind_of? Fixnum
|
12
|
+
raise TypeError,
|
13
|
+
"Expected the at_least argument to be a Fixnum, got #{at_least.class}"
|
14
|
+
end
|
15
|
+
unless at_most.nil? or at_most.kind_of?(Fixnum)
|
16
|
+
raise TypeError,
|
17
|
+
"Expected the at_most argument to be a Fixnum, got #{at_most.class}"
|
18
|
+
end
|
19
|
+
|
20
|
+
reg = Constraints::Util::Extensional.parse_regexp regexp
|
21
|
+
if at_most.nil?
|
22
|
+
if at_least.nil?
|
23
|
+
reg.send '*'
|
24
|
+
else
|
25
|
+
reg.send('()', at_least)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
reg.send('()', at_least, at_most)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Matches +regexp+ repeated zero or one time (i.e. like '?' in normal
|
33
|
+
# regexps). Produces the same result as calling
|
34
|
+
#
|
35
|
+
# repeat(regexp, 0, 1)
|
36
|
+
def at_most_once(regexp)
|
37
|
+
repeat(regexp, 0, 1)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Matches +regexp+ repeated at least one time (i.e. like '+' in normal
|
41
|
+
# regexps). Produces the same result as calling
|
42
|
+
#
|
43
|
+
# repeat(regexp, 1)
|
44
|
+
def at_least_once(regexp)
|
45
|
+
repeat(regexp, 1)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Matches any of the specified +regexps+.
|
49
|
+
def any(*regexps)
|
50
|
+
regexps.inject(Gecode::Raw::REG.new) do |result, regexp|
|
51
|
+
result | Constraints::Util::Extensional.parse_regexp(regexp)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Constraints::Util::Extensional
|
57
|
+
module_function
|
58
|
+
|
59
|
+
# Parses a regular expression over the integer domain, returning
|
60
|
+
# an instance of Gecode::REG .
|
61
|
+
#
|
62
|
+
# Pseudo-BNF of the integer regexp representation:
|
63
|
+
# regexp ::= <Fixnum> | <TrueClass> | <FalseClass> | <Gecode::Raw::REG>
|
64
|
+
# | [<regexp>, ...]
|
65
|
+
def parse_regexp(regexp)
|
66
|
+
# Check the involved types.
|
67
|
+
unless regexp.kind_of? Enumerable
|
68
|
+
regexp = [regexp]
|
69
|
+
end
|
70
|
+
regexp.to_a.flatten.each do |element|
|
71
|
+
unless element.kind_of?(Fixnum) or element.kind_of?(Gecode::Raw::REG) or
|
72
|
+
element.kind_of?(TrueClass) or element.kind_of?(FalseClass)
|
73
|
+
raise TypeError,
|
74
|
+
"Can't translate #{element.class} into integer or boolean regexp."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Convert it into a regexp.
|
79
|
+
internal_parse_regexp(regexp)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# Recursively converts arg into an instance of Gecode::REG. It is
|
85
|
+
# assumed that arg is of kind Gecode::Raw::REG, Fixnum, TrueClass,
|
86
|
+
# FalseClass or Enumerable.
|
87
|
+
def self.internal_parse_regexp(arg)
|
88
|
+
case arg
|
89
|
+
when Gecode::Raw::REG: arg
|
90
|
+
when Fixnum: Gecode::Raw::REG.new(arg)
|
91
|
+
when TrueClass: Gecode::Raw::REG.new(1)
|
92
|
+
when FalseClass: Gecode::Raw::REG.new(0)
|
93
|
+
when Enumerable
|
94
|
+
# Recursively convert the elements of the arg.
|
95
|
+
arg.inject(Gecode::Raw::REG.new) do |regexp, element|
|
96
|
+
regexp += internal_parse_regexp(element)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -35,19 +35,7 @@ module Gecode::Constraints::Int
|
|
35
35
|
# set to k then the integer variable takes value i+k exactly
|
36
36
|
# when the variable at index i in the boolean enumration is true
|
37
37
|
# and the rest are false.
|
38
|
-
|
39
|
-
unless bool_enum.respond_to? :to_bool_var_array
|
40
|
-
raise TypeError, 'Expected an enumration of boolean variables, got ' +
|
41
|
-
"#{bool_enum.class}."
|
42
|
-
end
|
43
|
-
|
44
|
-
# Just provide commutivity with the boolean enum channel constraint.
|
45
|
-
if @params[:negate]
|
46
|
-
bool_enum.must_not.channel(@params[:lhs], options)
|
47
|
-
else
|
48
|
-
bool_enum.must.channel(@params[:lhs], options)
|
49
|
-
end
|
50
|
-
end
|
38
|
+
provide_commutivity(:channel){ |rhs, _| rhs.respond_to? :to_bool_var_array }
|
51
39
|
end
|
52
40
|
|
53
41
|
# A module that gathers the classes and modules used in channel constraints
|
@@ -7,23 +7,20 @@ module Gecode::Constraints::IntEnum
|
|
7
7
|
raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
|
8
8
|
'is not implemented.'
|
9
9
|
end
|
10
|
-
unless enum.respond_to?(:to_int_var_array)
|
11
|
-
|
12
|
-
raise TypeError, "Expected int or set enum, got #{enum.class}."
|
10
|
+
unless enum.respond_to?(:to_int_var_array)
|
11
|
+
raise TypeError, "Expected int enum, got #{enum.class}."
|
13
12
|
end
|
14
|
-
if
|
15
|
-
|
16
|
-
|
17
|
-
'reification option.'
|
18
|
-
end
|
19
|
-
@params.update(Gecode::Constraints::Set::Util.decode_options(options))
|
20
|
-
else
|
21
|
-
@params.update(Gecode::Constraints::Util.decode_options(options))
|
13
|
+
if options.has_key? :reify
|
14
|
+
raise ArgumentError, 'The channel constraints does not support the ' +
|
15
|
+
'reification option.'
|
22
16
|
end
|
23
17
|
|
18
|
+
@params.update(Gecode::Constraints::Util.decode_options(options))
|
24
19
|
@params.update(:rhs => enum)
|
25
20
|
@model.add_constraint Channel::ChannelConstraint.new(@model, @params)
|
26
21
|
end
|
22
|
+
|
23
|
+
provide_commutivity(:channel){ |rhs, _| rhs.respond_to? :to_set_var_array }
|
27
24
|
end
|
28
25
|
|
29
26
|
# A module that gathers the classes and modules used in channel constraints.
|
@@ -33,14 +30,12 @@ module Gecode::Constraints::IntEnum
|
|
33
30
|
# enumeration of set variables. Channel constraints are used to give
|
34
31
|
# access to multiple viewpoints when modelling.
|
35
32
|
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
33
|
+
# The channel constraint can be thought of as constraining the arrays to
|
34
|
+
# be each other's inverses. I.e. if the i:th value in the first enumeration
|
35
|
+
# is j, then the j:th value in the second enumeration is constrained to be
|
36
|
+
# i.
|
40
37
|
#
|
41
|
-
# Neither reification nor negation is supported.
|
42
|
-
# supported when using the constraint between two integer enumerations,
|
43
|
-
# it's not supported when a set enumeration is used.
|
38
|
+
# Neither reification nor negation is supported.
|
44
39
|
#
|
45
40
|
# == Example
|
46
41
|
#
|
@@ -82,26 +77,11 @@ module Gecode::Constraints::IntEnum
|
|
82
77
|
#
|
83
78
|
# elements.must.channel positions
|
84
79
|
#
|
85
|
-
# == Example (sets)
|
86
|
-
#
|
87
|
-
# # +set_enum+ is constrained to channel +int_enum+.
|
88
|
-
# int_enum.must.channel set_enum
|
89
|
-
#
|
90
|
-
# # This is another way of saying the above.
|
91
|
-
# set_enum.must.channel int_enum
|
92
80
|
class ChannelConstraint < Gecode::Constraints::Constraint
|
93
81
|
def post
|
94
82
|
lhs, rhs = @params.values_at(:lhs, :rhs)
|
95
|
-
|
96
|
-
|
97
|
-
if rhs.respond_to? :to_int_var_array
|
98
|
-
# Int var array.
|
99
|
-
Gecode::Raw::channel(@model.active_space, lhs, rhs.to_int_var_array,
|
100
|
-
*propagation_options)
|
101
|
-
else
|
102
|
-
# Set var array, no propagation options.
|
103
|
-
Gecode::Raw::channel(@model.active_space, lhs, rhs.to_set_var_array)
|
104
|
-
end
|
83
|
+
Gecode::Raw::channel(@model.active_space, lhs.to_int_var_array,
|
84
|
+
rhs.to_int_var_array, *propagation_options)
|
105
85
|
end
|
106
86
|
end
|
107
87
|
end
|
@@ -26,6 +26,27 @@ module Gecode::Constraints::IntEnum
|
|
26
26
|
@model.add_constraint Extensional::TupleConstraint.new(@model,
|
27
27
|
@params.update(util.decode_options(options)))
|
28
28
|
end
|
29
|
+
|
30
|
+
# Adds a constraint that forces the enumeration to match the
|
31
|
+
# specified regular expression over the integer domain. The regular
|
32
|
+
# expression is expressed using arrays and integers. See
|
33
|
+
# IntEnum::Extensional::RegexpConstraint for more information and examples of
|
34
|
+
# such regexps.
|
35
|
+
def match(regexp, options = {})
|
36
|
+
if @params[:negate]
|
37
|
+
raise Gecode::MissingConstraintError, 'A negated regexp constraint ' +
|
38
|
+
'is not implemented.'
|
39
|
+
end
|
40
|
+
unless options[:reify].nil?
|
41
|
+
raise ArgumentError, 'Reification is not supported by the regexp ' +
|
42
|
+
'constraint.'
|
43
|
+
end
|
44
|
+
|
45
|
+
@params[:regexp] =
|
46
|
+
Gecode::Constraints::Util::Extensional.parse_regexp regexp
|
47
|
+
@params.update Gecode::Constraints::Util.decode_options(options)
|
48
|
+
@model.add_constraint Extensional::RegexpConstraint.new(@model, @params)
|
49
|
+
end
|
29
50
|
end
|
30
51
|
|
31
52
|
# A module that gathers the classes and modules used in extensional
|
@@ -60,5 +81,114 @@ module Gecode::Constraints::IntEnum
|
|
60
81
|
*propagation_options)
|
61
82
|
end
|
62
83
|
end
|
84
|
+
|
85
|
+
# Describes a regexp constraint, which constrains the enumeration of
|
86
|
+
# integer variables to match a specified regexp in the integer
|
87
|
+
# domain. Neither negation nor reification is supported.
|
88
|
+
#
|
89
|
+
# == Regexp syntax
|
90
|
+
#
|
91
|
+
# The regular expressions are specified using arrays, integers and a
|
92
|
+
# few methods provided by Model. Arrays are used to group the
|
93
|
+
# integers in sequences that must be matched. The following array
|
94
|
+
# describes a regular expression matching a 1 followed by a 7.
|
95
|
+
#
|
96
|
+
# [1, 7]
|
97
|
+
#
|
98
|
+
# Arrays can be nested or left out when not needed. I.e. the above
|
99
|
+
# is semantically equal to
|
100
|
+
#
|
101
|
+
# [[[1], 7]]
|
102
|
+
#
|
103
|
+
# A couple of methods provided by Model are used to express patterns
|
104
|
+
# beyond mere sequences:
|
105
|
+
#
|
106
|
+
# [Model#repeat] Used for specifying patterns that include patterns
|
107
|
+
# that may be repeated a given number of times. The
|
108
|
+
# number of times to repeat a pattern can be specified
|
109
|
+
# using a lower and upper bound, but the bounds can be
|
110
|
+
# omitted to for instance allow an expression to be
|
111
|
+
# repeated any number of times.
|
112
|
+
# [Model#any] Used for specifying alternatives.
|
113
|
+
#
|
114
|
+
# Additionally Model#at_least_once and Model#at_most_once are
|
115
|
+
# provided as convenience methods.
|
116
|
+
#
|
117
|
+
# === Examples
|
118
|
+
#
|
119
|
+
# # Matches 1 followed by any number of 2s.
|
120
|
+
# [1, repeat(2)]
|
121
|
+
#
|
122
|
+
# # Semantically the same as above. It just has a bunch of
|
123
|
+
# # needless brackets thrown in.
|
124
|
+
# [[1], [repeat([2])]]
|
125
|
+
#
|
126
|
+
# # Matches 1 followed by [a 2 followed by a 3] at least two times.
|
127
|
+
# # Matches e.g. 1, 2, 3, 2, 3
|
128
|
+
# [1, repeat([2, 3], 2)]
|
129
|
+
#
|
130
|
+
# # Matches between one and two [2 followed by [at least three 1]]
|
131
|
+
# # followed by between three and four 3. Matches e.g.
|
132
|
+
# # 2, 1, 1, 1, 2, 1, 1, 1, 3, 3, 3
|
133
|
+
# [repeat([2, repeat(1, 3], 1, 2), repeat(3, 3, 4)]
|
134
|
+
#
|
135
|
+
# # Matches [1, 2 or 3] followed by 4. Matches e.g. 2, 4
|
136
|
+
# [any(1, 2, 3), 4]
|
137
|
+
#
|
138
|
+
# # Matches 0 followed by [[1 followed by 2] or [3 followed by 5]].
|
139
|
+
# # Matches e.g. 0, 1, 2 as well as 0, 3, 5
|
140
|
+
# [0, any([1, 2], [3, 5])]
|
141
|
+
#
|
142
|
+
# # Matches 0 followed by [[[1 followed by 7] at least two times]
|
143
|
+
# # or [[8, 9], at most two times]. Matches e.g.
|
144
|
+
# # 0, 1, 7, 1, 7, 1, 7 as well as 0, 8, 9
|
145
|
+
# [0, any(repeat([1, 7], 2), repeat([8, 9], 0, 2)]
|
146
|
+
#
|
147
|
+
# # Matches 0 followed by at least one 1.
|
148
|
+
# [0, at_least_once(1)]
|
149
|
+
#
|
150
|
+
# # Exactly the same as the above.
|
151
|
+
# [0, repeat(1, 1)]
|
152
|
+
#
|
153
|
+
# # Matches 0 followed by at least one [[1 followed by 7] or [3
|
154
|
+
# # followed by 2]]. Matches e.g. 0, 1, 7, 3, 2, 1, 7
|
155
|
+
# [0, at_least_once(any([1, 7], [3, 2]]
|
156
|
+
#
|
157
|
+
# # Matches 0 followed by at either [[1 followed by 7] at least once]
|
158
|
+
# # or [[3 followed by 2] at least once]. Matches e.g.
|
159
|
+
# # 0, 1, 7, 1, 7 but does _not_ match 0, 1, 7, 3, 2, 1, 7
|
160
|
+
# [0, any(at_least_once([1, 7]), at_least_once([3, 2])]
|
161
|
+
#
|
162
|
+
# # Matches 0, followed by at most one 1. Matches 0 as well as
|
163
|
+
# # 0, 1
|
164
|
+
# [0, at_most_once(1)]
|
165
|
+
#
|
166
|
+
# # Exactly the same as the above.
|
167
|
+
# [0, repeat(1, 0, 1)]
|
168
|
+
#
|
169
|
+
# == Example
|
170
|
+
#
|
171
|
+
# # Constrains the two integer variables in +numbers+ to have
|
172
|
+
# # values 1 and 7.
|
173
|
+
# numbers.must.match [1, 7]
|
174
|
+
#
|
175
|
+
# # Constrains the integer variables in +numbers+ to contain the
|
176
|
+
# # value 47 followed by 11, with all other values set to -1.
|
177
|
+
# numbers.must.match [repeat(-1), 47, 11, repeat(-1)]
|
178
|
+
#
|
179
|
+
# # Constrains exactly three of the integer variables in +numbers+ to
|
180
|
+
# # contain 47 or 11, each followed by at least two
|
181
|
+
# # variables set to -1. All other variables are constrained to
|
182
|
+
# # equal -1.
|
183
|
+
# numbers.must.match repeat([repeat(-1), any(11, 47),
|
184
|
+
# repeat(-1, 2)], 3, 3)
|
185
|
+
#
|
186
|
+
class RegexpConstraint < Gecode::Constraints::Constraint
|
187
|
+
def post
|
188
|
+
lhs, regexp = @params.values_at(:lhs, :regexp)
|
189
|
+
Gecode::Raw::extensional(@model.active_space, lhs.to_int_var_array,
|
190
|
+
regexp, *propagation_options)
|
191
|
+
end
|
192
|
+
end
|
63
193
|
end
|
64
194
|
end
|