Files
ortools-clone/examples/csharp/costas_array.cs
2012-03-28 14:23:23 +00:00

182 lines
4.7 KiB
C#

//
// Copyright 2012 Hakan Kjellerstrand
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Google.OrTools.ConstraintSolver;
public class CostasArray
{
/**
*
* Costas array
*
* From http://mathworld.wolfram.com/CostasArray.html:
* """
* An order-n Costas array is a permutation on {1,...,n} such
* that the distances in each row of the triangular difference
* table are distinct. For example, the permutation {1,3,4,2,5}
* has triangular difference table {2,1,-2,3}, {3,-1,1}, {1,2},
* and {4}. Since each row contains no duplications, the permutation
* is therefore a Costas array.
* """
*
* Also see
* http://en.wikipedia.org/wiki/Costas_array
* http://hakank.org/or-tools/costas_array.py
*
*/
private static void Solve(int n = 6)
{
Solver solver = new Solver("CostasArray");
//
// Data
//
Console.WriteLine("n: {0}", n);
//
// Decision variables
//
IntVar[] costas = solver.MakeIntVarArray(n, 1, n, "costas");
IntVar[,] differences = solver.MakeIntVarMatrix(n, n, -n+1, n-1,
"differences");
//
// Constraints
//
// Fix the values in the lower triangle in the
// difference matrix to -n+1. This removes variants
// of the difference matrix for the the same Costas array.
for(int i = 0; i < n; i++) {
for(int j = 0; j <= i; j++ ) {
solver.Add(differences[i,j] == -n+1);
}
}
// hakank: All the following constraints are from
// Barry O'Sullivans's original model.
//
solver.Add(costas.AllDifferent());
// "How do the positions in the Costas array relate
// to the elements of the distance triangle."
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if (i < j) {
solver.Add( differences[i,j] - (costas[j] - costas[j-i-1]) == 0);
}
}
}
// "All entries in a particular row of the difference
// triangle must be distint."
for(int i = 0; i < n-2; i++) {
IntVar[] tmp = (
from j in Enumerable.Range(0, n)
where j > i
select differences[i,j]).ToArray();
solver.Add(tmp.AllDifferent());
}
//
// "All the following are redundant - only here to speed up search."
//
// "We can never place a 'token' in the same row as any other."
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if (i < j) {
solver.Add(differences[i,j] != 0);
solver.Add(differences[i,j] != 0);
}
}
}
for(int k = 2; k < n; k++) {
for(int l = 2; l < n; l++) {
if (k < l) {
solver.Add(
(differences[k-2,l-1] + differences[k,l]) -
(differences[k-1,l-1] + differences[k-1,l]) == 0
);
}
}
}
//
// Search
//
DecisionBuilder db = solver.MakePhase(costas,
Solver.CHOOSE_FIRST_UNBOUND,
Solver.ASSIGN_MIN_VALUE);
solver.NewSearch(db);
while (solver.NextSolution()) {
Console.Write("costas: ");
for(int i = 0; i < n; i++) {
Console.Write("{0} ", costas[i].Value());
}
Console.WriteLine("\ndifferences:");
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
long v = differences[i,j].Value();
if (v == -n+1) {
Console.Write(" ");
} else {
Console.Write("{0,2} ", v);
}
}
Console.WriteLine();
}
Console.WriteLine();
}
Console.WriteLine("\nSolutions: {0}", solver.Solutions());
Console.WriteLine("WallTime: {0}ms", solver.WallTime());
Console.WriteLine("Failures: {0}", solver.Failures());
Console.WriteLine("Branches: {0} ", solver.Branches());
solver.EndSearch();
}
public static void Main(String[] args)
{
int n = 6;
if (args.Length > 0) {
n = Convert.ToInt32(args[0]);
}
Solve(n);
}
}