├── .gitignore ├── LICENSE ├── README.md ├── docs ├── _config.yml ├── cplex_lecture.pdf ├── index.md └── javadoc │ ├── DirectedGraph.html │ ├── DirectedGraphArc.html │ ├── Item.html │ ├── Main.html │ ├── Model.html │ ├── allclasses-frame.html │ ├── allclasses-noframe.html │ ├── class-use │ ├── DirectedGraph.html │ ├── DirectedGraphArc.html │ ├── Item.html │ ├── Main.html │ └── Model.html │ ├── constant-values.html │ ├── deprecated-list.html │ ├── help-doc.html │ ├── index-files │ ├── index-1.html │ ├── index-10.html │ ├── index-11.html │ ├── index-2.html │ ├── index-3.html │ ├── index-4.html │ ├── index-5.html │ ├── index-6.html │ ├── index-7.html │ ├── index-8.html │ └── index-9.html │ ├── index.html │ ├── overview-tree.html │ ├── package-frame.html │ ├── package-list │ ├── package-summary.html │ ├── package-tree.html │ ├── package-use.html │ ├── script.js │ └── stylesheet.css ├── instance.txt └── src ├── basic ├── DirectedGraph.java ├── DirectedGraphArc.java ├── Item.java ├── Main.java └── Model.java └── colgen ├── Instance.java ├── Main.java ├── MasterModel.java ├── Pattern.java ├── PricingModel.java └── Solution.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Paul Bouman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java and CPLEX example project: Precendence Constrained Knapsack Problem (basic package) 2 | This repository contains example code for a small Java Project that utilizes the [IBM ILOG CPLEX library](https://www.ibm.com/academic/topic/data-science) (*on that webpage you can access it under 'Software'*) 3 | to solve instances of the Precendence Constrained Knapsack Problem. This code is available in the `basic` package and folder of this repository. 4 | 5 | The Precendence Constrained Knapsack Problem is a variant of the regular Knapsack Problems where we have items *I*, where for each item *i* we have a profit *pi* and a weight *wi*. 6 | Furthermore, there is a capacity*b* and a directed graph *G = (I,A)* defined on the items. The objective is to select a set of items *S ⊆ I*, such that the sum of*pi* over *i ∈ S* is maximized, 7 | while the sum of *wi* over *i ∈ S* is smaller than or equal to *b*. Additionally, an item *i* can only be in *S* if all items *j* for which *A* contains an arc *(i,j)* are also in *S*. 8 | 9 | The code for the basic example consists of the following files: 10 | * `DirectedGraph.java` contains a general purpose data structure for directed graphs. It provides methods to add nodes and arcs, and allows us to attach arbitrary data types to the nodes and arcs. 11 | * `DirectedGraphArc.java` models the arcs that are created by the graph. These arcs contain the origin node of an arc, the destination node of an arc and the data associated with the arc. 12 | * `Item.java` models a knapsack item, without its precendence constraints (these are modelled in the project using a DirectedGraph object). 13 | * `Model.java` manages a CPLEX integer linear programming model, converting a directed graph with a precendence constrained knapsack problem and a capacity to a CPLEX model that can be solved. 14 | * `Main.java` is used to read in an instance of the problem from a text file, convert it to a directed graph, and call the `Model` class to solve the instance. 15 | 16 | More detailed documentation of these classes can be found in the [Javadocs of this project](https://pcbouman-eur.github.io/JavaCplexExample/javadoc/). 17 | 18 | For a general explanation of using CPLEX from Java the repository contains some [lecture slides](https://pcbouman-eur.github.io/JavaCplexExample/cplex_lecture.pdf). 19 | There is also a [series of four YouTube videos](https://www.youtube.com/watch?v=C4YDrVT3fcg&list=PLrX1UIgv0C_4V5Xx6IIWj0U8i-4JN6F1g) in which this project is implemented. 20 | 21 | # Java and CPLEX column generation project: Cutting Stock (colgen package) 22 | A second part of the example code covers column generation. This example is self contained, and implements a solution approach for the [Cutting Stock Problem](https://en.wikipedia.org/wiki/Cutting_stock_problem). 23 | 24 | The cutting stock problem consists of a number of orders of items *i ∈ I*, each with a unique size *si* and a demand *di*, as well as the capacity *C* of a single unit of base stock. 25 | The objective of the cutting stock problem is to select cutting patterns that specify how many items of the given sizes are cut from a unit of base stock, such that no more items are cut than the capacity of the base stock allowed. 26 | The patterns must be selected such that the demand *di* of each item is covered, while units of base stock that are required to cut the items is minimized. Note that a cutting pattern can be applied more than once. 27 | 28 | A classic approach for this problem is column generation, where we have a master problem that has decision variables to decide how many times each cutting pattern must be applied. As there are exponentially many cutting patterns, 29 | the master problem is initialized with a limited set of cutting patterns. Dual information from the master problem is then provided to a pricing problem, that is basically a knapsack problem that is used to generate new cutting patterns 30 | with positive reduced costs. These cutting patterns are added to the master problem, and this is resolved. This process is repeated iteratively as long as new cutting patterns with positive reduced costs are found. Finally, using the generated columns, the master problem is convereted to an integer programming problem and solved to find a heuristic solution. 31 | 32 | The code for the column generation example consists of the following classes: 33 | * `Instance.java` is used to model an instance of the cutting stock problem. It also contains a static method that can be used to generate a random instance. 34 | * `Main.java` contains a main method that generates random instances and solves them using the column generation approach. 35 | * `MasterModel.java` contains an implementation of the master problem and provides methods to solve the LP-relaxation and generate columns as long as new columns with negative reduced costs are found, as well as a method that solves an integer program with the columns generated while solving the LP-relaxation. 36 | * `Pattern.java` is used to model a cutting pattern, i.e. how to cut a single piece of stock into multiple items. 37 | * `PricingModel.java` implements an optimization model for the pricing problem. The objective can be updated based on the current duals of the master problem, and solving it gives a pattern with maximal reduced costs. Note that adding a pattern to the master problem only has effect if the reduced costs are in fact positive. 38 | * `Solution.java` represents a solution to a particular instance of the problem. The solution consists of utilized patterns, and how often each pattern must be applied to a piece of stock. 39 | 40 | Currently, all documentation of this example is only provided within the source code itself. In future updates to this repository, the Javadoc documentation may be added to the Github pages website. 41 | 42 | # Using CPLEX 43 | 44 | ## Obtaining CPLEX 45 | 46 | For this example to work, you need to have a working version of the CPLEX Java Library `cplex.jar` and the native library. The native libary is called `cplexYYYY.dll` on Windows, `libcplexYYYY.jnilib` on MacOS and `libcplexYYYY.so` on Linux, where `YYYY` is replaced by the version of your CPLEX library (e.g. 1263). 47 | 48 | Students who do not have these files can obtain the full [IBM ILOG CPLEX Optimization Studio](https://www.ibm.com/academic/topic/data-science) from IBM for free using a student account (*on that webpage you can access it under 'Software'*). 49 | 50 | After installing the IBM ILOG CPLEX Optimization Studio, you can find the .jar file in `cplex/lib` relative to the installation folder of the software. The native library can be found in `cplex/bin/x64_win64` on Windows installations, and similar locations on MacOS or Linux. 51 | 52 | ## Adding CPLEX to an Eclipse Project 53 | 54 | If you only need CPLEX, the easiest way to include it in an Eclipse project is to just add it is a library to the project. You can take the following steps to do this: 55 | 56 | 1. Create a directory `lib` in the root of your project and copy `cplex.jar` and the native library file there. 57 | 1. Go to the project properties, which can be access by right clicking on your project folder or via the Project menu in the menu bar. 58 | 3. Go to the Java Build Path option and select the `Libraries` tab. 59 | 4. Press `Add JARs` and select the `cplex.jar` file from the lib folder. For projects configured for Java versions up to 8, there is only a classpath to which the library will be automatically added. If you have a Java 9+ project, you need to take care it is added to the classpath (not the module path) and make sure your project has no `module-info.java` file (delete it if you created it). 60 | 5. Click on the `>` symbol in front of `cplex.jar`, select `Native Library Location` and click `Edit`. Click `Workspace` and select the `lib` folder that contains the native library. 61 | 62 | There is a [YouTube video](https://youtu.be/C4YDrVT3fcg) that shows these steps. 63 | 64 | ## Adding CPLEX via Maven 65 | 66 | If you have the full IBM ILOG CPLEX Optimization Studio installed, you can also add CPLEX as a [Maven](https://maven.apache.org/) dependency. 67 | 68 | ``` 69 | 70 | cplex 71 | cplex 72 | YY.Y.Y 73 | system 74 | ${env.CPLEX_STUDIO_DIRYYYY}/cplex/lib/cplex.jar 75 | 76 | ``` 77 | 78 | Note that you have to replace the Y's with the proper CPLEX version. For CPLEX 12.6.3, the snippet would be: 79 | 80 | ``` 81 | 82 | cplex 83 | cplex 84 | 12.6.3 85 | system 86 | ${env.CPLEX_STUDIO_DIR1263}/cplex/lib/cplex.jar 87 | 88 | ``` 89 | This approach assumes that a system environment variable `CPLEX_STUDIO_DIRYYYY` exists and that the CPLEX 90 | binaries are on the system path. For Windows installations of full ILOG CPLEX Optimization Studio this is 91 | the case and this step is sufficient. I am currently unaware if this works out-of-the-box on MacOS and 92 | Linux as well. 93 | 94 | ## Further Reading 95 | 96 | It is highly recommended to have a look at the [Java CPLEX Reference Documentation](https://www.ibm.com/support/knowledgecenter/SSSA5P_12.8.0/ilog.odms.cplex.help/refjavacplex/html/index.html) to discover what methods are available for a `IloCplex` modelling object. Be sure to have a look at [the documentation of the](https://www.ibm.com/support/knowledgecenter/SSSA5P_12.8.0/ilog.odms.cplex.help/refjavacplex/html/ilog/cplex/IloCplexModeler.html) `IloCplexModeler` class, which is a superclass of the `IloCplex` class you typically use to build a model in Java. In particular, the `addEq()`, `addLe()` and `addGe()` are important for the modelling of constraints, the `addMaximize()` and `addMinimize()` methodes are important for the modelling of the objective, and `sum()` and `prod()` are important for building mathematical expressions in CPLEX. It is also recommended to review [the documentation of](https://www.ibm.com/support/knowledgecenter/SSSA5P_12.8.0/ilog.odms.cplex.help/refjavacplex/html/ilog/cplex/IloCplex.html) the `IloCplex` class, in particular the `solve()`, `getValue()`, `getObjValue()`, `exportModel()` and `setOut()` methods are important. Furthermore, you can finetune the advanced settings of CPLEX the `setParam()` methods if you desire. IBM provides a [list of available parameters](https://www.ibm.com/support/knowledgecenter/SSSA5P_12.8.0/ilog.odms.cplex.help/CPLEX/Parameters/topics/introListAlpha.html). 97 | 98 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /docs/cplex_lecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pcbouman-eur/JavaCplexExample/40c83f6cd2de6b83e34c1e75faaaaacc5ed86636/docs/cplex_lecture.pdf -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Java and CPLEX example project: Precendence Constrained Knapsack Problem 3 | layout: post 4 | --- 5 | 6 | 7 | ## Java and CPLEX example project: Precendence Constrained Knapsack Problem 8 | 9 | This is a project page for a small example project that showcases how to use CPLEX from Java. It solves the Precedence Constrained Knapsack Problem, but is a useful example if you intend to implement other optimization problems that involve (directed) graphs. 10 | 11 | ## Useful links 12 | * IBM offers free versions of the IBM ILOG CPLEX Optimization Studio. You can got to [https://www.ibm.com/academic/topic/data-science](https://www.ibm.com/academic/topic/data-science) and create an IBM account with your EUR e-mail. You land on a general site "Data Science". If you scroll down there is a tab "Software". Click on "Software" and then under ILOG CPLEX Optimization Studio on Download. Your browser may suppress a pop-up, so make sure you allow the IBM website to show popups. In the pop-up, I advise to choose HTTP and select the CPLEX version appropriate for you operating system. 13 | * View the [GitHub repository](https://github.com/pcbouman-eur/JavaCplexExample) which has a more in-depth explanation. This also contains a more advanced column generation example, but these examples are separate. 14 | * You can look at the code [the code](https://github.com/pcbouman-eur/JavaCplexExample/tree/master/src) of this project, as well as an [example instance file](https://github.com/pcbouman-eur/JavaCplexExample/blob/master/instance.txt). You can [download a zip file](https://github.com/pcbouman-eur/JavaCplexExample/archive/master.zip) with the latest files. 15 | * There are [lecture slides](./cplex_lecture.pdf) with some background information and the most important ideas of this example project. 16 | * There is a [series of four YouTube videos](https://www.youtube.com/watch?v=C4YDrVT3fcg&list=PLrX1UIgv0C_4V5Xx6IIWj0U8i-4JN6F1g) in which this project is implemented. 17 | * You can view the [Javadoc documentation](./javadoc) of this example project. 18 | 19 | -------------------------------------------------------------------------------- /docs/javadoc/Item.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Item 7 | 8 | 9 | 10 | 11 | 12 | 28 | 31 | 32 |
33 | 34 | 35 |
Skip navigation links
36 | 37 | 38 | 39 | 48 |
49 | 91 | 92 | 93 |
94 |

Class Item

95 |
96 |
97 | 105 |
106 | 119 |
120 |
121 | 183 |
184 |
185 | 262 |
263 |
264 | 265 | 266 |
267 | 268 | 269 |
Skip navigation links
270 | 271 | 272 | 273 | 282 |
283 | 325 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /docs/javadoc/allclasses-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Classes 7 | 8 | 9 | 10 | 11 | 12 |

All Classes

13 |
14 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/javadoc/allclasses-noframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | All Classes 7 | 8 | 9 | 10 | 11 | 12 |

All Classes

13 |
14 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/javadoc/class-use/DirectedGraph.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uses of Class DirectedGraph 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Uses of Class
DirectedGraph

73 |
74 |
75 | 115 |
116 | 117 |
118 | 119 | 120 |
Skip navigation links
121 | 122 | 123 | 124 | 133 |
134 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /docs/javadoc/class-use/DirectedGraphArc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uses of Class DirectedGraphArc 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Uses of Class
DirectedGraphArc

73 |
74 |
75 | 113 |
114 | 115 |
116 | 117 | 118 |
Skip navigation links
119 | 120 | 121 | 122 | 131 |
132 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /docs/javadoc/class-use/Item.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uses of Class Item 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Uses of Class
Item

73 |
74 |
75 | 138 |
139 | 140 |
141 | 142 | 143 |
Skip navigation links
144 | 145 | 146 | 147 | 156 |
157 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /docs/javadoc/class-use/Main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uses of Class Main 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Uses of Class
Main

73 |
74 |
No usage of Main
75 | 76 |
77 | 78 | 79 |
Skip navigation links
80 | 81 | 82 | 83 | 92 |
93 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/javadoc/class-use/Model.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uses of Class Model 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Uses of Class
Model

73 |
74 |
No usage of Model
75 | 76 |
77 | 78 | 79 |
Skip navigation links
80 | 81 | 82 | 83 | 92 |
93 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/javadoc/constant-values.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Constant Field Values 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Constant Field Values

73 |

Contents

74 |
75 | 76 |
77 | 78 | 79 |
Skip navigation links
80 | 81 | 82 | 83 | 92 |
93 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/javadoc/deprecated-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Deprecated List 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Deprecated API

73 |

Contents

74 |
75 | 76 |
77 | 78 | 79 |
Skip navigation links
80 | 81 | 82 | 83 | 92 |
93 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/javadoc/help-doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | API Help 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

How This API Document Is Organized

73 |
This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.
74 |
75 |
76 | 175 | This help file applies to API documentation generated using the standard doclet.
176 | 177 |
178 | 179 | 180 |
Skip navigation links
181 | 182 | 183 | 184 | 193 |
194 | 221 | 222 | 223 | 224 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | A-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

A

75 |
76 |
addArc(V, V, A) - Method in class DirectedGraph
77 |
78 |
Adds an arc to this graph.
79 |
80 |
addNode(V) - Method in class DirectedGraph
81 |
82 |
Add a new node to this graph
83 |
84 |
85 | A C D E G H I M R S T 
86 | 87 |
88 | 89 | 90 |
Skip navigation links
91 | 92 | 93 | 94 | 103 |
104 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | S-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

S

75 |
76 |
setItem(Item, boolean) - Method in class Model
77 |
78 |
Disable an item in the model (fix it to 0) or enable it (either 0 or 1)
79 |
80 |
solve() - Method in class Model
81 |
82 |
Solve the Mathematical Programming Model
83 |
84 |
85 | A C D E G H I M R S T 
86 | 87 |
88 | 89 | 90 |
Skip navigation links
91 | 92 | 93 | 94 | 103 |
104 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-11.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | T-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

T

75 |
76 |
toString() - Method in class DirectedGraph
77 |
 
78 |
toString() - Method in class DirectedGraphArc
79 |
 
80 |
toString() - Method in class Item
81 |
 
82 |
83 | A C D E G H I M R S T 
84 | 85 |
86 | 87 | 88 |
Skip navigation links
89 | 90 | 91 | 92 | 101 |
102 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | C-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

C

75 |
76 |
cleanup() - Method in class Model
77 |
78 |
Cleans up the CPLEX model in order to free up some memory.
79 |
80 |
81 | A C D E G H I M R S T 
82 | 83 |
84 | 85 | 86 |
Skip navigation links
87 | 88 | 89 | 90 | 99 |
100 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | D-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

D

75 |
76 |
DirectedGraph<V,A> - Class in <Unnamed>
77 |
78 |
Simple class that can be used to model directed graphs, where 79 | arbitrary types of data are associated with the nodes and arcs 80 | of the graph.
81 |
82 |
DirectedGraph() - Constructor for class DirectedGraph
83 |
84 |
Creates an empty graph with no nodes or arcs.
85 |
86 |
DirectedGraphArc<V,A> - Class in <Unnamed>
87 |
88 |
Class that models arcs in the directed arcs.
89 |
90 |
DirectedGraphArc(V, V, A) - Constructor for class DirectedGraphArc
91 |
92 |
Construct an arc of the graph
93 |
94 |
95 | A C D E G H I M R S T 
96 | 97 |
98 | 99 | 100 |
Skip navigation links
101 | 102 | 103 | 104 | 113 |
114 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | E-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

E

75 |
76 |
equals(Object) - Method in class DirectedGraph
77 |
 
78 |
equals(Object) - Method in class DirectedGraphArc
79 |
 
80 |
81 | A C D E G H I M R S T 
82 | 83 |
84 | 85 | 86 |
Skip navigation links
87 | 88 | 89 | 90 | 99 |
100 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | G-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

G

75 |
76 |
getArcs() - Method in class DirectedGraph
77 |
78 |
Gives a list of all arcs currently in the graph
79 |
80 |
getData() - Method in class DirectedGraphArc
81 |
82 |
Used to retrieve the data associated with this arc
83 |
84 |
getFrom() - Method in class DirectedGraphArc
85 |
86 |
Used to retrieve the origin of this arc
87 |
88 |
getInArcs(V) - Method in class DirectedGraph
89 |
90 |
Gives all the arcs that enter a particular node in the graph.
91 |
92 |
getInDegree(V) - Method in class DirectedGraph
93 |
94 |
Gives the in-degree of a node in the graph.
95 |
96 |
getNodes() - Method in class DirectedGraph
97 |
98 |
Gives a list of all nodes currently in the graph
99 |
100 |
getNumberOfArcs() - Method in class DirectedGraph
101 |
102 |
The total number of arcs in this graph
103 |
104 |
getNumberOfNodes() - Method in class DirectedGraph
105 |
106 |
The total number of nodes in this graph
107 |
108 |
getOutArcs(V) - Method in class DirectedGraph
109 |
110 |
Gives all the arcs that leave a particular node in the graph.
111 |
112 |
getOutDegree(V) - Method in class DirectedGraph
113 |
114 |
Gives the out-degree of a node in the graph
115 |
116 |
getProfit() - Method in class Item
117 |
118 |
The profit of the current item.
119 |
120 |
getSolution() - Method in class Model
121 |
122 |
Create a list of the items for which the decision variables 123 | are one in the current solution of the mathematical program.
124 |
125 |
getTo() - Method in class DirectedGraphArc
126 |
127 |
Used to retrieve the destination of this arc
128 |
129 |
getWeight() - Method in class Item
130 |
131 |
The weight of the current item.
132 |
133 |
134 | A C D E G H I M R S T 
135 | 136 |
137 | 138 | 139 |
Skip navigation links
140 | 141 | 142 | 143 | 152 |
153 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | H-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

H

75 |
76 |
hashCode() - Method in class DirectedGraph
77 |
 
78 |
hashCode() - Method in class DirectedGraphArc
79 |
 
80 |
81 | A C D E G H I M R S T 
82 | 83 |
84 | 85 | 86 |
Skip navigation links
87 | 88 | 89 | 90 | 99 |
100 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | I-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

I

75 |
76 |
isFeasible() - Method in class Model
77 |
78 |
Checks whether the current solution to the model is feasible
79 |
80 |
Item - Class in <Unnamed>
81 |
82 |
Class that models a knapsack item with a profit and a weight
83 |
84 |
Item(int, int) - Constructor for class Item
85 |
86 |
Default constructor for a knapsack item
87 |
88 |
89 | A C D E G H I M R S T 
90 | 91 |
92 | 93 | 94 |
Skip navigation links
95 | 96 | 97 | 98 | 107 |
108 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | M-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

M

75 |
76 |
Main - Class in <Unnamed>
77 |
78 |
Main class for the Java/CPLEX example
79 |
80 |
Main() - Constructor for class Main
81 |
 
82 |
main(String[]) - Static method in class Main
83 |
 
84 |
Model - Class in <Unnamed>
85 |
86 |
Model class that converts a directed graph representing a 87 | precedence constrained knapsack problem into a mathematical programming 88 | model managed by CPLEX.
89 |
90 |
Model(DirectedGraph<Item, String>, int) - Constructor for class Model
91 |
92 |
Constructor that takes a directed graph with the items and precedence constraints
93 |
94 |
95 | A C D E G H I M R S T 
96 | 97 |
98 | 99 | 100 |
Skip navigation links
101 | 102 | 103 | 104 | 113 |
114 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /docs/javadoc/index-files/index-9.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | R-Index 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
A C D E G H I M R S T  72 | 73 | 74 |

R

75 |
76 |
read(File) - Static method in class Main
77 |
78 |
Reads a Precedence Constrained Knapsack Problem as a directed graph from a file
79 |
80 |
81 | A C D E G H I M R S T 
82 | 83 |
84 | 85 | 86 |
Skip navigation links
87 | 88 | 89 | 90 | 99 |
100 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/javadoc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Generated Documentation (Untitled) 7 | 60 | 61 | 62 | 63 | 64 | 65 | <noscript> 66 | <div>JavaScript is disabled on your browser.</div> 67 | </noscript> 68 | <h2>Frame Alert</h2> 69 | <p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="DirectedGraph.html">Non-frame version</a>.</p> 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /docs/javadoc/overview-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Class Hierarchy 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Hierarchy For All Packages

73 |
74 |
75 |

Class Hierarchy

76 | 87 |
88 | 89 |
90 | 91 | 92 |
Skip navigation links
93 | 94 | 95 | 96 | 105 |
106 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /docs/javadoc/package-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <Unnamed> 7 | 8 | 9 | 10 | 11 | 12 |

<Unnamed>

13 |
14 |

Classes

15 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/javadoc/package-list: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/javadoc/package-summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 |
16 | 17 | 18 |
Skip navigation links
19 | 20 | 21 | 22 | 31 |
32 | 59 | 60 |
61 |

Package <Unnamed>

62 |
63 |
64 | 111 |
112 | 113 |
114 | 115 | 116 |
Skip navigation links
117 | 118 | 119 | 120 | 129 |
130 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /docs/javadoc/package-tree.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Class Hierarchy 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Hierarchy For Package <Unnamed>

73 |
74 |
75 |

Class Hierarchy

76 | 87 |
88 | 89 |
90 | 91 | 92 |
Skip navigation links
93 | 94 | 95 | 96 | 105 |
106 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /docs/javadoc/package-use.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Uses of Package 7 | 8 | 9 | 10 | 11 | 12 | 22 | 25 | 26 |
27 | 28 | 29 |
Skip navigation links
30 | 31 | 32 | 33 | 42 |
43 | 70 | 71 |
72 |

Uses of Package

73 |
74 |
75 | 94 |
95 | 96 |
97 | 98 | 99 |
Skip navigation links
100 | 101 | 102 | 103 | 112 |
113 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/javadoc/script.js: -------------------------------------------------------------------------------- 1 | function show(type) 2 | { 3 | count = 0; 4 | for (var key in methods) { 5 | var row = document.getElementById(key); 6 | if ((methods[key] & type) != 0) { 7 | row.style.display = ''; 8 | row.className = (count++ % 2) ? rowColor : altColor; 9 | } 10 | else 11 | row.style.display = 'none'; 12 | } 13 | updateTabs(type); 14 | } 15 | 16 | function updateTabs(type) 17 | { 18 | for (var value in tabs) { 19 | var sNode = document.getElementById(tabs[value][0]); 20 | var spanNode = sNode.firstChild; 21 | if (value == type) { 22 | sNode.className = activeTableTab; 23 | spanNode.innerHTML = tabs[value][1]; 24 | } 25 | else { 26 | sNode.className = tableTab; 27 | spanNode.innerHTML = "" + tabs[value][1] + ""; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /instance.txt: -------------------------------------------------------------------------------- 1 | 3 2 | 10 5 3 | 7 2 4 | 15 7 5 | 6 | 2 7 | 2 0 expensive 8 | 0 1 cheap 9 | -------------------------------------------------------------------------------- /src/basic/DirectedGraph.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | import java.util.ArrayList; 3 | import java.util.Collections; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * Simple class that can be used to model directed graphs, where 10 | * arbitrary types of data are associated with the nodes and arcs 11 | * of the graph. Note that this implementation of an arc allows 12 | * multiple copies of the same arc. As such, it can not be assumed 13 | * that graphs stored by instances of this class are simple; they 14 | * can be multigraphs. 15 | * 16 | * It is assumed that the data type associated with the nodes 17 | * has a consistent implementation of hashCode() and equals(). 18 | * 19 | * @author Paul Bouman 20 | * 21 | * @param the type of data associated with nodes in this graph 22 | * @param the type of data associated with arcs in this graph 23 | */ 24 | 25 | public class DirectedGraph 26 | { 27 | private final List nodes; 28 | private final List> arcs; 29 | private final Map>> outArcs; 30 | private final Map>> inArcs; 31 | 32 | /** 33 | * Creates an empty graph with no nodes or arcs. 34 | */ 35 | public DirectedGraph() 36 | { 37 | this.nodes = new ArrayList<>(); 38 | this.arcs = new ArrayList<>(); 39 | this.outArcs = new LinkedHashMap<>(); 40 | this.inArcs = new LinkedHashMap<>(); 41 | } 42 | 43 | /** 44 | * Add a new node to this graph 45 | * @param node the data associated with the node that is added 46 | * @throws IllegalArgumentException if the node is already in the graph or is null 47 | */ 48 | public void addNode(V node) throws IllegalArgumentException 49 | { 50 | if (node == null) 51 | { 52 | throw new IllegalArgumentException("Unable to add null to the graph"); 53 | } 54 | else if (inArcs.containsKey(node)) 55 | { 56 | throw new IllegalArgumentException("Unable to add the same node twice to the same graph"); 57 | } 58 | else 59 | { 60 | nodes.add(node); 61 | inArcs.put(node, new ArrayList<>()); 62 | outArcs.put(node, new ArrayList<>()); 63 | } 64 | } 65 | 66 | /** 67 | * Adds an arc to this graph. 68 | * @param from the origin node of the arc to be added 69 | * @param to the destination of the arc to be added 70 | * @param arcData the data associated with the arc 71 | * @throws IllegalArgumentException if one of the end points is not in the graph 72 | */ 73 | public void addArc(V from, V to, A arcData) throws IllegalArgumentException 74 | { 75 | if (!inArcs.containsKey(from) || !outArcs.containsKey(to)) 76 | { 77 | throw new IllegalArgumentException("Unable to add arcs between nodes not in the graph"); 78 | } 79 | DirectedGraphArc a = new DirectedGraphArc<>(from, to, arcData); 80 | outArcs.get(from).add(a); 81 | inArcs.get(to).add(a); 82 | arcs.add(a); 83 | } 84 | 85 | 86 | /** 87 | * Gives a list of all nodes currently in the graph 88 | * @return the nodes in the graph 89 | */ 90 | public List getNodes() 91 | { 92 | return Collections.unmodifiableList(nodes); 93 | } 94 | 95 | /** 96 | * Gives a list of all arcs currently in the graph 97 | * @return the arcs in the graph 98 | */ 99 | public List> getArcs() 100 | { 101 | return Collections.unmodifiableList(arcs); 102 | } 103 | 104 | /** 105 | * Gives all the arcs that leave a particular node in the graph. 106 | * Note that this list may be empty if no arcs leave this node. 107 | * @param node the node for which we want the leaving arcs 108 | * @return a list of arcs leaving the node 109 | * @throws IllegalArgumentException if the node is not in the graph 110 | */ 111 | public List> getOutArcs(V node) throws IllegalArgumentException 112 | { 113 | if (!outArcs.containsKey(node)) 114 | { 115 | throw new IllegalArgumentException("Unable to provide out-arcs for a node that is not in the graph"); 116 | } 117 | return Collections.unmodifiableList(outArcs.get(node)); 118 | } 119 | 120 | /** 121 | * Gives all the arcs that enter a particular node in the graph. 122 | * Note that this list may be empty if no arcs enter this node. 123 | * @param node the node for which we want the entering arcs 124 | * @return a list of arcs entering the node 125 | * @throws IllegalArgumentException if the node is not in the graph 126 | */ 127 | public List> getInArcs(V node) throws IllegalArgumentException 128 | { 129 | if (!inArcs.containsKey(node)) 130 | { 131 | throw new IllegalArgumentException("Unable to provide in-arcs for a node that is not in the graph"); 132 | } 133 | return Collections.unmodifiableList(inArcs.get(node)); 134 | } 135 | 136 | /** 137 | * The total number of nodes in this graph 138 | * @return the number of nodes in the graph 139 | */ 140 | public int getNumberOfNodes() 141 | { 142 | return nodes.size(); 143 | } 144 | 145 | /** 146 | * The total number of arcs in this graph 147 | * @return the number of arcs in the graph 148 | */ 149 | public int getNumberOfArcs() 150 | { 151 | return arcs.size(); 152 | } 153 | 154 | /** 155 | * Gives the in-degree of a node in the graph. 156 | * @param node the node for which we want the in-degree 157 | * @return the in-degree of the node 158 | * @throws IllegalArgumentException if the node is not in the graph 159 | */ 160 | public int getInDegree(V node) throws IllegalArgumentException 161 | { 162 | return getInArcs(node).size(); 163 | } 164 | 165 | /** 166 | * Gives the out-degree of a node in the graph 167 | * @param node the node for which we want the out-degree 168 | * @return the out-degree of the node 169 | * @throws IllegalArgumentException if the node is not in the graph 170 | */ 171 | public int getOutDegree(V node) throws IllegalArgumentException 172 | { 173 | return getOutArcs(node).size(); 174 | } 175 | 176 | @Override 177 | public int hashCode() { 178 | final int prime = 31; 179 | int result = 1; 180 | result = prime * result + ((arcs == null) ? 0 : arcs.hashCode()); 181 | result = prime * result + ((nodes == null) ? 0 : nodes.hashCode()); 182 | return result; 183 | } 184 | 185 | @Override 186 | public boolean equals(Object obj) { 187 | if (this == obj) 188 | return true; 189 | if (obj == null) 190 | return false; 191 | if (getClass() != obj.getClass()) 192 | return false; 193 | DirectedGraph other = (DirectedGraph) obj; 194 | if (arcs == null) { 195 | if (other.arcs != null) 196 | return false; 197 | } else if (!arcs.equals(other.arcs)) 198 | return false; 199 | if (nodes == null) { 200 | if (other.nodes != null) 201 | return false; 202 | } else if (!nodes.equals(other.nodes)) 203 | return false; 204 | return true; 205 | } 206 | 207 | @Override 208 | public String toString() { 209 | return "DirectedGraph [nodes=" + nodes + ", arcs=" + arcs + "]"; 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /src/basic/DirectedGraphArc.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | /** 3 | * Class that models arcs in the directed arcs. Stores both the end-points, 4 | * as well as the data associated with the arc. 5 | * @author Paul Bouman 6 | * 7 | * @param the type of data associated with nodes in the graph 8 | * @param the type of data associated with arcs in the graph 9 | */ 10 | public class DirectedGraphArc 11 | { 12 | private final V from; 13 | private final V to; 14 | private final A data; 15 | 16 | /** 17 | * Construct an arc of the graph 18 | * @param from the origin of this arc 19 | * @param to the destination of this arc 20 | * @param data the data asociated with this arc 21 | */ 22 | public DirectedGraphArc(V from, V to, A data) 23 | { 24 | this.from = from; 25 | this.to = to; 26 | this.data = data; 27 | } 28 | 29 | /** 30 | * Used to retrieve the origin of this arc 31 | * @return the origin of this arc 32 | */ 33 | public V getFrom() 34 | { 35 | return from; 36 | } 37 | 38 | /** 39 | * Used to retrieve the destination of this arc 40 | * @return the destination of this arc 41 | */ 42 | public V getTo() 43 | { 44 | return to; 45 | } 46 | 47 | /** 48 | * Used to retrieve the data associated with this arc 49 | * @return the data associated with this arc 50 | */ 51 | public A getData() 52 | { 53 | return data; 54 | } 55 | 56 | @Override 57 | public int hashCode() 58 | { 59 | final int prime = 31; 60 | int result = 1; 61 | result = prime * result + ((data == null) ? 0 : data.hashCode()); 62 | result = prime * result + ((from == null) ? 0 : from.hashCode()); 63 | result = prime * result + ((to == null) ? 0 : to.hashCode()); 64 | return result; 65 | } 66 | 67 | @Override 68 | public boolean equals(Object obj) 69 | { 70 | if (this == obj) 71 | return true; 72 | if (obj == null) 73 | return false; 74 | if (getClass() != obj.getClass()) 75 | return false; 76 | DirectedGraphArc other = (DirectedGraphArc) obj; 77 | if (data == null) { 78 | if (other.data != null) 79 | return false; 80 | } else if (!data.equals(other.data)) 81 | return false; 82 | if (from == null) { 83 | if (other.from != null) 84 | return false; 85 | } else if (!from.equals(other.from)) 86 | return false; 87 | if (to == null) { 88 | if (other.to != null) 89 | return false; 90 | } else if (!to.equals(other.to)) 91 | return false; 92 | return true; 93 | } 94 | 95 | @Override 96 | public String toString() 97 | { 98 | return "Arc [from=" + from + ", to=" + to + ", data=" + data + "]"; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/basic/Item.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | /** 3 | * Class that models a knapsack item with a profit and a weight 4 | * @author Paul Bouman 5 | */ 6 | 7 | public class Item 8 | { 9 | private final int profit; 10 | private final int weight; 11 | 12 | /** 13 | * Default constructor for a knapsack item 14 | * @param profit the profit for this item (we want to maximize this) 15 | * @param weight the weight of the item (this consumes capacity) 16 | */ 17 | public Item(int profit, int weight) 18 | { 19 | super(); 20 | this.profit = profit; 21 | this.weight = weight; 22 | } 23 | 24 | /** 25 | * The profit of the current item. This is what we want to maximize. 26 | * @return the profit 27 | */ 28 | public int getProfit() 29 | { 30 | return profit; 31 | } 32 | 33 | /** 34 | * The weight of the current item. This consume capacity. 35 | * @return the weight 36 | */ 37 | public int getWeight() 38 | { 39 | return weight; 40 | } 41 | 42 | @Override 43 | public String toString() 44 | { 45 | return "Item [profit=" + profit + ", weight=" + weight + "]"; 46 | } 47 | 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/basic/Main.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | import java.io.File; 3 | import java.io.FileNotFoundException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Scanner; 7 | 8 | import ilog.concert.IloException; 9 | 10 | /** 11 | * Main class for the Java/CPLEX example 12 | * @author Paul Bouman 13 | * 14 | */ 15 | 16 | public class Main 17 | { 18 | public static void main(String [] args) 19 | { 20 | try 21 | { 22 | // Read the graph from the file 23 | DirectedGraph instance = read(new File("instance.txt")); 24 | System.out.println("The following instance was read:"); 25 | System.out.println(instance); 26 | 27 | // Create a model instance based on the directed graph 28 | Model model = new Model(instance, 9); 29 | // Solve the model 30 | model.solve(); 31 | // Print the solution 32 | System.out.println(model.getSolution()); 33 | System.out.println("Feasible? "+model.isFeasible()); 34 | 35 | // Take an item and manipulate it in the model 36 | Item i = instance.getNodes().get(0); 37 | model.setItem(i, false); 38 | model.solve(); 39 | System.out.println(model.getSolution()); 40 | 41 | // Undo the manipulation of the model 42 | model.setItem(i, true); 43 | model.solve(); 44 | System.out.println(model.getSolution()); 45 | 46 | model.cleanup(); 47 | } 48 | catch (IloException e) 49 | { 50 | e.printStackTrace(); 51 | } 52 | catch (FileNotFoundException e) 53 | { 54 | e.printStackTrace(); 55 | } 56 | } 57 | 58 | /** 59 | * Reads a Precedence Constrained Knapsack Problem as a directed graph from a file 60 | * @param f the file to read 61 | * @return a directed graph containing the Precedence Constrained Knapsack Problem 62 | * @throws FileNotFoundException if the file to read does not exist 63 | */ 64 | public static DirectedGraph read(File f) throws FileNotFoundException 65 | { 66 | try (Scanner scan = new Scanner(f)) 67 | { 68 | DirectedGraph result = new DirectedGraph<>(); 69 | List items = new ArrayList<>(); 70 | 71 | // Reading the items 72 | int numItems = scan.nextInt(); 73 | for (int i=0; i < numItems; i++) 74 | { 75 | int profit = scan.nextInt(); 76 | int weight = scan.nextInt(); 77 | Item item = new Item(profit,weight); 78 | items.add(item); 79 | result.addNode(item); 80 | } 81 | 82 | // Reading the arcs / precedence constraints 83 | int numArcs = scan.nextInt(); 84 | for (int i=0; i < numArcs; i++) 85 | { 86 | int fromIndex = scan.nextInt(); 87 | int toIndex = scan.nextInt(); 88 | String reason = scan.next(); 89 | 90 | Item from = items.get(fromIndex); 91 | Item to = items.get(toIndex); 92 | result.addArc(from, to, reason); 93 | } 94 | 95 | return result; 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/basic/Model.java: -------------------------------------------------------------------------------- 1 | package basic; 2 | import java.util.ArrayList; 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import ilog.concert.IloException; 8 | import ilog.concert.IloNumExpr; 9 | import ilog.concert.IloNumVar; 10 | import ilog.cplex.IloCplex; 11 | 12 | /** 13 | * Model class that converts a directed graph representing a 14 | * precedence constrained knapsack problem into a mathematical programming 15 | * model managed by CPLEX. 16 | * @author Paul Bouman 17 | */ 18 | 19 | public class Model 20 | { 21 | private DirectedGraph instance; 22 | private int capacity; 23 | 24 | private IloCplex cplex; 25 | 26 | private Map varMap; 27 | 28 | /** 29 | * Constructor that takes a directed graph with the items and precedence constraints 30 | * @param instance a directed graph with items 31 | * @param capacity the capacity of the knapsack 32 | * @throws IloException if something goes wrong with CPLEX 33 | */ 34 | 35 | public Model(DirectedGraph instance, int capacity) throws IloException 36 | { 37 | // Initialize the instance variables 38 | this.instance = instance; 39 | this.capacity = capacity; 40 | this.cplex = new IloCplex(); 41 | 42 | // Create a map to link items to variables 43 | this.varMap = new HashMap<>(); 44 | 45 | // Initialize the model. It is important to initialize the variables first! 46 | addVariables(); 47 | addKnapsackConstraint(); 48 | addPrecedenceConstraints(); 49 | addObjective(); 50 | 51 | // Optionally: export the model to a file, so we can check the mathematical 52 | // program generated by CPLEX 53 | cplex.exportModel("model.lp"); 54 | // Optionally: suppress the output of CPLEX 55 | cplex.setOut(null); 56 | } 57 | 58 | /** 59 | * Disable an item in the model (fix it to 0) or enable it (either 0 or 1) 60 | * @param i the item to manipulate 61 | * @param enabled whether to enable it (0 or 1) or disable it (always 0) 62 | * @throws IloException if something is wrong with CPLEX 63 | */ 64 | public void setItem(Item i, boolean enabled) throws IloException 65 | { 66 | IloNumVar var = varMap.get(i); 67 | if (enabled) { 68 | // If it is enabled, the lower bound is 0 and the upper bound is 1 69 | var.setLB(0); 70 | var.setUB(1); 71 | } 72 | else { 73 | // If it is disabled, both lower and upper bound are set to 0 74 | var.setLB(0); 75 | var.setUB(0); 76 | } 77 | } 78 | 79 | /** 80 | * Solve the Mathematical Programming Model 81 | * @throws IloException if something is wrong with CPLEX 82 | */ 83 | public void solve() throws IloException 84 | { 85 | cplex.solve(); 86 | } 87 | 88 | /** 89 | * Checks whether the current solution to the model is feasible 90 | * @return the feasibility of the model 91 | * @throws IloException if something is wrong with CPLEX 92 | */ 93 | public boolean isFeasible() throws IloException 94 | { 95 | return cplex.isPrimalFeasible(); 96 | } 97 | 98 | /** 99 | * Create a list of the items for which the decision variables 100 | * are one in the current solution of the mathematical program. 101 | * @return a list of selected items 102 | * @throws IloException if something is wrong with CPLEX 103 | */ 104 | public List getSolution() throws IloException 105 | { 106 | List result = new ArrayList<>(); 107 | for (Item i : instance.getNodes()) 108 | { 109 | IloNumVar var = varMap.get(i); 110 | double value = cplex.getValue(var); 111 | if (value >= 0.5) 112 | { 113 | result.add(i); 114 | } 115 | } 116 | return result; 117 | } 118 | 119 | /** 120 | * Cleans up the CPLEX model in order to free up some memory. 121 | * This is important if you create many models, as memory used 122 | * by CPLEX is not freed up automatically by the JVM. 123 | * @throws IloException if something goes wrong with CPLEX 124 | */ 125 | public void cleanup() throws IloException 126 | { 127 | cplex.clearModel(); 128 | cplex.end(); 129 | } 130 | 131 | private void addObjective() throws IloException 132 | { 133 | // Initialize the objective sum to 0 134 | IloNumExpr obj = cplex.constant(0); 135 | for (Item i : instance.getNodes()) 136 | { 137 | IloNumVar var = varMap.get(i); 138 | // Take the product of the decision variable and the profit of the item 139 | IloNumExpr term = cplex.prod(var, i.getProfit()); 140 | // Add the term to the current sum 141 | obj = cplex.sum(obj, term); 142 | } 143 | // Add the obj expression as a maximization objective 144 | cplex.addMaximize(obj); 145 | } 146 | 147 | private void addPrecedenceConstraints() throws IloException 148 | { 149 | for (DirectedGraphArc arc : instance.getArcs()) 150 | { 151 | IloNumVar from = varMap.get(arc.getFrom()); 152 | IloNumVar to = varMap.get(arc.getTo()); 153 | cplex.addLe(from, to); 154 | } 155 | } 156 | 157 | private void addKnapsackConstraint() throws IloException 158 | { 159 | // Initialize the left-hand side of our constraint to 0 160 | IloNumExpr lhs = cplex.constant(0); 161 | for (Item i : instance.getNodes()) 162 | { 163 | IloNumVar var = varMap.get(i); 164 | // Take the product of the decision variable and the item weight 165 | IloNumExpr term = cplex.prod(i.getWeight(), var); 166 | // Add the term to the left hand side summation 167 | lhs = cplex.sum(lhs, term); 168 | } 169 | // Add the constraint lhs <= capacity to the model 170 | cplex.addLe(lhs, capacity); 171 | } 172 | 173 | private void addVariables() throws IloException 174 | { 175 | for (Item i : instance.getNodes()) 176 | { 177 | IloNumVar var = cplex.boolVar(); 178 | varMap.put(i, var); 179 | } 180 | } 181 | 182 | 183 | } 184 | -------------------------------------------------------------------------------- /src/colgen/Instance.java: -------------------------------------------------------------------------------- 1 | package colgen; 2 | import java.util.Collections; 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | import java.util.Random; 6 | import java.util.Set; 7 | 8 | /** 9 | * This class models an instance of the cutting-stock problem. 10 | * The cutting stock problem consists of a number of orders 11 | * of certain sizes. The question is how we can most efficiently 12 | * cut the orders out of larger stock such that we need the least 13 | * amount of large stock. 14 | * 15 | * For example, we have to produce metal bars. The orders indicate 16 | * how many bars of a certain length we must produce. The capacity 17 | * indicates how long a bar is that we can cut up into smallers bars 18 | * required for the order. The goal is to cut up as few large bars 19 | * as possible. 20 | * @author Paul Bouman 21 | * 22 | */ 23 | public class Instance 24 | { 25 | private int capacity; 26 | private Map orders; 27 | 28 | /** 29 | * Creates a cutting stock instance based on the provided orders and a capacity 30 | * @param orders the orders that need to be produced 31 | * @param capacity the length or capacity of the base stock we must cut up 32 | */ 33 | public Instance(Map orders, int capacity) 34 | { 35 | this.orders = new LinkedHashMap<>(orders); 36 | this.capacity = capacity; 37 | } 38 | 39 | /** 40 | * Provides a list of sizes that occur in the orders in this instance. 41 | * The size of the order is the amount of stock required to produce a 42 | * single item of a particular size. 43 | * @return a list with the sizes of the order. 44 | */ 45 | public Set getSizes() 46 | { 47 | return Collections.unmodifiableSet(orders.keySet()); 48 | } 49 | 50 | /** 51 | * Provides how many copies of items of the provides size need to be 52 | * produces 53 | * @param size the size of the item to be produced 54 | * @return how many copies of the item must be produced 55 | */ 56 | public int getAmount(int size) 57 | { 58 | return orders.getOrDefault(size, 0); 59 | } 60 | 61 | /** 62 | * Provides the capacity of a unit of base stock that will be cut up 63 | * in order to produce the items in the orders. 64 | * @return the capacity of a unit of base stock 65 | */ 66 | public int getCapacity() 67 | { 68 | return capacity; 69 | } 70 | 71 | /** 72 | * Method that can be used to generate a random cutting-stock instance 73 | * @param seed a random seed 74 | * @param orders the number unique sizes that occur in the orders 75 | * @param maxStep the maximum step size of the sizes in the orders 76 | * @param maxAmount the maximum amount that can be ordered of a single size 77 | * @return a random instance based on the provided information 78 | */ 79 | public static Instance randomInstance(long seed, int orders, int maxStep, int maxAmount) 80 | { 81 | Random ran = new Random(seed); 82 | Map map = new LinkedHashMap<>(); 83 | int curLength = 0; 84 | for (int t=0; t < orders; t++) 85 | { 86 | curLength += 1 + ran.nextInt(maxStep); 87 | int amount = 1 + ran.nextInt(maxAmount); 88 | map.put(curLength, amount); 89 | } 90 | curLength += 1 + ran.nextInt(maxStep); 91 | return new Instance(map, curLength); 92 | } 93 | 94 | @Override 95 | public String toString() { 96 | return "Instance [capacity=" + capacity + ", orders=" + orders + "]"; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/colgen/Main.java: -------------------------------------------------------------------------------- 1 | package colgen; 2 | import java.util.Random; 3 | 4 | import ilog.concert.IloException; 5 | 6 | /** 7 | * Main class that generates random instances and solves them using the Column Generation model 8 | * @author Paul Bouman 9 | * 10 | */ 11 | public class Main 12 | { 13 | public static void main(String [] args) throws IloException 14 | { 15 | long time = System.currentTimeMillis(); 16 | Random ran = new Random(54321); 17 | for (int i=0; i < 100; i++) 18 | { 19 | Instance instance = Instance.randomInstance(ran.nextLong(), 50, 13, 20); 20 | 21 | MasterModel mm = new MasterModel(instance); 22 | mm.solveInteger(); 23 | Solution sol = mm.getSolution(); 24 | double lb = mm.getLowerBound(); 25 | 26 | System.out.println("Instance: "+instance); 27 | System.out.println("Solution: "+sol); 28 | System.out.println("Integer solution: "+sol.getStockNeeded()); 29 | System.out.println("Lowerbound: "+lb); 30 | if (lb > sol.getStockNeeded()) { 31 | System.out.println("This is very strange..."); 32 | } 33 | System.out.println(); 34 | mm.cleanUp(); 35 | } 36 | time = System.currentTimeMillis() - time; 37 | System.out.println("Runtime: "+time+"ms"); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/colgen/MasterModel.java: -------------------------------------------------------------------------------- 1 | package colgen; 2 | import java.util.ArrayList; 3 | import java.util.LinkedHashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Map.Entry; 7 | 8 | import ilog.concert.IloColumn; 9 | import ilog.concert.IloConversion; 10 | import ilog.concert.IloException; 11 | import ilog.concert.IloNumExpr; 12 | import ilog.concert.IloNumVar; 13 | import ilog.concert.IloNumVarType; 14 | import ilog.concert.IloObjective; 15 | import ilog.concert.IloRange; 16 | import ilog.cplex.IloCplex; 17 | import ilog.cplex.IloCplex.DoubleParam; 18 | 19 | /** 20 | * Class that implements the Master Problem of the Cutting Stock problem 21 | * 22 | * This class performs column generation on the LP-relaxation of the master problem. 23 | * It is also possible to solve the current version of the model, including the 24 | * generated columns, as an Integer problem. 25 | * 26 | * Note that this class will not necesarilly find the optimal solution to the problem, 27 | * as a full-blown branch-and-price approach is required to do so. However, the lower-bound 28 | * provided by the LP-relaxation can be used to determine the gap between the solution found 29 | * and the optimal solution. 30 | * 31 | * @author Paul Bouman 32 | * 33 | */ 34 | public class MasterModel 35 | { 36 | private double threshold = 1e-14; 37 | 38 | private Instance instance; 39 | private IloCplex model; 40 | 41 | private IloObjective obj; 42 | private Map vars; 43 | private Map constraints; 44 | 45 | private PricingModel pricing; 46 | 47 | private double lowerbound = 0; 48 | private Solution solution; 49 | 50 | /** 51 | * Constructor that builds the Master Problem of a Column Generation model 52 | * for the Cutting Stock problem 53 | * @param instance the instance for which to build a column generation model 54 | * @throws IloException if something is wrong with CPLEX 55 | */ 56 | public MasterModel(Instance instance) throws IloException 57 | { 58 | this.instance = instance; 59 | this.model = new IloCplex(); 60 | 61 | this.vars = new LinkedHashMap<>(); 62 | this.constraints = new LinkedHashMap<>(); 63 | this.pricing = new PricingModel(instance); 64 | 65 | initPatternsAndVars(); 66 | initConstraints(); 67 | initObjective(); 68 | model.setOut(null); 69 | } 70 | 71 | /** 72 | * This method initializes some basic patterns, where each item size is 73 | * cut multiple times from a single piece of stock. 74 | * @throws IloException 75 | */ 76 | private void initPatternsAndVars() throws IloException 77 | { 78 | for (Integer size : instance.getSizes()) { 79 | Map cutMap = new LinkedHashMap<>(); 80 | cutMap.put(size, instance.getCapacity()/size); 81 | Pattern pattern = new Pattern(cutMap); 82 | IloNumVar var = model.numVar(0, Double.POSITIVE_INFINITY); 83 | vars.put(pattern, var); 84 | } 85 | } 86 | 87 | /** 88 | * This method initializes the constraints that for each size of items 89 | * that need to be produced, enough items are cut. 90 | * @throws IloException 91 | */ 92 | private void initConstraints() throws IloException 93 | { 94 | for (Integer size : instance.getSizes()) 95 | { 96 | IloNumExpr expr = model.constant(0); 97 | for (Entry e : vars.entrySet()) 98 | { 99 | Pattern pattern = e.getKey(); 100 | if (pattern.containsSize(size)) 101 | { 102 | IloNumVar var = e.getValue(); 103 | IloNumExpr term = model.prod(var, pattern.getAmount(size)); 104 | expr = model.sum(expr, term); 105 | } 106 | } 107 | IloRange constraint = model.addGe(expr, instance.getAmount(size)); 108 | constraints.put(size, constraint); 109 | } 110 | } 111 | 112 | /** 113 | * Initializes the minimization objective. Each time one of the patterns 114 | * is used, one unit of base stock is utilized, so the objective is to 115 | * minimize the sum of the decision variables. 116 | * @throws IloException 117 | */ 118 | private void initObjective() throws IloException 119 | { 120 | IloNumExpr expr = model.constant(0); 121 | for (IloNumVar var : vars.values()) 122 | { 123 | expr = model.sum(expr,var); 124 | } 125 | obj = model.addMinimize(expr); 126 | } 127 | 128 | /** 129 | * This method can be used to add a new pattern to the current model. 130 | * The steps perform are to introduce a new decision variable, 131 | * add this decision variable to the relevant constraints and add 132 | * it to the objective 133 | * @param p the pattern to introduce as a new column in the model 134 | * @throws IloException if something goes wrong with CPLEX 135 | */ 136 | private void addPattern(Pattern p) throws IloException 137 | { 138 | if (vars.containsKey(p)) { 139 | // This should never happen in a correct column generation procedure 140 | throw new IllegalArgumentException("This pattern was already added to the model"); 141 | } 142 | 143 | // We build a column object by first defining the contribution to the objective as 1 144 | IloColumn column = model.column(obj, 1); 145 | for (Entry e : constraints.entrySet()) 146 | { 147 | int size = e.getKey(); 148 | if (p.containsSize(size)) 149 | { 150 | // Retrieve the constraint associated with this 151 | IloRange rng = e.getValue(); 152 | // We define a partial column based on the constraint and the contribution to the constraint 153 | IloColumn coefficient = model.column(rng, p.getAmount(size)); 154 | // The column is expanded with the coefficient just created 155 | column = column.and(coefficient); 156 | } 157 | } 158 | 159 | // We introduce a new decision variable for this column 160 | IloNumVar var = model.numVar(column, 0, Double.POSITIVE_INFINITY); 161 | // Finally, we store the variable in our map 162 | vars.put(p, var); 163 | } 164 | 165 | /** 166 | * Generates a map of duals, with a dual for each size of item that can be generated 167 | * @return a map with duals for the different items 168 | * @throws IloException if something goes wrong with CPLEX 169 | */ 170 | private Map getDuals() throws IloException 171 | { 172 | Map map = new LinkedHashMap<>(); 173 | for (Entry e : constraints.entrySet()) 174 | { 175 | // This is the size of the items related to this particular constraint 176 | int size = e.getKey(); 177 | // This is the objective referred to the constraint itself 178 | IloRange constraint = e.getValue(); 179 | // Retrieve the dual and store it in the map of duals 180 | double dual = model.getDual(constraint); 181 | map.put(size, dual); 182 | } 183 | return map; 184 | } 185 | 186 | /** 187 | * This method generates a single column and if it has positive reduced costs 188 | * adds it to the model 189 | * @return whether a column with positive reduced costs was found 190 | * @throws IloException when something goes wrong with CPLEX 191 | */ 192 | private boolean generateColumn() throws IloException 193 | { 194 | Map duals = getDuals(); 195 | pricing.setDuals(duals); 196 | pricing.solve(); 197 | Pattern pattern = pricing.getPattern(); 198 | if (pricing.getObjective() > threshold && !vars.containsKey(pattern)) 199 | { 200 | addPattern(pricing.getPattern()); 201 | return true; 202 | } 203 | return false; 204 | } 205 | 206 | /** 207 | * This method solves the Master Problem using Column Generation. This provides 208 | * the optimal LP-relaxation of the master model 209 | * @throws IloException when something goes wrong with CPLEX 210 | */ 211 | public void solveRelaxation() throws IloException 212 | { 213 | do 214 | { 215 | // Solve the LP-relaxation 216 | model.solve(); 217 | } while (generateColumn()); // As long as new columns with positive reduced costs are generated 218 | } 219 | 220 | /** 221 | * This method solves the IP version of the Master Problem based on the current columns in the model. 222 | * This method first executed the column generation procedure on the relaxed version of the problem. 223 | * @throws IloException 224 | */ 225 | public void solveInteger() throws IloException 226 | { 227 | // Store the relaxed solution as a lowerbound 228 | // Note that we know the integer-objective must be integer, 229 | // so we can take the ceil of the LP-relaxation for this 230 | // particular problem. We subtract the current numeric precision to avoid 231 | // situations where the lower bound is greater than the optimal solution. 232 | solveRelaxation(); 233 | lowerbound = Math.ceil(model.getObjValue() - model.getParam(DoubleParam.EpOpt)); 234 | 235 | // Convert the model to an integer model and solve 236 | List conversions = new ArrayList<>(); 237 | for (IloNumVar var : vars.values()) 238 | { 239 | IloConversion conv = model.conversion(var, IloNumVarType.Int); 240 | model.add(conv); 241 | conversions.add(conv); 242 | } 243 | model.solve(); 244 | 245 | // Construct a solution based on the IP-solution 246 | Map result = new LinkedHashMap<>(); 247 | for (Entry e : vars.entrySet()) 248 | { 249 | Pattern pattern = e.getKey(); 250 | IloNumVar var = e.getValue(); 251 | int copies = (int)Math.round(model.getValue(var)); 252 | if (copies > 0) 253 | { 254 | result.put(pattern, copies); 255 | } 256 | } 257 | solution = new Solution(instance, result); 258 | 259 | // Undo the integer conversion 260 | for (IloConversion conv : conversions) 261 | { 262 | model.remove(conv); 263 | } 264 | } 265 | 266 | /** 267 | * Clears the CPLEX model from memory. Recommended if you do not need the model any more, 268 | * as the JNI-based memory used by the model is not automatically collected by the garbage collector. 269 | * @throws IloException 270 | */ 271 | public void cleanUp() throws IloException 272 | { 273 | model.clearModel(); 274 | model.end(); 275 | pricing.cleanUp(); 276 | } 277 | 278 | /** 279 | * Retrieve the last solution found when solveInteger() was called 280 | * @return the best solution found during the most recent call to solveInteger() 281 | */ 282 | public Solution getSolution() 283 | { 284 | return solution; 285 | } 286 | 287 | /** 288 | * Gives the lower bound to the problem based on the LP-relaxation. This is a lower bound 289 | * on the best possible solution to the problem and can be used to compute how far the 290 | * computed integer solution is possibly away from optimality. 291 | * @return a lower bound on the best possible solution to the problem 292 | */ 293 | public double getLowerBound() 294 | { 295 | return lowerbound; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/colgen/Pattern.java: -------------------------------------------------------------------------------- 1 | package colgen; 2 | import java.util.Collections; 3 | import java.util.LinkedHashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Set; 7 | import java.util.stream.Collectors; 8 | import java.util.stream.Stream; 9 | 10 | /** 11 | * Models a cutting pattern for a base unit of stock. 12 | * It indicates how many pieces of a particular size 13 | * are to be cut from a piece of base stock. 14 | * @author Paul Bouman 15 | * 16 | */ 17 | public class Pattern 18 | { 19 | 20 | // In this map, the keys represent the sizes of items to be cut, 21 | // and the values represent how many copies of such an items are 22 | // to be cut according to this pattern. 23 | private Map cuts; 24 | // The total length of this cutting pattern. Should not exceed the 25 | // capacity of a base unit of stock 26 | private int size; 27 | 28 | 29 | /** 30 | * Constructor for a cutting pattern. The list should contain 31 | * the sizes of the items to be cut. 32 | * @param cuts a list indicating the size of each item to be cut 33 | * from the base stock. Item sizes can be repeated 34 | * multiple times if the same size must be cut from 35 | * the base stock more than once. 36 | */ 37 | public Pattern(List cuts) 38 | { 39 | this.cuts = new LinkedHashMap<>(); 40 | cuts.forEach(i -> this.cuts.merge(i, 1, Integer::sum)); 41 | this.size = cuts.stream() 42 | .mapToInt(i -> i) 43 | .sum(); 44 | } 45 | 46 | /** 47 | * Constructor for a cutting pattern. The map should contain keys 48 | * indicating the sizes of items that must be cut from the base 49 | * stock. The values in the map indicate how many copies of such 50 | * an item must be cut from the base stock. 51 | * @param cuts a map representing the sizes of items to be cut (keys) 52 | * and the number of copies of those items (values) 53 | */ 54 | public Pattern(Map cuts) 55 | { 56 | this.cuts = new LinkedHashMap<>(cuts); 57 | this.size = cuts.entrySet() 58 | .stream() 59 | .mapToInt(e -> e.getKey()*e.getValue()) 60 | .sum(); 61 | } 62 | 63 | /** 64 | * Check whether this cutting pattern contains an item of a 65 | * particular size. 66 | * @param size the size for which to check items are generated 67 | * in this cutting pattern 68 | * @return true if the item size occurs in this cutting pattern 69 | */ 70 | public boolean containsSize(int size) 71 | { 72 | return cuts.containsKey(size); 73 | } 74 | 75 | /** 76 | * Provides a set of unique sizes that occur in this cutting pattern. 77 | * Note that a single cutting pattern may cut the same size multiple 78 | * times from a base stock. In order to deduce how often an item size 79 | * occurs in this cutting pattern, the getAmount() method must be used. 80 | * @return a set with the item sizes that occur in this cutting pattern 81 | */ 82 | public Set getSizes() 83 | { 84 | return Collections.unmodifiableSet(cuts.keySet()); 85 | } 86 | 87 | /** 88 | * Retrieves the number of copies of an item of a particular size 89 | * are creating when this cutting pattern is applied to the base stock. 90 | * @param size the size of the item for which to check the number of copies 91 | * @return the number of copies produces when this cutting pattern is applied 92 | */ 93 | public int getAmount(int size) 94 | { 95 | return cuts.getOrDefault(size, 0); 96 | } 97 | 98 | /** 99 | * The total size of this cutting pattern. If multiple items with the same 100 | * size are created within this cutting pattern, the number of copies is 101 | * multiplied with the size of the item. 102 | * @return the total size of this cutting pattern 103 | */ 104 | public int getSize() 105 | { 106 | return size; 107 | } 108 | 109 | /** 110 | * Represents this cutting pattern as a list of item sizes, 111 | * where item sizes that are cut multiple times are repeated 112 | * in the list. 113 | * @return a list of item sizes that represents this cutting pattern 114 | */ 115 | public List asList() 116 | { 117 | return cuts.entrySet() 118 | .stream() 119 | .flatMap(e -> Stream.generate(e::getKey).limit(e.getValue())) 120 | .collect(Collectors.toList()); 121 | } 122 | 123 | @Override 124 | public int hashCode() { 125 | final int prime = 31; 126 | int result = 1; 127 | result = prime * result + ((cuts == null) ? 0 : cuts.hashCode()); 128 | result = prime * result + size; 129 | return result; 130 | } 131 | 132 | @Override 133 | public boolean equals(Object obj) { 134 | if (this == obj) 135 | return true; 136 | if (obj == null) 137 | return false; 138 | if (getClass() != obj.getClass()) 139 | return false; 140 | Pattern other = (Pattern) obj; 141 | if (cuts == null) { 142 | if (other.cuts != null) 143 | return false; 144 | } else if (!cuts.equals(other.cuts)) 145 | return false; 146 | if (size != other.size) 147 | return false; 148 | return true; 149 | } 150 | 151 | @Override 152 | public String toString() { 153 | return asList().toString(); 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /src/colgen/PricingModel.java: -------------------------------------------------------------------------------- 1 | package colgen; 2 | import java.util.LinkedHashMap; 3 | import java.util.Map; 4 | import java.util.Map.Entry; 5 | 6 | import ilog.concert.IloException; 7 | import ilog.concert.IloNumExpr; 8 | import ilog.concert.IloNumVar; 9 | import ilog.concert.IloObjective; 10 | import ilog.cplex.IloCplex; 11 | 12 | /** 13 | * A model for the Pricing Problem of the Cutting Stock problem. 14 | * This basically solves a Knapsack Problem, where the profits of the 15 | * items are based on the reduced costs, and the capacity of the knapsack 16 | * is the capacity of a single piece of base stock. 17 | * @author Paul Bouman 18 | * 19 | */ 20 | public class PricingModel 21 | { 22 | private Instance instance; 23 | private IloCplex model; 24 | 25 | private IloObjective obj; 26 | private Map vars; 27 | 28 | 29 | /** 30 | * Initializes a model for the Pricing Problem of the Cutting Stock problem. 31 | * @param instance the instance for which to initialize the pricing problem model. 32 | * @throws IloException if something goes wrong with CPLEX 33 | */ 34 | public PricingModel(Instance instance) throws IloException 35 | { 36 | this.instance = instance; 37 | this.model = new IloCplex(); 38 | this.vars = new LinkedHashMap<>(); 39 | 40 | initVars(); 41 | initCapacityConstraint(); 42 | initObjective(); 43 | model.setOut(null); 44 | } 45 | 46 | private void initVars() throws IloException 47 | { 48 | for (Integer size : instance.getSizes()) 49 | { 50 | IloNumVar var = model.intVar(0, Integer.MAX_VALUE); 51 | vars.put(size, var); 52 | } 53 | } 54 | 55 | private void initObjective() throws IloException 56 | { 57 | obj = model.addMaximize(); 58 | } 59 | 60 | private void initCapacityConstraint() throws IloException 61 | { 62 | IloNumExpr expr = model.constant(0); 63 | for (Entry e : vars.entrySet()) 64 | { 65 | int size = e.getKey(); 66 | IloNumVar var = e.getValue(); 67 | IloNumExpr term = model.prod(size, var); 68 | expr = model.sum(expr, term); 69 | } 70 | model.addLe(expr, instance.getCapacity()); 71 | } 72 | 73 | /** 74 | * Update the objective based on a map of duals, where the current 75 | * shadow costs of each item size is provided 76 | * @param duals a dual or shadow cost for each item size in the instance 77 | * @throws IloException if something goes wrong with CPLEX 78 | */ 79 | public void setDuals(Map duals) throws IloException 80 | { 81 | // Create a new expression for the objective 82 | IloNumExpr expr = model.constant(-1); 83 | for (Entry e : duals.entrySet()) 84 | { 85 | int size = e.getKey(); 86 | double dual = e.getValue(); 87 | IloNumVar var = vars.get(size); 88 | IloNumExpr term = model.prod(var, dual); 89 | expr = model.sum(expr, term); 90 | } 91 | // Replace the objective with the new expression 92 | obj.setExpr(expr); 93 | } 94 | 95 | 96 | /** 97 | * Clears the model from the memory. This is required because CPLEX uses 98 | * JNI-allocated memory that is not automatically garbage collected. 99 | * @throws IloException if something goes wrong with CPLEX 100 | */ 101 | public void cleanUp() throws IloException 102 | { 103 | model.clearModel(); 104 | model.end(); 105 | } 106 | 107 | /** 108 | * Solve the model with the most recentely configured objective 109 | * @throws IloException when something goes wrong with CPLEX 110 | */ 111 | public void solve() throws IloException 112 | { 113 | model.solve(); 114 | } 115 | 116 | /** 117 | * Provides the objective value (the reduced costs) of the last time 118 | * the pricing problem was solved 119 | * @return the objective value / reduced costs of the last solution 120 | * @throws IloException in case something goes wrong with CPLEX 121 | */ 122 | public double getObjective() throws IloException 123 | { 124 | return model.getObjValue(); 125 | } 126 | 127 | /** 128 | * Obtain a cutting pattern based on the most recent solution found 129 | * for this pricing problem. 130 | * @return a cutting pattern that minimizes the reduced costs 131 | * @throws IloException in case something goes wrong with CPLEX 132 | */ 133 | public Pattern getPattern() throws IloException 134 | { 135 | Map resultMap = new LinkedHashMap<>(); 136 | for (Entry e : vars.entrySet()) 137 | { 138 | int size = e.getKey(); 139 | IloNumVar var = e.getValue(); 140 | int cuts = (int)Math.round(model.getValue(var)); 141 | resultMap.put(size, cuts); 142 | } 143 | return new Pattern(resultMap); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/colgen/Solution.java: -------------------------------------------------------------------------------- 1 | package colgen; 2 | import java.util.Collections; 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | import java.util.Set; 6 | 7 | /** 8 | * This class represents a solution to the Cutting Stock problem. 9 | * It contains a reference to the instance solved, cutting patterns 10 | * and how many times each cutting must be applied to a unit of stock 11 | * in order to produce the items in the demand of the instance. 12 | * @author Paul Bouman 13 | * 14 | */ 15 | public class Solution 16 | { 17 | private Instance instance; 18 | private Map patterns; 19 | private int stockNeeded; 20 | 21 | /** 22 | * Construct a solution based on a instance, and a map that specifies 23 | * cutting patterns and how often each pattern must be applied to 24 | * cover the demand. 25 | * @param instance the instance for which this is a solution 26 | * @param solution a map with patterns and times each pattern must be applied 27 | */ 28 | public Solution(Instance instance, Map solution) 29 | { 30 | this.instance = instance; 31 | this.patterns = new LinkedHashMap<>(solution); 32 | this.stockNeeded = patterns.values() 33 | .stream() 34 | .mapToInt(i -> i) 35 | .sum(); 36 | } 37 | 38 | /** 39 | * Provides a set of unique patterns that are utilized within this solution 40 | * @return the set of utilized patterns 41 | */ 42 | public Set getPatterns() 43 | { 44 | return Collections.unmodifiableSet(patterns.keySet()); 45 | } 46 | 47 | /** 48 | * Provides how many times a given pattern is applied in order to cover demand 49 | * @param p the pattern 50 | * @return how often it must be applied in order to cover demand 51 | */ 52 | public int getCopies(Pattern p) 53 | { 54 | return patterns.getOrDefault(p, 0); 55 | } 56 | 57 | /** 58 | * Gives the total number of base stock needed to cover all the demand. 59 | * This is basically the sum over the number of times each pattern must be applied. 60 | * @return the number of base stock required to cover the demand 61 | */ 62 | public int getStockNeeded() 63 | { 64 | return stockNeeded; 65 | } 66 | 67 | /** 68 | * Gives the instance for which this solution was computed 69 | * @return the instance for which this is a solution 70 | */ 71 | public Instance getInstance() 72 | { 73 | return instance; 74 | } 75 | 76 | @Override 77 | public String toString() 78 | { 79 | return patterns.toString(); 80 | } 81 | 82 | } 83 | --------------------------------------------------------------------------------