Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# Sudoku Examples

This section includes source code for all of the Gurobi sudoku examples. The same source code can be found in the `examples` directory of the Gurobi distribution.

    /* Copyright 2025, Gurobi Optimization, LLC */
    /*
      Sudoku example.

      The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
      of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
      No two grid cells in the same row, column, or 3x3 subgrid may take the
      same value.

      In the MIP formulation, binary variables x[i,j,v] indicate whether
      cell <i,j> takes value 'v'.  The constraints are as follows:
        1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
        2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
        3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
        4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)

      Input datasets for this example can be found in examples/data/sudoku*.
    */

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "gurobi_c.h"

    #define SUBDIM  3
    #define DIM    (SUBDIM*SUBDIM)

    int
    main(int   argc,
         char *argv[])
    {
      FILE     *fp    = NULL;
      GRBenv   *env   = NULL;
      GRBmodel *model = NULL;
      int       board[DIM][DIM];
      char      inputline[100];
      int       ind[DIM];
      double    val[DIM];
      double    lb[DIM*DIM*DIM];
      char      vtype[DIM*DIM*DIM];
      char     *names[DIM*DIM*DIM];
      char      namestorage[10*DIM*DIM*DIM];
      char     *cursor;
      int       optimstatus;
      double    objval;
      int       i, j, v, ig, jg, count;
      int       error = 0;

      if (argc < 2) {
        fprintf(stderr, "Usage: sudoku_c datafile\n");
        exit(1);
      }

      fp = fopen(argv[1], "r");
      if (fp == NULL) {
        fprintf(stderr, "Error: unable to open input file %s\n", argv[1]);
        exit(1);
      }

      for (i = 0; i < DIM; i++) {
        fgets(inputline, 100, fp);
        if (strlen(inputline) < 9) {
          fprintf(stderr, "Error: not enough board positions specified\n");
          exit(1);
        }
        for (j = 0; j < DIM; j++) {
          board[i][j] = (int) inputline[j] - (int) '1';
          if (board[i][j] < 0 || board[i][j] >= DIM)
            board[i][j] = -1;
        }
      }

      /* Create an empty model */

      cursor = namestorage;
      for (i = 0; i < DIM; i++) {
        for (j = 0; j < DIM; j++) {
          for (v = 0; v < DIM; v++) {
            if (board[i][j] == v)
              lb[i*DIM*DIM+j*DIM+v] = 1;
            else
              lb[i*DIM*DIM+j*DIM+v] = 0;
            vtype[i*DIM*DIM+j*DIM+v] = GRB_BINARY;

            names[i*DIM*DIM+j*DIM+v] = cursor;
            sprintf(names[i*DIM*DIM+j*DIM+v], "x[%d,%d,%d]", i, j, v+1);
            cursor += strlen(names[i*DIM*DIM+j*DIM+v]) + 1;
          }
        }
      }

      /* Create environment */

      error = GRBloadenv(&env, "sudoku.log");
      if (error) goto QUIT;

      /* Create new model */

      error = GRBnewmodel(env, &model, "sudoku", DIM*DIM*DIM, NULL, lb, NULL,
                          vtype, names);
      if (error) goto QUIT;

      /* Each cell gets a value */

      for (i = 0; i < DIM; i++) {
        for (j = 0; j < DIM; j++) {
          for (v = 0; v < DIM; v++) {
            ind[v] = i*DIM*DIM + j*DIM + v;
            val[v] = 1.0;
          }

          error = GRBaddconstr(model, DIM, ind, val, GRB_EQUAL, 1.0, NULL);
          if (error) goto QUIT;
        }
      }

      /* Each value must appear once in each row */

      for (v = 0; v < DIM; v++) {
        for (j = 0; j < DIM; j++) {
          for (i = 0; i < DIM; i++) {
            ind[i] = i*DIM*DIM + j*DIM + v;
            val[i] = 1.0;
          }

          error = GRBaddconstr(model, DIM, ind, val, GRB_EQUAL, 1.0, NULL);
          if (error) goto QUIT;
        }
      }

      /* Each value must appear once in each column */

      for (v = 0; v < DIM; v++) {
        for (i = 0; i < DIM; i++) {
          for (j = 0; j < DIM; j++) {
            ind[j] = i*DIM*DIM + j*DIM + v;
            val[j] = 1.0;
          }

          error = GRBaddconstr(model, DIM, ind, val, GRB_EQUAL, 1.0, NULL);
          if (error) goto QUIT;
        }
      }

      /* Each value must appear once in each subgrid */

      for (v = 0; v < DIM; v++) {
        for (ig = 0; ig < SUBDIM; ig++) {
          for (jg = 0; jg < SUBDIM; jg++) {
            count = 0;
            for (i = ig*SUBDIM; i < (ig+1)*SUBDIM; i++) {
              for (j = jg*SUBDIM; j < (jg+1)*SUBDIM; j++) {
                ind[count] = i*DIM*DIM + j*DIM + v;
                val[count] = 1.0;
                count++;
              }
            }

            error = GRBaddconstr(model, DIM, ind, val, GRB_EQUAL, 1.0, NULL);
            if (error) goto QUIT;
          }
        }
      }

      /* Optimize model */

      error = GRBoptimize(model);
      if (error) goto QUIT;

      /* Write model to 'sudoku.lp' */

      error = GRBwrite(model, "sudoku.lp");
      if (error) goto QUIT;

      /* Capture solution information */

      error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimstatus);
      if (error) goto QUIT;

      error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &objval);
      if (error) goto QUIT;

      printf("\nOptimization complete\n");
      if (optimstatus == GRB_OPTIMAL)
        printf("Optimal objective: %.4e\n", objval);
      else if (optimstatus == GRB_INF_OR_UNBD)
        printf("Model is infeasible or unbounded\n");
      else
        printf("Optimization was stopped early\n");
      printf("\n");

    QUIT:

      /* Error reporting */

      if (error) {
        printf("ERROR: %s\n", GRBgeterrormsg(env));
        exit(1);
      }

      fclose(fp);

      /* Free model */

      GRBfreemodel(model);

      /* Free environment */

      GRBfreeenv(env);

      return 0;
    }

    /* Copyright 2025, Gurobi Optimization, LLC */
    /*
      Sudoku example.

      The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
      of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
      No two grid cells in the same row, column, or 3x3 subgrid may take the
      same value.

      In the MIP formulation, binary variables x[i,j,v] indicate whether
      cell <i,j> takes value 'v'.  The constraints are as follows:
        1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
        2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
        3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
        4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)

      Input datasets for this example can be found in examples/data/sudoku*.
    */

    #include "gurobi_c++.h"
    #include <sstream>
    using namespace std;

    #define sd 3
    #define n (sd*sd)

    string itos(int i) {stringstream s; s << i; return s.str(); }

    int
    main(int   argc,
         char *argv[])
    {
      try {
        GRBEnv env = GRBEnv();
        GRBModel model = GRBModel(env);

        GRBVar vars[n][n][n];
        int i, j, v;

        // Create 3-D array of model variables

        for (i = 0; i < n; i++) {
          for (j = 0; j < n; j++) {
            for (v = 0; v < n; v++) {
              string s = "G_" + itos(i) + "_" + itos(j) + "_" + itos(v);
              vars[i][j][v] = model.addVar(0.0, 1.0, 0.0, GRB_BINARY, s);
            }
          }
        }

        // Add constraints

        // Each cell must take one value

        for (i = 0; i < n; i++) {
          for (j = 0; j < n; j++) {
            GRBLinExpr expr = 0;
            for (v = 0; v < n; v++)
              expr += vars[i][j][v];
            string s = "V_" + itos(i) + "_" + itos(j);
            model.addConstr(expr, GRB_EQUAL, 1.0, s);
          }
        }

        // Each value appears once per row

        for (i = 0; i < n; i++) {
          for (v = 0; v < n; v++) {
            GRBLinExpr expr = 0;
            for (j = 0; j < n; j++)
              expr += vars[i][j][v];
            string s = "R_" + itos(i) + "_" + itos(v);
            model.addConstr(expr == 1.0, s);
          }
        }

        // Each value appears once per column

        for (j = 0; j < n; j++) {
          for (v = 0; v < n; v++) {
            GRBLinExpr expr = 0;
            for (i = 0; i < n; i++)
              expr += vars[i][j][v];
            string s = "C_" + itos(j) + "_" + itos(v);
            model.addConstr(expr == 1.0, s);
          }
        }

        // Each value appears once per sub-grid

        for (v = 0; v < n; v++) {
          for (int i0 = 0; i0 < sd; i0++) {
            for (int j0 = 0; j0 < sd; j0++) {
              GRBLinExpr expr = 0;
              for (int i1 = 0; i1 < sd; i1++) {
                for (int j1 = 0; j1 < sd; j1++) {
                  expr += vars[i0*sd+i1][j0*sd+j1][v];
                }
              }

              string s = "Sub_" + itos(v) + "_" + itos(i0) + "_" + itos(j0);
              model.addConstr(expr == 1.0, s);
            }
          }
        }

        // Fix variables associated with pre-specified cells

        char input[10];
        for (i = 0; i < n; i++) {
          cin >> input;
          for (j = 0; j < n; j++) {
            int val = (int) input[j] - 48 - 1; // 0-based

            if (val >= 0)
              vars[i][j][val].set(GRB_DoubleAttr_LB, 1.0);
          }
        }

        // Optimize model

        model.optimize();

        // Write model to file

        model.write("sudoku.lp");

        cout << endl;
        for (i = 0; i < n; i++) {
          for (j = 0; j < n; j++) {
            for (v = 0; v < n; v++) {
              if (vars[i][j][v].get(GRB_DoubleAttr_X) > 0.5)
                cout << v+1;
            }
          }
          cout << endl;
        }
        cout << endl;
      } catch(GRBException e) {
        cout << "Error code = " << e.getErrorCode() << endl;
        cout << e.getMessage() << endl;
      } catch (...) {
        cout << "Error during optimization" << endl;
      }

      return 0;
    }

    /* Copyright 2025, Gurobi Optimization, LLC */

    /*
      Sudoku example.

      The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
      of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
      No two grid cells in the same row, column, or 3x3 subgrid may take the
      same value.

      In the MIP formulation, binary variables x[i,j,v] indicate whether
      cell <i,j> takes value 'v'.  The constraints are as follows:
        1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
        2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
        3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
        4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)

      Input datasets for this example can be found in examples/data/sudoku*.
    */

    using System;
    using System.IO;
    using Gurobi;

    class sudoku_cs
    {
      static void Main(string[] args)
      {
        int n = 9;
        int s = 3;

        if (args.Length < 1) {
          Console.Out.WriteLine("Usage: sudoku_cs filename");
          return;
        }

        try {
          GRBEnv env = new GRBEnv();
          GRBModel model = new GRBModel(env);

          // Create 3-D array of model variables

          GRBVar[,,] vars = new GRBVar[n,n,n];

          for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
              for (int v = 0; v < n; v++) {
                string st = "G_" + i.ToString() + "_" + j.ToString()
                                 + "_" + v.ToString();
                vars[i,j,v] = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, st);
              }
            }
          }

          // Add constraints

          GRBLinExpr expr;

          // Each cell must take one value

          for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
              expr = 0.0;
              for (int v = 0; v < n; v++)
                expr.AddTerm(1.0, vars[i,j,v]);
              string st = "V_" + i.ToString() + "_" + j.ToString();
              model.AddConstr(expr == 1.0, st);
            }
          }

          // Each value appears once per row

          for (int i = 0; i < n; i++) {
            for (int v = 0; v < n; v++) {
              expr = 0.0;
              for (int j = 0; j < n; j++)
                expr.AddTerm(1.0, vars[i,j,v]);
              string st = "R_" + i.ToString() + "_" + v.ToString();
              model.AddConstr(expr == 1.0, st);
            }
          }

          // Each value appears once per column

          for (int j = 0; j < n; j++) {
            for (int v = 0; v < n; v++) {
              expr = 0.0;
              for (int i = 0; i < n; i++)
                expr.AddTerm(1.0, vars[i,j,v]);
              string st = "C_" + j.ToString() + "_" + v.ToString();
              model.AddConstr(expr == 1.0, st);
            }
          }

          // Each value appears once per sub-grid

          for (int v = 0; v < n; v++) {
            for (int i0 = 0; i0 < s; i0++) {
              for (int j0 = 0; j0 < s; j0++) {
                expr = 0.0;
                for (int i1 = 0; i1 < s; i1++) {
                  for (int j1 = 0; j1 < s; j1++) {
                    expr.AddTerm(1.0, vars[i0*s+i1,j0*s+j1,v]);
                  }
                }
                string st = "Sub_" + v.ToString() + "_" + i0.ToString()
                                   + "_" + j0.ToString();
                model.AddConstr(expr == 1.0, st);
              }
            }
          }

          // Fix variables associated with pre-specified cells

          StreamReader sr = File.OpenText(args[0]);

          for (int i = 0; i < n; i++) {
            string input = sr.ReadLine();
            for (int j = 0; j < n; j++) {
              int val = (int) input[j] - 48 - 1; // 0-based

              if (val >= 0)
                vars[i,j,val].LB = 1.0;
            }
          }

          // Optimize model

          model.Optimize();

          // Write model to file
          model.Write("sudoku.lp");

          double[,,] x = model.Get(GRB.DoubleAttr.X, vars);

          Console.WriteLine();
          for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
              for (int v = 0; v < n; v++) {
                if (x[i,j,v] > 0.5) {
                  Console.Write(v+1);
                }
              }
            }
            Console.WriteLine();
          }

          // Dispose of model and env
          model.Dispose();
          env.Dispose();

        } catch (GRBException e) {
          Console.WriteLine("Error code: " + e.ErrorCode + ". " + e.Message);
        }
      }
    }

    /* Copyright 2025, Gurobi Optimization, LLC */
    /*
      Sudoku example.

      The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
      of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
      No two grid cells in the same row, column, or 3x3 subgrid may take the
      same value.

      In the MIP formulation, binary variables x[i,j,v] indicate whether
      cell <i,j> takes value 'v'.  The constraints are as follows:
        1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
        2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
        3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
        4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)

      Input datasets for this example can be found in examples/data/sudoku*.
    */

    import com.gurobi.gurobi.*;
    import java.io.*;

    public class Sudoku {
      public static void main(String[] args) {
        int n = 9;
        int s = 3;

        if (args.length < 1) {
          System.out.println("Usage: java Sudoku filename");
          System.exit(1);
        }

        try {
          GRBEnv env = new GRBEnv();
          GRBModel model = new GRBModel(env);

          // Create 3-D array of model variables

          GRBVar[][][] vars = new GRBVar[n][n][n];

          for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
              for (int v = 0; v < n; v++) {
                String st = "G_" + String.valueOf(i) + "_" + String.valueOf(j)
                                 + "_" + String.valueOf(v);
                vars[i][j][v] = model.addVar(0.0, 1.0, 0.0, GRB.BINARY, st);
              }
            }
          }

          // Add constraints

          GRBLinExpr expr;

          // Each cell must take one value

          for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
              expr = new GRBLinExpr();
              expr.addTerms(null, vars[i][j]);
              String st = "V_" + String.valueOf(i) + "_" + String.valueOf(j);
              model.addConstr(expr, GRB.EQUAL, 1.0, st);
            }
          }

          // Each value appears once per row

          for (int i = 0; i < n; i++) {
            for (int v = 0; v < n; v++) {
              expr = new GRBLinExpr();
              for (int j = 0; j < n; j++)
                expr.addTerm(1.0, vars[i][j][v]);
              String st = "R_" + String.valueOf(i) + "_" + String.valueOf(v);
              model.addConstr(expr, GRB.EQUAL, 1.0, st);
            }
          }

          // Each value appears once per column

          for (int j = 0; j < n; j++) {
            for (int v = 0; v < n; v++) {
              expr = new GRBLinExpr();
              for (int i = 0; i < n; i++)
                expr.addTerm(1.0, vars[i][j][v]);
              String st = "C_" + String.valueOf(j) + "_" + String.valueOf(v);
              model.addConstr(expr, GRB.EQUAL, 1.0, st);
            }
          }

          // Each value appears once per sub-grid

          for (int v = 0; v < n; v++) {
            for (int i0 = 0; i0 < s; i0++) {
              for (int j0 = 0; j0 < s; j0++) {
                expr = new GRBLinExpr();
                for (int i1 = 0; i1 < s; i1++) {
                  for (int j1 = 0; j1 < s; j1++) {
                    expr.addTerm(1.0, vars[i0*s+i1][j0*s+j1][v]);
                  }
                }
                String st = "Sub_" + String.valueOf(v) + "_" + String.valueOf(i0)
                                   + "_" + String.valueOf(j0);
                model.addConstr(expr, GRB.EQUAL, 1.0, st);
              }
            }
          }

          // Fix variables associated with pre-specified cells

          File file = new File(args[0]);

          try (BufferedReader br = new BufferedReader(new FileReader(file))) {
            for (int i = 0; i < n; i++) {
                String line = br.readLine();
                for (int j = 0; j < n; j++) {
                  char c = line.charAt(j);
                  if (Character.isDigit(c)) {
                    vars[i][j][Character.getNumericValue(c)-1].set(GRB.DoubleAttr.LB, 1.0);
                  }
                }
            }
          }

          // Optimize model

          model.optimize();

          // Write model to file
          model.write("sudoku.lp");

          double[][][] x = model.get(GRB.DoubleAttr.X, vars);

          System.out.println();
          for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
              for (int v = 0; v < n; v++) {
                if (x[i][j][v] > 0.5) {
                  System.out.print(v+1);
                }
              }
            }
            System.out.println();
          }

          // Dispose of model and environment
          model.dispose();
          env.dispose();

        } catch (GRBException e) {
          System.out.println("Error code: " + e.getErrorCode() + ". " +
              e.getMessage());
        } catch (IOException e) {
          System.out.println("IO Error");
        }
      }
    }

    function sudoku(filename)

    %  Copyright 2025, Gurobi Optimization, LLC */
    %
    % Sudoku example.
    %
    % The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
    % of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
    % No two grid cells in the same row, column, or 3x3 subgrid may take the
    % same value.
    %
    % In the MIP formulation, binary variables x[i,j,v] indicate whether
    % cell <i,j> takes value 'v'.  The constraints are as follows:
    %   1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
    %   2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
    %   3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
    %   4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)
    %
    % Input datasets for this example can be found in examples/data/sudoku*.
    %

    SUBDIM = 3;
    DIM    = SUBDIM*SUBDIM;

    fileID = fopen(filename);
    if fileID == -1
        fprintf('Could not read file %s, quit\n', filename);
        return;
    end

    board = repmat(-1, DIM, DIM);
    for i = 1:DIM
        s = fgets(fileID, 100);
        if length(s) <= DIM
            fprintf('Error: not enough board positions specified, quit\n');
            return;
        end
        for j = 1:DIM
            if s(j) ~= '.'
                board(i, j) = str2double(s(j));
                if board(i,j) < 1 || board(i,j) > DIM
                    fprintf('Error: Unexpected character in Input line %d, quit\n', i);
                    return;
                end
            end
        end
    end

    % Map X(i,j,k) into an index variable in the model
    nVars = DIM * DIM * DIM;

    % Build model
    model.vtype    = repmat('B', nVars, 1);
    model.lb       = zeros(nVars, 1);
    model.ub       = ones(nVars, 1);

    for i = 1:DIM
        for j = 1:DIM
            for v = 1:DIM
                var = (i-1)*DIM*DIM + (j-1)*DIM + v;
                model.varnames{var} = sprintf('x[%d,%d,%d]', i, j, v);
            end
        end
    end

    % Create constraints:
    nRows = 4 * DIM * DIM;
    model.A = sparse(nRows, nVars);
    model.rhs = ones(nRows, 1);
    model.sense = repmat('=', nRows, 1);

    Row = 1;

    % Each cell gets a value */
    for i = 1:DIM
        for j = 1:DIM
            for v = 1:DIM
                if board(i,j) == v
                    model.lb((i-1)*DIM*DIM + (j-1)*DIM + v) = 1;
                end
                model.A(Row, (i-1)*DIM*DIM + (j-1)*DIM + v) = 1;
            end
            Row = Row + 1;
        end
    end

    % Each value must appear once in each row
    for v = 1:DIM
        for j = 1:DIM
            for i = 1:DIM
                model.A(Row, (i-1)*DIM*DIM + (j-1)*DIM + v) = 1;
            end
            Row = Row + 1;
        end
    end

    % Each value must appear once in each column
    for v = 1:DIM
        for i = 1:DIM
            for j = 1:DIM
                model.A(Row, (i-1)*DIM*DIM + (j-1)*DIM + v) = 1;
            end
            Row = Row + 1;
        end
    end

    % Each value must appear once in each subgrid
    for v = 1:DIM
        for ig = 0: SUBDIM-1
            for jg = 0: SUBDIM-1
                for i = ig*SUBDIM+1:(ig+1)*SUBDIM
                    for j = jg*SUBDIM+1:(jg+1)*SUBDIM
                        model.A(Row, (i-1)*DIM*DIM + (j-1)*DIM + v) = 1;
                    end
                end
                Row = Row + 1;
            end
        end
    end

    % Save model
    gurobi_write(model, 'sudoku_m.lp');

    % Optimize model
    params.logfile = 'sudoku_m.log';
    result = gurobi(model, params);

    if strcmp(result.status, 'OPTIMAL')
        fprintf('Solution:\n');
        for i = 1:DIM
            for j = 1:DIM
                for v = 1:DIM
                    var = (i-1)*DIM*DIM + (j-1)*DIM + v;
                    if result.x(var) > 0.99
                        fprintf('%d', v);
                    end
                end
            end
            fprintf('\n');
        end
    else
        fprintf('Problem was infeasible\n')
    end

    #!/usr/bin/env python3

    # Copyright 2025, Gurobi Optimization, LLC

    # Sudoku example.

    # The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
    # of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
    # No two grid cells in the same row, column, or 3x3 subgrid may take the
    # same value.
    #
    # In the MIP formulation, binary variables x[i,j,v] indicate whether
    # cell <i,j> takes value 'v'.  The constraints are as follows:
    #   1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
    #   2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
    #   3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
    #   4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)
    #
    # Input datasets for this example can be found in examples/data/sudoku*.

    import sys
    import math
    import gurobipy as gp
    from gurobipy import GRB

    if len(sys.argv) < 2:
        print("Usage: sudoku.py filename")
        sys.exit(0)

    f = open(sys.argv[1])

    grid = f.read().split()

    n = len(grid[0])
    s = int(math.sqrt(n))

    # Create our 3-D array of model variables

    model = gp.Model("sudoku")

    vars = model.addVars(n, n, n, vtype=GRB.BINARY, name="G")

    # Fix variables associated with cells whose values are pre-specified

    for i in range(n):
        for j in range(n):
            if grid[i][j] != ".":
                v = int(grid[i][j]) - 1
                vars[i, j, v].LB = 1

    # Each cell must take one value

    model.addConstrs(
        (vars.sum(i, j, "*") == 1 for i in range(n) for j in range(n)), name="V"
    )

    # Each value appears once per row

    model.addConstrs(
        (vars.sum(i, "*", v) == 1 for i in range(n) for v in range(n)), name="R"
    )

    # Each value appears once per column

    model.addConstrs(
        (vars.sum("*", j, v) == 1 for j in range(n) for v in range(n)), name="C"
    )

    # Each value appears once per subgrid

    model.addConstrs(
        (
            gp.quicksum(
                vars[i, j, v]
                for i in range(i0 * s, (i0 + 1) * s)
                for j in range(j0 * s, (j0 + 1) * s)
            )
            == 1
            for v in range(n)
            for i0 in range(s)
            for j0 in range(s)
        ),
        name="Sub",
    )

    model.optimize()

    model.write("sudoku.lp")

    print("")
    print("Solution:")
    print("")

    # Retrieve optimization result

    solution = model.getAttr("X", vars)

    for i in range(n):
        sol = ""
        for j in range(n):
            for v in range(n):
                if solution[i, j, v] > 0.5:
                    sol += str(v + 1)
        print(sol)

    #  Copyright 2025, Gurobi Optimization, LLC */
    #
    # Sudoku example.
    #
    # The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
    # of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
    # No two grid cells in the same row, column, or 3x3 subgrid may take the
    # same value.
    #
    # In the MIP formulation, binary variables x[i,j,v] indicate whether
    # cell <i,j> takes value 'v'.  The constraints are as follows:
    #   1. Each cell must take exactly one value (sum_v x[i,j,v] = 1)
    #   2. Each value is used exactly once per row (sum_i x[i,j,v] = 1)
    #   3. Each value is used exactly once per column (sum_j x[i,j,v] = 1)
    #   4. Each value is used exactly once per 3x3 subgrid (sum_grid x[i,j,v] = 1)
    #
    # Input datasets for this example can be found in examples/data/sudoku*.
    #

    library(Matrix)
    library(gurobi)

    args <- commandArgs(trailingOnly = TRUE)
    if (length(args) < 1) {
      stop('Usage: Rscript sudoku.R filename\n')
    }

    # Read input file
    conn <- file(args[1], open='r')
    if(!isOpen(conn)) {
      cat('Could not read file',args[1],'\n')
      stop('Stop now\n')
    }
    linn <- readLines(conn)
    close(conn)

    # Ensure that all lines have the same length as the number of lines, and
    # that the character set is the correct one.
    # Load fixed positions in board
    Dim    <- length(linn)
    board  <- matrix(0, Dim, Dim, byrow = TRUE)
    if (Dim != 9) {
      cat('Input file',args[1],'has',Dim,'lines instead of 9\n')
      stop('Stop now\n')
    }
    for (i in 1:Dim) {
      line <- strsplit(linn[[i]],split='')[[1]]
      if (length(line) != Dim) {
        cat('Input line',i,'has',length(line),'characters, expected',Dim,'\n')
        stop('Stop now\n')
      }
      for (j in 1:Dim) {
        if (line[[j]] != '.') {
          k <- as.numeric(line[[j]])
          if (k < 1 || k > Dim) {
            cat('Unexpected character in Input line',i,'character',j,'\n')
            stop('Stop now\n')
          } else {
            board[i,j] = k
          }
        }
      }
    }

    # Map X[i,j,k] into an index variable in the model
    nVars  <- Dim * Dim * Dim
    varIdx <- function(i,j,k) {i + (j-1) * Dim + (k-1) * Dim * Dim}

    cat('Dataset grid:',Dim,'x',Dim,'\n')

    # Set up parameters
    params <- list()
    params$logfile <- 'sudoku.log'

    # Build model
    model            <- list()
    model$modelname  <- 'sudoku'
    model$modelsense <- 'min'

    # Create variable names, types, and bounds
    model$vtype    <- 'B'
    model$lb       <- rep(0,  nVars)
    model$ub       <- rep(1,  nVars)
    model$varnames <- rep('', nVars)
    for (i in 1:Dim) {
      for (j in 1:Dim) {
        for (k in 1:Dim) {
          if (board[i,j] == k) model$lb[varIdx(i,j,k)] = 1
          model$varnames[varIdx(i,j,k)] = paste0('X',i,j,k)
        }
      }
    }

    # Create (empty) constraints:
    model$A           <- spMatrix(0,nVars)
    model$rhs         <- c()
    model$sense       <- c()
    model$constrnames <- c()

    # Each cell gets a value:
    for (i in 1:Dim) {
      for (j in 1:Dim) {
        B <- spMatrix(1, nVars,
                i = rep(1,Dim),
                j = varIdx(i,j,1:Dim),
                x = rep(1,Dim))
        model$A           <- rbind(model$A, B)
        model$rhs         <- c(model$rhs, 1)
        model$sense       <- c(model$sense, '=')
        model$constrnames <- c(model$constrnames, paste0('OneValInCell',i,j))
      }
    }

    # Each value must appear once in each column
    for (i in 1:Dim) {
      for (k in 1:Dim) {
        B <- spMatrix(1, nVars,
                i = rep(1,Dim),
                j = varIdx(i,1:Dim,k),
                x = rep(1,Dim))
        model$A           <- rbind(model$A, B)
        model$rhs         <- c(model$rhs, 1)
        model$sense       <- c(model$sense, '=')
        model$constrnames <- c(model$constrnames, paste0('OnceValueInRow',i,k))
      }
    }

    #Each value must appear once in each row
    for (j in 1:Dim) {
      for (k in 1:Dim) {
        B <- spMatrix(1, nVars,
                i = rep(1,Dim),
                j = varIdx(1:Dim,j,k),
                x = rep(1,Dim))
        model$A           <- rbind(model$A, B)
        model$rhs         <- c(model$rhs, 1)
        model$sense       <- c(model$sense, '=')
        model$constrnames <- c(model$constrnames, paste0('OnceValueInColumn',j,k))
      }
    }

    # Each value must appear once in each subgrid
    SubDim <- 3
    for (k in 1:Dim) {
      for (g1 in 1:SubDim) {
        for (g2 in 1:SubDim) {
          B <- spMatrix(1, nVars,
                  i = rep(1,Dim),
                  j = c(varIdx(1+(g1-1)*SubDim,(g2-1)*SubDim + 1:SubDim, k),
                        varIdx(2+(g1-1)*SubDim,(g2-1)*SubDim + 1:SubDim, k),
                        varIdx(3+(g1-1)*SubDim,(g2-1)*SubDim + 1:SubDim, k)),
                  x = rep(1,Dim))
          model$A           <- rbind(model$A, B)
          model$rhs         <- c(model$rhs, 1)
          model$sense       <- c(model$sense, '=')
          model$constrnames <- c(model$constrnames,
                                 paste0('OnceValueInSubGrid',g1,g2,k))
        }
      }
    }

    # Save model
    gurobi_write(model, 'sudoku.lp', params)

    # Optimize model
    result <- gurobi(model, params =  params)

    if (result$status == 'OPTIMAL') {
      cat('Solution:\n')
      cat('----------------------------------\n')
      for (i in 1:Dim) {
        for (j in 1:Dim) {
          if (j %% SubDim == 1) cat('| ')
          for (k in 1:Dim) {
            if (result$x[varIdx(i,j,k)] > 0.99) {
              cat(k,' ')
            }
          }
        }
        cat('|\n')
        if (i %% SubDim == 0) cat('----------------------------------\n')
      }
    } else {
      cat('Problem was infeasible\n')
    }

    # Clear space
    rm(result, model, board, linn, params)

    ' Copyright 2025, Gurobi Optimization, LLC
    '
    ' Sudoku example.
    '
    ' The Sudoku board is a 9x9 grid, which is further divided into a 3x3 grid
    ' of 3x3 grids.  Each cell in the grid must take a value from 0 to 9.
    ' No two grid cells in the same row, column, or 3x3 subgrid may take the
    ' same value.

    ' In the MIP formulation, binary variables x(i,j,v) indicate whether
    ' cell <i,j> takes value 'v'.  The constraints are as follows:
    '   1. Each cell must take exactly one value (sum_v x(i,j,v) = 1)
    '   2. Each value is used exactly once per row (sum_i x(i,j,v) = 1)
    '   3. Each value is used exactly once per column (sum_j x(i,j,v) = 1)
    '   4. Each value is used exactly once per 3x3 subgrid (sum_grid x(i,j,v) = 1)
    '
    ' Input datasets for this example can be found in examples/data/sudoku*.

    Imports System
    Imports System.IO
    Imports Gurobi

    Class sudoku_vb
        Shared Sub Main(ByVal args as String())
            Dim n As Integer = 9
            Dim s As Integer = 3

            If args.Length < 1 Then
                Console.WriteLine("Usage: sudoku_vb filename")
                Return
            End If

            Try
                Dim env As New GRBEnv()
                Dim model As New GRBModel(env)

                ' Create 3-D array of model variables

                Dim vars As GRBVar(,,) = New GRBVar(n - 1, n - 1, n - 1) {}

                For i As Integer = 0 To n - 1
                    For j As Integer = 0 To n - 1
                        For v As Integer = 0 To n - 1
                            Dim st As String = "G_" & i & "_" & j & "_" & v
                            vars(i, j, v) = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, st)
                        Next
                    Next
                Next

                ' Add constraints

                Dim expr As GRBLinExpr

                ' Each cell must take one value

                For i As Integer = 0 To n - 1
                    For j As Integer = 0 To n - 1
                        expr = 0
                        For v As Integer = 0 To n - 1
                            expr.AddTerm(1.0, vars(i, j, v))
                        Next
                        Dim st As String = "V_" & i & "_" & j
                        model.AddConstr(expr = 1, st)
                    Next
                Next

                ' Each value appears once per row

                For i As Integer = 0 To n - 1
                    For v As Integer = 0 To n - 1
                        expr = 0
                        For j As Integer = 0 To n - 1
                            expr.AddTerm(1.0, vars(i, j, v))
                        Next
                        Dim st As String = "R_" & i & "_" & v
                        model.AddConstr(expr = 1, st)
                    Next
                Next

                ' Each value appears once per column

                For j As Integer = 0 To n - 1
                    For v As Integer = 0 To n - 1
                        expr = 0
                        For i As Integer = 0 To n - 1
                            expr.AddTerm(1.0, vars(i, j, v))
                        Next
                        Dim st As String = "C_" & j & "_" & v
                        model.AddConstr(expr = 1, st)
                    Next
                Next

                ' Each value appears once per sub-grid

                For v As Integer = 0 To n - 1
                    For i0 As Integer = 0 To s - 1
                        For j0 As Integer = 0 To s - 1
                            expr = 0
                            For i1 As Integer = 0 To s - 1
                                For j1 As Integer = 0 To s - 1
                                    expr.AddTerm(1.0, vars(i0 * s + i1, j0 * s + j1, v))
                                Next
                            Next
                            Dim st As String = "Sub_" & v & "_" & i0 & "_" & j0
                            model.AddConstr(expr = 1, st)
                        Next
                    Next
                Next

                ' Fix variables associated with pre-specified cells

                Dim sr As StreamReader = File.OpenText(args(0))

                For i As Integer = 0 To n - 1
                    Dim input As String = sr.ReadLine()
                    For j As Integer = 0 To n - 1
                        Dim val As Integer = Microsoft.VisualBasic.Asc(input(j)) - 48 - 1
                        ' 0-based
                        If val >= 0 Then
                            vars(i, j, val).LB = 1.0
                        End If
                    Next
                Next

                ' Optimize model

                model.Optimize()

                ' Write model to file
                model.Write("sudoku.lp")

                Dim x As Double(,,) = model.Get(GRB.DoubleAttr.X, vars)

                Console.WriteLine()
                For i As Integer = 0 To n - 1
                    For j As Integer = 0 To n - 1
                        For v As Integer = 0 To n - 1
                            If x(i, j, v) > 0.5 Then
                                Console.Write(v + 1)
                            End If
                        Next
                    Next
                    Console.WriteLine()
                Next

                ' Dispose of model and env
                model.Dispose()
                env.Dispose()

            Catch e As GRBException
                Console.WriteLine("Error code: " & e.ErrorCode & ". " & e.Message)
            End Try
        End Sub
    End Class

Help and Feedback

Press `/` or click to search this documentation | Gurobi website | Gurobi community forum
Go to other Gurobi documentation | Gurobi download | Contact support