├── .gitignore ├── Sudoku ├── data │ ├── puzzle1.txt │ ├── puzzle2.txt │ ├── puzzle3.txt │ ├── puzzle4.txt │ ├── puzzle5.txt │ └── puzzle6.txt ├── README.md ├── .vscode │ ├── c_cpp_properties.json │ └── launch.json ├── src │ ├── sudoku_utils.h │ └── sudoku_main.cpp └── Makefile ├── README.md └── toy ├── makefile └── src └── scip_toy.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Mac system files 2 | .DS_store 3 | bin 4 | obj 5 | *.lp -------------------------------------------------------------------------------- /Sudoku/data/puzzle1.txt: -------------------------------------------------------------------------------- 1 | .234..8..6....7......53.62...5......84.....36......1...52.96......1....7..8..521. -------------------------------------------------------------------------------- /Sudoku/data/puzzle2.txt: -------------------------------------------------------------------------------- 1 | 406080930030006070000030000000000000000019600008000025025800003309000000000005041 -------------------------------------------------------------------------------- /Sudoku/data/puzzle3.txt: -------------------------------------------------------------------------------- 1 | 000000000030012008070068020000009870120650400000000006003940000000200060400000031 -------------------------------------------------------------------------------- /Sudoku/data/puzzle4.txt: -------------------------------------------------------------------------------- 1 | ...2....9..4..7..17..4.13...6.1..2....29.51....8..4.9...37.9..21..8..5..8....3... -------------------------------------------------------------------------------- /Sudoku/data/puzzle5.txt: -------------------------------------------------------------------------------- 1 | 6..........45.....2.8.1.7....6..........................7...3.6..3..5.8......4... -------------------------------------------------------------------------------- /Sudoku/data/puzzle6.txt: -------------------------------------------------------------------------------- 1 | 390002400040060010000900702009423000000080000000591600107004000050010060008200045 -------------------------------------------------------------------------------- /Sudoku/README.md: -------------------------------------------------------------------------------- 1 | ### How To Use? 2 | 3 | 1) Change the location of the SCIP Directory in the makefile (line 2) 4 | 2) Compile the code using `make -s CXXFLAGS=-std=c++14` command 5 | 3) Run the code using for instance `/bin/SuDoKu data/puzzle5.txt` command 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A collection of SCIP examples in C++ to get started quickly. 2 | 3 | Some more detailed explanation on how these examples have been constructed: 4 | 5 | toy: https://www.cgudapati.com/integer-programming/2019/12/15/Getting-Started-With-SCIP-Optimization-Suite.html 6 | 7 | Sudoku: https://www.cgudapati.com/integer-programming/2020/08/19/SCIP-Tutorial-Solving-Sudoku.html 8 | -------------------------------------------------------------------------------- /Sudoku/.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Mac", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/Library/scip6/scip/", 8 | "/Library/scip6/scip/src" 9 | ], 10 | "defines": [], 11 | "macFrameworkPath": [], 12 | "compilerPath": "/usr/local/bin/gcc-9", 13 | "cStandard": "c11", 14 | "cppStandard": "gnu++14", 15 | "intelliSenseMode": "clang-x64" 16 | } 17 | ], 18 | "version": 4 19 | } -------------------------------------------------------------------------------- /Sudoku/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(lldb) Launch", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "enter program name, for example ${workspaceFolder}/a.out", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "lldb" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /Sudoku/src/sudoku_utils.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | //Here we create a simple namespace to hold all of the related suDoKu functions together. 8 | namespace sudoku 9 | { 10 | std::vector> get_sudoku_grid(std::string file_path) 11 | { 12 | //Just setting an 9x9 grid for storing the sudoku puzzle. 13 | std::vector> puzzle(9, std::vector(9)); 14 | 15 | //Let us read the puzzle into a stringstream 16 | std::ifstream infile(file_path); 17 | 18 | std::string puzzle_data; 19 | 20 | if (infile.is_open()) 21 | { 22 | std::getline(infile, puzzle_data); 23 | if (puzzle_data.length() != 81) //The puzzle should have 81 characters 24 | { 25 | std::cerr << "Please check the puzzle file for inconsistencies" 26 | << "\n"; 27 | exit(1); 28 | } 29 | } 30 | 31 | int idx = 0; //This variable will be used to access the numbers in the puzzle string 32 | 33 | for (int i = 0; i < 9; ++i) 34 | { 35 | for (int j = 0; j < 9; ++j) 36 | { 37 | if ((puzzle_data.substr(idx, 1) != ".") and (puzzle_data.substr(idx, 1) != "0")) // We will only convert the numeric charcater to an integer if it is not '.' or '0'. 38 | { 39 | puzzle[i][j] = std::stoi(puzzle_data.substr(idx, 1)); 40 | } 41 | else 42 | { 43 | puzzle[i][j] = -1; // If we are currently reading a '.' or '0' make it -1. 44 | } 45 | idx++; 46 | } 47 | } 48 | 49 | return puzzle; 50 | } 51 | 52 | void print_sudoku(const std::vector> &sudoku_puzzle) 53 | { 54 | std::cout << "+----------+-----------+-----------+" 55 | << "\n"; 56 | for (auto i = 0; i < 9; ++i) 57 | { 58 | std::cout << "|"; 59 | for (auto j = 0; j < 9; ++j) 60 | { 61 | if (sudoku_puzzle[i][j] > 0) 62 | { 63 | 64 | if (j == 2 or j == 5 or j == 8) 65 | { 66 | std::cout << sudoku_puzzle[i][j] << " | "; 67 | } 68 | else 69 | { 70 | std::cout << sudoku_puzzle[i][j] << " "; 71 | } 72 | } 73 | else 74 | { 75 | if (j == 2 or j == 5 or j == 8) 76 | { 77 | std::cout << "." 78 | << " | "; 79 | } 80 | else 81 | { 82 | std::cout << "." 83 | << " "; 84 | } 85 | } 86 | } 87 | std::cout << "\n"; 88 | 89 | if (i == 2 or i == 5 or i == 8) 90 | { 91 | std::cout << "+----------+-----------+-----------+" 92 | << "\n"; 93 | } 94 | } 95 | } 96 | } // namespace sudoku -------------------------------------------------------------------------------- /Sudoku/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SCIPDIR = /Library/scip7.0.1/scip 3 | 4 | 5 | #----------------------------------------------------------------------------- 6 | # include default project Makefile from SCIP (need to do this twice, once to 7 | # find the correct binary, then, after getting the correct flags from the 8 | # binary (which is necessary since the ZIMPL flags differ from the default 9 | # if compiled with the SCIP Optsuite instead of SCIP), we need to set the 10 | # compile flags, e.g., for the ZIMPL library, which is again done in make.project 11 | #----------------------------------------------------------------------------- 12 | include $(SCIPDIR)/make/make.project 13 | SCIPVERSION :=$(shell $(SCIPDIR)/bin/scip.$(BASE).$(LPS).$(TPI)$(EXEEXTENSION) -v | sed -e 's/$$/@/') 14 | override ARCH :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ARCH=\([^@]*\).*/\1/') 15 | override EXPRINT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* EXPRINT=\([^@]*\).*/\1/') 16 | override GAMS :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* GAMS=\([^@]*\).*/\1/') 17 | override GMP :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* GMP=\([^@]*\).*/\1/') 18 | override SYM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* SYM=\([^@]*\).*/\1/') 19 | override IPOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* IPOPT=\([^@]*\).*/\1/') 20 | override IPOPTOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* IPOPTOPT=\([^@]*\).*/\1/') 21 | override LPSCHECK :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* LPSCHECK=\([^@]*\).*/\1/') 22 | override LPSOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* LPSOPT=\([^@]*\).*/\1/') 23 | override NOBLKBUFMEM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBLKBUFMEM=\([^@]*\).*/\1/') 24 | override NOBLKMEM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBLKMEM=\([^@]*\).*/\1/') 25 | override NOBUFMEM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBUFMEM=\([^@]*\).*/\1/') 26 | override PARASCIP :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* PARASCIP=\([^@]*\).*/\1/') 27 | override READLINE :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* READLINE=\([^@]*\).*/\1/') 28 | override SANITIZE :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* SANITIZE=\([^@]*\).*/\1/') 29 | override ZIMPL :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZIMPL=\([^@]*\).*/\1/') 30 | override ZIMPLOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZIMPLOPT=\([^@]*\).*/\1/') 31 | override ZLIB :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZLIB=\([^@]*\).*/\1/') 32 | 33 | include $(SCIPDIR)/make/make.project 34 | 35 | MAINNAME = sudoku 36 | MAINOBJ = sudoku_main.o 37 | MAINSRC = $(addprefix $(SRCDIR)/,$(MAINOBJ:.o=.cpp)) 38 | MAIN = $(MAINNAME).$(BASE).$(LPS)$(EXEEXTENSION) 39 | MAINFILE = $(BINDIR)/$(MAIN) 40 | MAINSHORTLINK = $(BINDIR)/$(MAINNAME) 41 | MAINOBJFILES = $(addprefix $(OBJDIR)/,$(MAINOBJ)) 42 | 43 | 44 | .PHONY: all 45 | all: $(SCIPDIR) $(MAINFILE) $(MAINSHORTLINK) 46 | 47 | 48 | $(MAINSHORTLINK): $(MAINFILE) 49 | @rm -f $@ 50 | cd $(dir $@) && ln -s $(notdir $(MAINFILE)) $(notdir $@) 51 | 52 | $(OBJDIR): 53 | @-mkdir -p $(OBJDIR) 54 | 55 | $(BINDIR): 56 | @-mkdir -p $(BINDIR) 57 | 58 | .PHONY: clean 59 | clean: $(OBJDIR) 60 | ifneq ($(OBJDIR),) 61 | -rm -f $(OBJDIR)/*.o 62 | -rmdir $(OBJDIR) 63 | endif 64 | -rm -f $(MAINFILE) 65 | 66 | .PHONY: depend 67 | depend: $(SCIPDIR) 68 | $(SHELL) -ec '$(DCXX) $(FLAGS) $(DFLAGS) $(MAINSRC) \ 69 | | sed '\''s|^\([0-9A-Za-z\_]\{1,\}\)\.o *: *$(SRCDIR)/\([0-9A-Za-z\_]*\).cpp|$$\(OBJDIR\)/\2.o: $(SRCDIR)/\2.cpp|g'\'' \ 70 | >$(MAINDEP)' 71 | 72 | -include $(MAINDEP) 73 | 74 | $(MAINFILE): $(BINDIR) $(OBJDIR) $(SCIPLIBFILE) $(LPILIBFILE) $(NLPILIBFILE) $(MAINOBJFILES) 75 | @echo "-> linking $@" 76 | $(LINKCXX) $(MAINOBJFILES) $(LINKCXXSCIPALL) $(LDFLAGS) $(LINKCXX_o)$@ 77 | 78 | $(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(SRCDIR)/sudoku_utils.h 79 | @echo "-> compiling $@" 80 | $(CXX) $(FLAGS) $(OFLAGS) $(BINOFLAGS) $(CXXFLAGS) -c $< $(CXX_o)$@ 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /toy/makefile: -------------------------------------------------------------------------------- 1 | SCIPDIR = /Library/scip6/scip 2 | 3 | 4 | #----------------------------------------------------------------------------- 5 | # include default project Makefile from SCIP (need to do this twice, once to 6 | # find the correct binary, then, after getting the correct flags from the 7 | # binary (which is necessary since the ZIMPL flags differ from the default 8 | # if compiled with the SCIP Optsuite instead of SCIP), we need to set the 9 | # compile flags, e.g., for the ZIMPL library, which is again done in make.project 10 | #----------------------------------------------------------------------------- 11 | include $(SCIPDIR)/make/make.project 12 | SCIPVERSION :=$(shell $(SCIPDIR)/bin/scip.$(BASE).$(LPS).$(TPI)$(EXEEXTENSION) -v | sed -e 's/$$/@/') 13 | override ARCH :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ARCH=\([^@]*\).*/\1/') 14 | override EXPRINT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* EXPRINT=\([^@]*\).*/\1/') 15 | override GAMS :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* GAMS=\([^@]*\).*/\1/') 16 | override GMP :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* GMP=\([^@]*\).*/\1/') 17 | override SYM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* SYM=\([^@]*\).*/\1/') 18 | override IPOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* IPOPT=\([^@]*\).*/\1/') 19 | override IPOPTOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* IPOPTOPT=\([^@]*\).*/\1/') 20 | override LPSCHECK :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* LPSCHECK=\([^@]*\).*/\1/') 21 | override LPSOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* LPSOPT=\([^@]*\).*/\1/') 22 | override NOBLKBUFMEM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBLKBUFMEM=\([^@]*\).*/\1/') 23 | override NOBLKMEM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBLKMEM=\([^@]*\).*/\1/') 24 | override NOBUFMEM :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* NOBUFMEM=\([^@]*\).*/\1/') 25 | override PARASCIP :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* PARASCIP=\([^@]*\).*/\1/') 26 | override READLINE :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* READLINE=\([^@]*\).*/\1/') 27 | override SANITIZE :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* SANITIZE=\([^@]*\).*/\1/') 28 | override ZIMPL :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZIMPL=\([^@]*\).*/\1/') 29 | override ZIMPLOPT :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZIMPLOPT=\([^@]*\).*/\1/') 30 | override ZLIB :=$(shell echo "$(SCIPVERSION)" | sed -e 's/.* ZLIB=\([^@]*\).*/\1/') 31 | include $(SCIPDIR)/make/make.project 32 | 33 | #----------------------------------------------------------------------------- 34 | # Main Program 35 | #----------------------------------------------------------------------------- 36 | 37 | MAINNAME = scip_toy 38 | MAINOBJ = scip_toy.o 39 | MAINSRC = $(addprefix $(SRCDIR)/,$(MAINOBJ:.o=.cpp)) 40 | MAIN = $(MAINNAME).$(BASE).$(LPS)$(EXEEXTENSION) 41 | MAINFILE = $(BINDIR)/$(MAIN) 42 | MAINSHORTLINK = $(BINDIR)/$(MAINNAME) 43 | MAINOBJFILES = $(addprefix $(OBJDIR)/,$(MAINOBJ)) 44 | 45 | .PHONY: all 46 | all: $(SCIPDIR) $(MAINFILE) $(MAINSHORTLINK) 47 | 48 | .PHONY: scip 49 | scip: 50 | @$(MAKE) -C $(SCIPDIR) libs $^ 51 | 52 | $(MAINSHORTLINK): $(MAINFILE) 53 | @rm -f $@ 54 | cd $(dir $@) && ln -s $(notdir $(MAINFILE)) $(notdir $@) 55 | 56 | $(OBJDIR): 57 | @-mkdir -p $(OBJDIR) 58 | 59 | $(BINDIR): 60 | @-mkdir -p $(BINDIR) 61 | 62 | .PHONY: clean 63 | clean: $(OBJDIR) 64 | ifneq ($(OBJDIR),) 65 | -rm -f $(OBJDIR)/*.o 66 | -rmdir $(OBJDIR) 67 | endif 68 | -rm -f $(MAINFILE) 69 | 70 | .PHONY: run 71 | run: 72 | ./$(BINDIR)/$(MAINNAME) 73 | 74 | 75 | 76 | $(MAINFILE): $(BINDIR) $(OBJDIR) $(SCIPLIBFILE) $(LPILIBFILE) $(NLPILIBFILE) $(MAINOBJFILES) 77 | @echo "-> linking $@" 78 | $(LINKCXX) $(MAINOBJFILES) $(LINKCXXSCIPALL) $(LDFLAGS) $(LINKCXX_o)$@ 79 | 80 | $(OBJDIR)/%.o: $(SRCDIR)/%.cpp 81 | @echo "-> compiling $@" 82 | $(CXX) $(FLAGS) $(OFLAGS) $(BINOFLAGS) $(CXXFLAGS) -c $< $(CXX_o)$@ 83 | 84 | #---- EOF -------------------------------------------------------------------- -------------------------------------------------------------------------------- /toy/src/scip_toy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // scip_toy.cpp 3 | // SCIP_toyeg 4 | // 5 | // Created by Naga V Gudapati on 12/13/19. 6 | // Copyright © 2019 Naga V Gudapati. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | SCIP_RETCODE execmain(int argc, const char** argv) 14 | { 15 | SCIP* scip = nullptr; 16 | SCIP_CALL( SCIPcreate(&scip) ); //Creating the SCIP environment 17 | 18 | 19 | /* include default plugins */ 20 | SCIP_CALL( SCIPincludeDefaultPlugins(scip) ); 21 | 22 | //Creating the SCIP Problem. 23 | SCIP_CALL( SCIPcreateProbBasic(scip, "SCIP_toy_example")); 24 | 25 | SCIP_CALL(SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE)); 26 | 27 | 28 | SCIP_VAR* x1 = nullptr; 29 | 30 | SCIP_CALL( SCIPcreateVarBasic(scip, 31 | &x1, // returns new index 32 | "x1", // name 33 | 0.0, // lower bound 34 | SCIPinfinity(scip), // upper bound 35 | 3.0, // objective 36 | SCIP_VARTYPE_CONTINUOUS)); // variable type 37 | 38 | 39 | SCIP_CALL( SCIPaddVar(scip, x1) ); //Adding the first variable 40 | 41 | SCIP_VAR* x2 = nullptr;; 42 | 43 | SCIP_CALL( SCIPcreateVarBasic(scip, 44 | &x2, // returns new index 45 | "x2", // name 46 | 0.0, // lower bound 47 | SCIPinfinity(scip), // upper bound 48 | 2.0, // objective 49 | SCIP_VARTYPE_CONTINUOUS)); // variable type 50 | 51 | SCIP_CALL( SCIPaddVar(scip, x2) ); //Adding the second variable 52 | 53 | SCIP_CONS* cons1 = nullptr;; 54 | 55 | 56 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, // SCIP pointer 57 | &cons1, // pointer to SCIP constraint 58 | "cons1", // name of the constraint 59 | 0, // How many variables are you adding now 60 | nullptr, // an array of pointers to various variables 61 | nullptr, // an array of values of the coefficients of the corresponding vars 62 | -SCIPinfinity(scip), // LHS of the constraint 63 | 4)); // RHS of the constraint 64 | 65 | SCIP_CALL( SCIPaddCoefLinear(scip, cons1, x1, 1.0)); //Adding the variable x1 with A matrix coeffient of 1.0 66 | SCIP_CALL( SCIPaddCoefLinear(scip, cons1, x2, 1.0)); //Adding the variable x2 with A matrix coeffient of 1.0 67 | SCIP_CALL( SCIPaddCons(scip, cons1)); 68 | 69 | 70 | 71 | SCIP_CONS* cons2 = nullptr;; 72 | 73 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, 74 | &cons2, 75 | "cons2", 76 | 0, 77 | nullptr, 78 | nullptr, 79 | -SCIPinfinity(scip), 80 | 5)); 81 | 82 | SCIP_CALL( SCIPaddCoefLinear(scip, cons2, x1, 2.0)); 83 | SCIP_CALL( SCIPaddCoefLinear(scip, cons2, x2, 1.0)); 84 | SCIP_CALL( SCIPaddCons(scip, cons2)); 85 | 86 | 87 | 88 | SCIP_CONS* cons3 = nullptr;; 89 | 90 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, 91 | &cons3, 92 | "cons3", 93 | 0, 94 | nullptr, 95 | nullptr, 96 | -SCIPinfinity(scip), 97 | -2.0)); 98 | 99 | SCIP_CALL( SCIPaddCoefLinear(scip, cons3, x1, 1.0)); 100 | SCIP_CALL( SCIPaddCoefLinear(scip, cons3, x2, -4.0)); 101 | SCIP_CALL( SCIPaddCons(scip, cons3)); 102 | 103 | 104 | //Scip releasing all the constraints 105 | SCIP_CALL( SCIPreleaseCons(scip, &cons1) ); 106 | SCIP_CALL( SCIPreleaseCons(scip, &cons2) ); 107 | SCIP_CALL( SCIPreleaseCons(scip, &cons3) ); 108 | 109 | //Solving the problem 110 | SCIP_CALL( SCIPsolve(scip) ); 111 | 112 | SCIP_SOL* sol = nullptr; 113 | 114 | sol = SCIPgetBestSol(scip); 115 | 116 | std::cout << "x1: " << SCIPgetSolVal(scip, sol, x1) << " " << "x2: " << SCIPgetSolVal(scip, sol, x2) << "\n"; 117 | 118 | 119 | SCIP_CALL( (SCIPwriteOrigProblem(scip, "scip_toy.lp", nullptr, FALSE))); 120 | 121 | 122 | 123 | 124 | //Freeing the variables 125 | SCIP_CALL( SCIPreleaseVar(scip, &x1)); 126 | 127 | SCIP_CALL( SCIPreleaseVar(scip, &x2)); 128 | 129 | 130 | 131 | SCIP_CALL( SCIPfree(&scip)); 132 | 133 | 134 | return SCIP_OKAY; 135 | 136 | } 137 | 138 | 139 | int main(int argc, const char * argv[]) { 140 | 141 | return execmain(argc, argv) != SCIP_OKAY ? 1 : 0; 142 | 143 | } 144 | -------------------------------------------------------------------------------- /Sudoku/src/sudoku_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "sudoku_utils.h" 4 | #include 5 | #include 6 | 7 | int main(int args, char *argv[]) 8 | { 9 | if (args < 2) 10 | { 11 | std::cerr << "call " << argv[0] << " " << "\n"; 12 | exit(1); 13 | } 14 | 15 | std::string puzzle_file_path = argv[1]; 16 | 17 | auto puzzle = sudoku::get_sudoku_grid(puzzle_file_path); 18 | 19 | std::cout << "The unsolved Sudoku Puzzle is: " << "\n"; 20 | sudoku::print_sudoku(puzzle); 21 | 22 | //Setting up the SCIP environment 23 | 24 | SCIP *scip = nullptr; //Declaring the scip environment 25 | 26 | SCIP_CALL(SCIPcreate(&scip)); //Creating the SCIP environment 27 | 28 | /* include default plugins */ 29 | SCIP_CALL(SCIPincludeDefaultPlugins(scip)); 30 | 31 | //Creating the SCIP Problem. 32 | SCIP_CALL(SCIPcreateProbBasic(scip, "SUDOKU")); 33 | 34 | SCIP_CALL(SCIPsetObjsense(scip, SCIP_OBJSENSE_MINIMIZE)); //Does not matter for us as this is just a feasibility problem 35 | 36 | 37 | /* 38 | * To solve the puzzle using integer programming, we shall use this handy tutorial; 39 | * http://profs.sci.univr.it/~rrizzi/classes/PLS2015/sudoku/doc/497_Olszowy_Wiktor_Sudoku.pdf 40 | * prior knowledge of sudoku is presumed. 41 | */ 42 | 43 | /* 44 | * We have to define 9x9x9 variables. Let x_{ijk} where i = 1...9, j = 1...9 and k = 1..9 be those binary variables. 45 | * x_{ijk} is the the binary variable related to number k (1 or 2 or ... 9) in the ith row and jth column. 46 | * 47 | */ 48 | 49 | 50 | 51 | std::vector>> x_vars(9, std::vector>(9, std::vector(9))); 52 | 53 | std::ostringstream namebuf; 54 | 55 | for (int i = 0; i < 9; ++i) 56 | { 57 | for (int j = 0; j < 9; ++j) 58 | { 59 | for (int k = 0; k < 9; ++k) 60 | { 61 | SCIP_VAR *var = nullptr; 62 | namebuf.str(""); 63 | namebuf << "x[" << i << "," << j << "," << k << "]"; 64 | SCIP_CALL(SCIPcreateVarBasic(scip, // SCIP environment 65 | &var, // reference to the variable 66 | namebuf.str().c_str(), // name of the variable 67 | 0.0, // Lower bound of the variable 68 | 1.0, // upper bound of the variable 69 | 1.0, // Obj. coefficient. Doesn't really matter for this problem 70 | SCIP_VARTYPE_BINARY // Binary variable 71 | )); 72 | SCIP_CALL(SCIPaddVar(scip, var)); 73 | x_vars[i][j][k] = var; 74 | } 75 | } 76 | } 77 | 78 | // Let us create the constraints now. Since there is nothing advanced about our constraints, 79 | // we will just use the simple constraints given by SCIPcreateConsBasicLinear() 80 | 81 | 82 | 83 | std::vector column_constrs; //These constraints will model that fact that in each column, the numbers 1..9 should not repeat. 84 | 85 | for (int j = 0; j < 9; ++j) 86 | { 87 | for (int k = 0; k < 9; ++k) 88 | { 89 | SCIP_CONS *cons = nullptr; 90 | 91 | namebuf.str(""); 92 | namebuf << "col_" << j << "_" << k << "]"; 93 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, 94 | &cons, 95 | namebuf.str().c_str(), 96 | 0, 97 | nullptr, 98 | nullptr, 99 | 1.0, 100 | 1.0)); 101 | for (int i = 0; i < 9; ++i) // The constraint will look like x_1jk + x_2jk + x_3jk + ... + x_9jk = 1 for a given value of j and k 102 | { 103 | SCIP_CALL(SCIPaddCoefLinear(scip, cons, x_vars[i][j][k], 1.0)); 104 | } 105 | 106 | SCIP_CALL(SCIPaddCons(scip, cons)); 107 | column_constrs.push_back(cons); 108 | } 109 | } 110 | 111 | std::vector row_constrs; //These constraints will model that fact that in each row, the numbers 1..9 do not repeat. 112 | 113 | for (int i = 0; i < 9; ++i) 114 | { 115 | for (int k = 0; k < 9; ++k) 116 | { 117 | SCIP_CONS *cons = nullptr; 118 | 119 | namebuf.str(""); 120 | namebuf << "row_" << i << "_" << k << "]"; 121 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, 122 | &cons, 123 | namebuf.str().c_str(), 124 | 0, 125 | nullptr, 126 | nullptr, 127 | 1.0, 128 | 1.0)); 129 | for (int j = 0; j < 9; ++j) // The constraint will look like x_i1k + x_i2k + x_i3k + ... + x_i9k = 1 for a given value of i and k 130 | { 131 | SCIP_CALL(SCIPaddCoefLinear(scip, cons, x_vars[i][j][k], 1.0)); 132 | } 133 | 134 | SCIP_CALL(SCIPaddCons(scip, cons)); 135 | row_constrs.push_back(cons); 136 | } 137 | } 138 | 139 | //Subgrid constraints 140 | std::vector subgrid_constrs; // These constraints will model that each of the 3x3 subgrids will contain 1...9 without any repetition. 141 | 142 | for (int k = 0; k < 9; ++k) 143 | { 144 | for (int p = 0; p < 3; ++p) 145 | { 146 | for (int q = 0; q < 3; ++q) 147 | { 148 | SCIP_CONS *cons = nullptr; 149 | 150 | namebuf.str(""); 151 | namebuf << "subgrid_" << k << "_" << p << "_" << q << "]"; 152 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, 153 | &cons, 154 | namebuf.str().c_str(), 155 | 0, 156 | nullptr, 157 | nullptr, 158 | 1.0, 159 | 1.0)); 160 | for (int j = 3 * (p + 1) - 3; j < 3 * (p + 1); ++j) //since we are indexing from 0..8 be careful with the loop indices. 161 | { 162 | for (int i = 3 * (q + 1) - 3; i < 3 * (q + 1); ++i) 163 | { 164 | SCIP_CALL(SCIPaddCoefLinear(scip, cons, x_vars[i][j][k], 1.0)); 165 | } 166 | } 167 | SCIP_CALL(SCIPaddCons(scip, cons)); 168 | subgrid_constrs.push_back(cons); 169 | } 170 | } 171 | } 172 | 173 | //ensure that the complete puzzle grid is filled constraints 174 | std::vector fillgrid_constrs; //These constraints ensure that every position in the whole 9x9 grid is filled with one number. 175 | 176 | for (int i = 0; i < 9; ++i) 177 | { 178 | for (int j = 0; j < 9; ++j) 179 | { 180 | SCIP_CONS *cons = nullptr; 181 | 182 | namebuf.str(""); 183 | namebuf << "fillgrid_" << i << "_" << j << "]"; 184 | SCIP_CALL(SCIPcreateConsBasicLinear(scip, 185 | &cons, 186 | namebuf.str().c_str(), 187 | 0, 188 | nullptr, 189 | nullptr, 190 | 1.0, 191 | 1.0)); 192 | for (int k = 0; k < 9; ++k) 193 | { 194 | SCIP_CALL(SCIPaddCoefLinear(scip, cons, x_vars[i][j][k], 1.0)); 195 | } 196 | 197 | SCIP_CALL(SCIPaddCons(scip, cons)); 198 | fillgrid_constrs.push_back(cons); 199 | } 200 | } 201 | 202 | //We have to set assign the already given numbers to the corresponding variables and we use the SCIPfixVar() function 203 | 204 | SCIP_Bool infeasible; 205 | SCIP_Bool fixed; 206 | for (int i = 0; i < 9; ++i) 207 | { 208 | for (int j = 0; j < 9; ++j) 209 | { 210 | if (puzzle[i][j] > 0) 211 | { 212 | SCIP_CALL(SCIPfixVar(scip, x_vars[i][j][(puzzle[i][j]) - 1], 1.0, &infeasible, &fixed)); 213 | } 214 | } 215 | } 216 | 217 | SCIP_CALL(SCIPsetObjsense(scip, SCIP_OBJSENSE_MAXIMIZE)); 218 | 219 | // SCIP_CALL((SCIPwriteOrigProblem(scip, "scip_sudoku.lp", nullptr, FALSE))); 220 | 221 | SCIP_CALL(SCIPsetIntParam(scip, "display/verblevel", 0)); // We use SCIPsetIntParams to turn off the logging. 222 | 223 | SCIP_CALL(SCIPsolve(scip)); 224 | 225 | SCIP_STATUS soln_status = SCIPgetStatus(scip); // Some wrongly generated sudoku puzzles can be infeasible. So we use the solnstatus to display different types of output. 226 | 227 | if (soln_status == 11) // solution status of 11 indicates optimal solution was found. Hence we can print the final puzzle. 228 | { 229 | SCIP_SOL *sol; 230 | sol = SCIPgetBestSol(scip); 231 | 232 | for (int i = 0; i < 9; ++i) 233 | { 234 | for (int j = 0; j < 9; ++j) 235 | { 236 | for (int k = 0; k < 9; ++k) 237 | { 238 | if (SCIPgetSolVal(scip, sol, x_vars[i][j][k]) > 0) 239 | { 240 | puzzle[i][j] = k + 1; // We are using 0 based indices. so when we have to display the final puzzle, we should increment it by 1. 241 | } 242 | } 243 | } 244 | } 245 | std::cout << "The solved puzzle is: " << "\n"; 246 | sudoku::print_sudoku(puzzle); 247 | } 248 | else if( soln_status == 12) // solutions status of 12 indicates that the puzzle is infeasible. 249 | { 250 | std::cout << "Check the Input puzzle" << "\n"; 251 | } 252 | 253 | //Freeing the variables 254 | 255 | for (int i = 0; i < 9; ++i) 256 | { 257 | for (int j = 0; j < 9; ++j) 258 | { 259 | for (int k = 0; k < 9; ++k) 260 | { 261 | SCIP_CALL(SCIPreleaseVar(scip, &x_vars[i][j][k])); 262 | } 263 | } 264 | } 265 | x_vars.clear(); 266 | 267 | // Freeing the constraints 268 | 269 | for (auto &constr : column_constrs) 270 | { 271 | SCIP_CALL(SCIPreleaseCons(scip, &constr)); 272 | } 273 | column_constrs.clear(); 274 | 275 | for (auto &constr : row_constrs) 276 | { 277 | SCIP_CALL(SCIPreleaseCons(scip, &constr)); 278 | } 279 | row_constrs.clear(); 280 | 281 | for (auto &constr : subgrid_constrs) 282 | { 283 | SCIP_CALL(SCIPreleaseCons(scip, &constr)); 284 | } 285 | subgrid_constrs.clear(); 286 | 287 | for (auto &constr : fillgrid_constrs) 288 | { 289 | SCIP_CALL(SCIPreleaseCons(scip, &constr)); 290 | } 291 | fillgrid_constrs.clear(); 292 | 293 | //freeing scip 294 | 295 | SCIP_CALL(SCIPfree(&scip)); 296 | } 297 | --------------------------------------------------------------------------------