@@ -1143,6 +1143,49 @@ struct AllDifferent <: AbstractVectorSet
11431143 end
11441144end
11451145
1146+ """
1147+ CountDistinct(dimension::Int)
1148+
1149+ The set ``\\ {(n, x) \\ in \\ mathbb{R}^{1+d}\\ }`` such that the number of distinct
1150+ values in `x` is `n`.
1151+
1152+ This constraint is sometimes called `nvalues`.
1153+
1154+ ## Example
1155+
1156+ ```julia
1157+ model = Utilities.Model{Float64}()
1158+ n = add_constrained_variable(model, MOI.Integer())
1159+ x = [add_constrained_variable(model, MOI.Integer()) for _ in 1:3]
1160+ add_constraint(model, vcat(n, x), CountDistinct(4))
1161+ # if n == 1, then x[1] == x[2] == x[3]
1162+ # if n == 2, then x[1] == x[2] != x[3] || x[1] != x[2] == x[3]
1163+ # if n == 3, then x[1] != x[2] != x[3]
1164+ ```
1165+
1166+ ## Relationship to AllDifferent
1167+
1168+ When the first element is `dimension - 1`, `CountDistinct` is equivalent to an
1169+ [`AllDifferent`](@ref) constraint.
1170+
1171+ ```julia
1172+ model = Utilities.Model{Float64}()
1173+ x = [add_constrained_variable(model, MOI.Integer()) for _ in 1:3]
1174+ add_constraint(model, vcat(3, x), CountDistinct(4))
1175+ # equivalent to
1176+ add_constraint(model, x, AllDifferent(3))
1177+ ```
1178+ """
1179+ struct CountDistinct <: AbstractVectorSet
1180+ dimension:: Int
1181+ function CountDistinct (dimension:: Base.Integer )
1182+ if dimension < 1
1183+ throw (DimensionMismatch (" Dimension of CountDistinct must be >= 1." ))
1184+ end
1185+ return new (dimension)
1186+ end
1187+ end
1188+
11461189# isbits types, nothing to copy
11471190function Base. copy (
11481191 set:: Union {
@@ -1178,6 +1221,7 @@ function Base.copy(
11781221 Semicontinuous,
11791222 Semiinteger,
11801223 AllDifferent,
1224+ CountDistinct,
11811225 },
11821226)
11831227 return set
0 commit comments