public static Theorem <SudokuTable> Create(Z3Context context) { var sudokuTheorem = context.NewTheorem <SudokuTable>(); var cells = typeof(SudokuTable).GetProperties(); foreach (var cell in cells) { sudokuTheorem = sudokuTheorem.Where(Between1And9(cell)); } sudokuTheorem = sudokuTheorem.Where(DistinctRows(cells)); sudokuTheorem = sudokuTheorem.Where(DistinctColumns(cells)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell11, t.Cell12, t.Cell13, t.Cell21, t.Cell22, t.Cell23, t.Cell31, t.Cell32, t.Cell33)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell14, t.Cell15, t.Cell16, t.Cell24, t.Cell25, t.Cell26, t.Cell34, t.Cell35, t.Cell36)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell17, t.Cell18, t.Cell19, t.Cell27, t.Cell28, t.Cell29, t.Cell37, t.Cell38, t.Cell39)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell41, t.Cell42, t.Cell43, t.Cell51, t.Cell52, t.Cell53, t.Cell61, t.Cell62, t.Cell63)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell44, t.Cell45, t.Cell46, t.Cell54, t.Cell55, t.Cell56, t.Cell64, t.Cell65, t.Cell66)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell47, t.Cell48, t.Cell49, t.Cell57, t.Cell58, t.Cell59, t.Cell67, t.Cell68, t.Cell69)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell71, t.Cell72, t.Cell73, t.Cell81, t.Cell82, t.Cell83, t.Cell91, t.Cell92, t.Cell93)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell74, t.Cell75, t.Cell76, t.Cell84, t.Cell85, t.Cell86, t.Cell94, t.Cell95, t.Cell96)); sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(t.Cell77, t.Cell78, t.Cell79, t.Cell87, t.Cell88, t.Cell89, t.Cell97, t.Cell98, t.Cell99)); return(sudokuTheorem); }
/// <summary> /// Creates a Z3-capable theorem to solve a Sudoku /// </summary> /// <param name="context">The wrapping Z3 context used to interpret c# Lambda into Z3 constraints</param> /// <returns>A typed theorem to be further filtered with additional contraints</returns> public static Theorem <SudokuAsArray> Create(Z3Context context) { var sudokuTheorem = context.NewTheorem <SudokuAsArray>(); // Cells have values between 1 and 9 for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { //To avoid side effects with lambdas, we copy indices to local variables var i1 = i; var j1 = j; sudokuTheorem = sudokuTheorem.Where(sudoku => sudoku.Cells[i1 * 9 + j1] > 0 && sudoku.Cells[i1 * 9 + j1] < 10); } } // Rows must have distinct digits for (int r = 0; r < 9; r++) { //Again we avoid Lambda closure side effects var r1 = r; sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(Indices.Select(j => t.Cells[r1 * 9 + j]).ToArray())); } // Columns must have distinct digits for (int c = 0; c < 9; c++) { //Preventing closure side effects var c1 = c; sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(Indices.Select(i => t.Cells[i * 9 + c1]).ToArray())); } // Boxes must have distinct digits for (int b = 0; b < 9; b++) { //On évite les effets de bords par closure var b1 = b; // We retrieve to top left cell for all boxes, using integer division and remainders. var iStart = b1 / 3; var jStart = b1 % 3; var indexStart = iStart * 3 * 9 + jStart * 3; sudokuTheorem = sudokuTheorem.Where(t => Z3Methods.Distinct(new int[] { t.Cells[indexStart], t.Cells[indexStart + 1], t.Cells[indexStart + 2], t.Cells[indexStart + 9], t.Cells[indexStart + 10], t.Cells[indexStart + 11], t.Cells[indexStart + 18], t.Cells[indexStart + 19], t.Cells[indexStart + 20], } ) ); } return(sudokuTheorem); }
public Sudoku.Core.Sudoku Solve(Sudoku.Core.Sudoku s) { using (var ctx = new Z3Context()) { var theorem = CreateTheorem(ctx, s); theorem.DefaultCollectionHandling = CollectionHandling.Constants; return(theorem.Solve()); } }
///// <summary> ///// The array property is to be used in linq to Z3 ///// </summary> //public int[] Cells //{ // get => CellsList.ToArray(); // set => CellsList = new List<int>(value); //} /// <summary> /// Creates a Z3 theorem to solve the sudoku, adding the general constraints, and the mask constraints for this particular Sudoku /// </summary> /// <param name="context">The linq to Z3 context wrapping Z3</param> /// <returns>a theorem with all constraints compounded</returns> public Theorem <SudokuAsArray> CreateTheorem(Z3Context context) { var toReturn = Create(context); for (int i = 0; i < 81; i++) { if (Cells[i] != 0) { var idx = i; var cellValue = Cells[i]; toReturn = toReturn.Where(sudoku => sudoku.Cells[idx] == cellValue); } } return(toReturn); }
private static void Main(string[] args) { // Basic Usage using (var ctx = new Z3Context()) { ctx.Log = Console.Out; // see internal logging var theorem = from t in ctx.NewTheorem(new { x = default(bool), y = default(bool) }) where t.x ^ t.y select t; var result = theorem.Solve(); Console.WriteLine(result); } // Advanced Usage using (var ctx = new Z3Context()) { ctx.Log = Console.Out; // see internal logging var theorem = from t in ctx.NewTheorem <Symbols <int, int> >() where t.X1 < t.X2 + 1 where t.X1 > 2 where t.X1 != t.X2 select t; var result = theorem.Solve(); Console.WriteLine(result); } // Sudoku Extension Usage (Z3.LinqBinding.Sudoku) using (var ctx = new Z3Context()) { var theorem = from t in SudokuTheorem.Create(ctx) where t.Cell13 == 2 && t.Cell16 == 1 && t.Cell18 == 6 where t.Cell23 == 7 && t.Cell26 == 4 where t.Cell31 == 5 && t.Cell37 == 9 where t.Cell42 == 1 && t.Cell44 == 3 where t.Cell51 == 8 && t.Cell55 == 5 && t.Cell59 == 4 where t.Cell66 == 6 && t.Cell68 == 2 where t.Cell73 == 6 && t.Cell79 == 7 where t.Cell84 == 8 && t.Cell87 == 3 where t.Cell92 == 4 && t.Cell94 == 9 && t.Cell97 == 2 select t; var result = theorem.Solve(); Console.WriteLine(result); } // All samples using (var ctx = new Z3Context()) { ctx.Log = Console.Out; // see internal logging Print(from t in ctx.NewTheorem(new { x = default(bool) }) where t.x && !t.x select t); Print(from t in ctx.NewTheorem(new { x = default(bool), y = default(bool) }) where t.x ^ t.y select t); Print(from t in ctx.NewTheorem(new { x = default(int), y = default(int) }) where t.x < t.y + 1 where t.x > 2 select t); Print(from t in ctx.NewTheorem <Symbols <int, int> >() where t.X1 < t.X2 + 1 where t.X1 > 2 where t.X1 != t.X2 select t); Print(from t in ctx.NewTheorem <Symbols <int, int, int, int, int> >() where t.X1 - t.X2 >= 1 where t.X1 - t.X2 <= 3 where t.X1 == (2 * t.X3) + t.X5 where t.X3 == t.X5 where t.X2 == 6 * t.X4 select t); Print(from t in ctx.NewTheorem <Symbols <int, int> >() where Z3Methods.Distinct(t.X1, t.X2) select t); Print(from t in SudokuTheorem.Create(ctx) where t.Cell13 == 2 && t.Cell16 == 1 && t.Cell18 == 6 where t.Cell23 == 7 && t.Cell26 == 4 where t.Cell31 == 5 && t.Cell37 == 9 where t.Cell42 == 1 && t.Cell44 == 3 where t.Cell51 == 8 && t.Cell55 == 5 && t.Cell59 == 4 where t.Cell66 == 6 && t.Cell68 == 2 where t.Cell73 == 6 && t.Cell79 == 7 where t.Cell84 == 8 && t.Cell87 == 3 where t.Cell92 == 4 && t.Cell94 == 9 && t.Cell97 == 2 select t); } }
private static void Main(string[] args) { // Basic Usage using (var ctx = new Z3Context()) { ctx.Log = Console.Out; // see internal logging var theorem = from t in ctx.NewTheorem(new { x = default(bool), y = default(bool) }) where t.x ^ t.y select t; var result = theorem.Solve(); Console.WriteLine(result); } // Advanced Usage using (var ctx = new Z3Context()) { ctx.Log = Console.Out; // see internal logging var theorem = from t in ctx.NewTheorem <Symbols <int, int> >() where t.X1 < t.X2 + 1 where t.X1 > 2 where t.X1 != t.X2 select t; var result = theorem.Solve(); Console.WriteLine(result); } // Sudoku Extension Usage (Z3.LinqBinding.Sudoku) using (var ctx = new Z3Context()) { var theorem = from t in SudokuTheorem.Create(ctx) where t.Cell13 == 2 && t.Cell16 == 1 && t.Cell18 == 6 where t.Cell23 == 7 && t.Cell26 == 4 where t.Cell31 == 5 && t.Cell37 == 9 where t.Cell42 == 1 && t.Cell44 == 3 where t.Cell51 == 8 && t.Cell55 == 5 && t.Cell59 == 4 where t.Cell66 == 6 && t.Cell68 == 2 where t.Cell73 == 6 && t.Cell79 == 7 where t.Cell84 == 8 && t.Cell87 == 3 where t.Cell92 == 4 && t.Cell94 == 9 && t.Cell97 == 2 select t; var result = theorem.Solve(); Console.WriteLine(result); } // Sudoku Extension Usage (Z3.LinqBinding.Sudoku) using (var ctx = new Z3Context()) { var theorem = SudokuAsArray .Parse("9.2..54.31...63.255.84.7.6..263.9..1.57.1.29..9.67.53.24.53.6..7.52..3.4.8..4195.") // Very easy .CreateTheorem(ctx); var result = theorem.Solve(); Console.WriteLine(result); theorem = SudokuAsArray .Parse("..48...1767.9.....5.8.3...43..74.1...69...78...1.69..51...8.3.6.....6.9124...15..") // Easy .CreateTheorem(ctx); result = theorem.Solve(); Console.WriteLine(result); theorem = SudokuAsArray .Parse("..6.......8..542...4..9..7...79..3......8.4..6.....1..2.3.67981...5...4.478319562") // Medium .CreateTheorem(ctx); result = theorem.Solve(); Console.WriteLine(result); theorem = SudokuAsArray .Parse("....9.4.8.....2.7..1.7....32.4..156...........952..7.19....5.1..3.4.....1.2.7....") // Hard .CreateTheorem(ctx); result = theorem.Solve(); Console.WriteLine(result); } // Solving Canibals & Missionaires using (var ctx = new Z3Context()) { var can = new MissionariesAndCannibals() { NbMissionaries = 3, SizeBoat = 2, Length = 50 }; var startTime = stopwatch.Elapsed; var minimal = MissionariesAndCannibals.SearchMinimal(can); var endTime = stopwatch.Elapsed; Console.WriteLine("Minimal Solution to missionaries and cannibals through Binary search"); Console.WriteLine(minimal == null ? "none" : minimal.ToString()); Console.WriteLine($"Time to solve: {endTime - startTime}"); var theorem = can.Create(ctx); startTime = stopwatch.Elapsed; minimal = theorem.Optimize(Optimization.Minimize, objMnC => objMnC.Length); endTime = stopwatch.Elapsed; Console.WriteLine("Minimal Solution to missionaries and cannibals through Z3 optimization"); Console.WriteLine(minimal == null ? "none" : minimal.ToString()); Console.WriteLine($"Time to solve: {endTime - startTime}"); } // Testing simplification using (var ctx = new Z3Context()) { //ctx.Log = Console.Out; var can = new MissionariesAndCannibals() { NbMissionaries = 3, SizeBoat = 2, Length = 30 }; Console.WriteLine($"Non simplified version"); Console.WriteLine(); var theorem = can.Create(ctx); theorem.SimplifyLambdas = false; var startTime = stopwatch.Elapsed; var minimal = theorem.Optimize(Optimization.Minimize, objMnC => objMnC.Length); var endTime = stopwatch.Elapsed; Console.WriteLine("Minimal Solution to missionaries and cannibals non simplified through Z3 optimization"); Console.WriteLine($"Time to solve: {endTime - startTime}"); Console.WriteLine($"simplified version"); Console.WriteLine(); theorem.SimplifyLambdas = true; startTime = stopwatch.Elapsed; minimal = theorem.Optimize(Optimization.Minimize, objMnC => objMnC.Length); endTime = stopwatch.Elapsed; Console.WriteLine("Minimal Solution to missionaries and cannibals simplified through Z3 optimization"); Console.WriteLine($"Time to solve: {endTime - startTime}"); } //AllSamplesInSameContext(); Console.Read(); }
private static void AllSamplesInSameContext() { // All samples using (var ctx = new Z3Context()) { ctx.Log = Console.Out; // see internal logging Print(from t in ctx.NewTheorem(new { x = default(bool) }) where t.x && !t.x select t); Print(from t in ctx.NewTheorem(new { x = default(bool), y = default(bool) }) where t.x ^ t.y select t); Print(from t in ctx.NewTheorem(new { x = default(int), y = default(int) }) where t.x < t.y + 1 where t.x > 2 select t); Print(from t in ctx.NewTheorem <Symbols <int, int> >() where t.X1 < t.X2 + 1 where t.X1 > 2 where t.X1 != t.X2 select t); Print(from t in ctx.NewTheorem <Symbols <int, int, int, int, int> >() where t.X1 - t.X2 >= 1 where t.X1 - t.X2 <= 3 where t.X1 == (2 * t.X3) + t.X5 where t.X3 == t.X5 where t.X2 == 6 * t.X4 select t); Print(from t in ctx.NewTheorem <Symbols <int, int> >() where Z3Methods.Distinct(t.X1, t.X2) select t); Print(from t in SudokuTheorem.Create(ctx) where t.Cell13 == 2 && t.Cell16 == 1 && t.Cell18 == 6 where t.Cell23 == 7 && t.Cell26 == 4 where t.Cell31 == 5 && t.Cell37 == 9 where t.Cell42 == 1 && t.Cell44 == 3 where t.Cell51 == 8 && t.Cell55 == 5 && t.Cell59 == 4 where t.Cell66 == 6 && t.Cell68 == 2 where t.Cell73 == 6 && t.Cell79 == 7 where t.Cell84 == 8 && t.Cell87 == 3 where t.Cell92 == 4 && t.Cell94 == 9 && t.Cell97 == 2 select t); // Sudoku Extension Usage Z3.LinqBinding.Sudoku demonstrating array capabilities Print <SudokuAsArray>(SudokuAsArray .Parse("9.2..54.31...63.255.84.7.6..263.9..1.57.1.29..9.67.53.24.53.6..7.52..3.4.8..4195.") // Very easy .CreateTheorem(ctx)); Print <SudokuAsArray>(SudokuAsArray .Parse("..48...1767.9.....5.8.3...43..74.1...69...78...1.69..51...8.3.6.....6.9124...15..") // Easy .CreateTheorem(ctx)); Print <SudokuAsArray>(SudokuAsArray .Parse("..6.......8..542...4..9..7...79..3......8.4..6.....1..2.3.67981...5...4.478319562") // Medium .CreateTheorem(ctx)); Print <SudokuAsArray>(SudokuAsArray .Parse("....9.4.8.....2.7..1.7....32.4..156...........952..7.19....5.1..3.4.....1.2.7....") // Hard .CreateTheorem(ctx)); // Solving Canibals & Missionaires var can = new MissionariesAndCannibals() { NbMissionaries = 3, SizeBoat = 2, Length = 50 }; Print <MissionariesAndCannibals>(can.Create(ctx)); } }