001    package net.sf.cpsolver.ifs.example.jobshop;
002    
003    import java.io.*;
004    import java.util.*;
005    
006    import net.sf.cpsolver.ifs.model.*;
007    import net.sf.cpsolver.ifs.util.*;
008    
009    /**
010     * Job Shop model.
011     * <br><br>
012     * It contains the number of available time slots and all machines and jobs.
013     * <br><br>
014     * It can also load the model from a file and save the solution.
015     * <br><br>
016     * <b>Input file format:</b><ul>
017     * First line: <ul><code>&lt;number of jobs&gt; &lt;number of machines&gt;</code></ul>
018     * Following lines: <ul>space separated list (a line for each job) of operations, each operation consist of machine number and operation processing time</ul>
019     * Example of 10 jobs, 10 machines:<ul><code>
020     * 10 10<br>
021     * 4 88 8 68 6 94 5 99 1 67 2 89 9 77 7 99 0 86 3 92<br>
022     * 5 72 3 50 6 69 4 75 2 94 8 66 0 92 1 82 7 94 9 63<br>
023     * 9 83 8 61 0 83 1 65 6 64 5 85 7 78 4 85 2 55 3 77<br>
024     * 7 94 2 68 1 61 4 99 3 54 6 75 5 66 0 76 9 63 8 67<br>
025     * 3 69 4 88 9 82 8 95 0 99 2 67 6 95 5 68 7 67 1 86<br>
026     * 1 99 4 81 5 64 6 66 8 80 2 80 7 69 9 62 3 79 0 88<br>
027     * 7 50 1 86 4 97 3 96 0 95 8 97 2 66 5 99 6 52 9 71<br>
028     * 4 98 6 73 3 82 2 51 1 71 5 94 7 85 0 62 8 95 9 79<br>
029     * 0 94 6 71 3 81 7 85 1 66 2 90 4 76 5 58 8 93 9 97<br>
030     * 3 50 0 59 1 82 8 67 7 56 9 96 6 58 4 81 5 59 2 96<br>
031     * </code></ul>
032     * For instance, the first job is described as follows: <ul>
033     * 88 time units on machine 4, then 68 time units on machine 8, then 94 time units on machine 6 ...
034     * </ul>
035     * </ul><br>
036     * <b>Output file firmat:</b><ul>
037     * A line for each machine, in each line there is a space separated list of jobs which the machine will process in the order they will be processed.
038     * </ul>
039     * @version
040     * IFS 1.1 (Iterative Forward Search)<br>
041     * Copyright (C) 2006 Tomáš Müller<br>
042     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
043     * Lazenska 391, 76314 Zlin, Czech Republic<br>
044     * <br>
045     * This library is free software; you can redistribute it and/or
046     * modify it under the terms of the GNU Lesser General Public
047     * License as published by the Free Software Foundation; either
048     * version 2.1 of the License, or (at your option) any later version.
049     * <br><br>
050     * This library is distributed in the hope that it will be useful,
051     * but WITHOUT ANY WARRANTY; without even the implied warranty of
052     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
053     * Lesser General Public License for more details.
054     * <br><br>
055     * You should have received a copy of the GNU Lesser General Public
056     * License along with this library; if not, write to the Free Software
057     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
058     */
059    public class JobShopModel extends Model {
060        private int iTotalNumberOfSlots = 1250;
061        private Machine[] iMachines;
062        private Job[] iJobs;
063        
064        /**
065         * Constructor 
066         * @param nrMachines number of machines
067         * @param nrJobs number of jobs
068         */
069        public JobShopModel(int nrMachines,int nrJobs) {
070            super();
071            iMachines = new Machine[nrMachines];
072            iJobs = new Job[nrJobs];
073        }
074        
075        /** Get total number of slots */
076        public int getTotalNumberOfSlots() { return iTotalNumberOfSlots; }
077        /** Get machine of the given numbner */
078        public Machine getMachine(int machineNumber) { return iMachines[machineNumber]; }
079        /** Count number of machines in the model */
080        public int countMachines() { return iMachines.length; }
081        /** Get job of the given number */
082        public Job getJob(int jobNumber) { return iJobs[jobNumber]; }
083        /** Count number of jobs in the model */
084        public int countJobs() { return iJobs.length; }
085    
086        private void setJob(int jobNumber, Job job) { iJobs[jobNumber]=job; }
087        private void setMachine(int machineNumber, Machine machine) { iMachines[machineNumber]=machine; }
088        
089        /** Loads the model from the given file */
090        public static JobShopModel loadModel(String file) throws IOException {
091            BufferedReader reader = new BufferedReader(new FileReader(file));
092            String line = reader.readLine();
093            while (line.startsWith("#")) line = reader.readLine();
094            StringTokenizer stk = new StringTokenizer(line," ");
095            int nrJobs = Integer.parseInt(stk.nextToken());
096            int nrMachines = Integer.parseInt(stk.nextToken());
097            JobShopModel model = new JobShopModel(nrMachines,nrJobs);
098            Machine[] machine = new Machine[nrMachines];
099            for (int i=0;i<nrMachines;i++) {
100                machine[i]=new Machine(i);
101                model.addConstraint(machine[i]);
102                model.setMachine(i, machine[i]);
103            }
104            for (int i=0;i<nrJobs;i++) {
105                Job job = new Job(i);
106                model.addConstraint(job);
107                model.setJob(i, job);
108                line = reader.readLine();
109                stk = new StringTokenizer(line," ");
110                for (int j=0;j<nrMachines;j++) {
111                    int machineNumber = Integer.parseInt(stk.nextToken());
112                    int processingTime = Integer.parseInt(stk.nextToken());
113                    Operation operation = new Operation(job,machine[machineNumber],j,processingTime);
114                    model.addVariable(operation);
115                    job.addVariable(operation);
116                    machine[machineNumber].addVariable(operation);
117                }
118                if (stk.hasMoreTokens()) {
119                    job.setDueTime(Integer.parseInt(stk.nextToken()));
120                }
121            }
122            reader.close();
123            for (Enumeration e=model.variables().elements();e.hasMoreElements();)
124                ((Operation)e.nextElement()).init();
125            return model;
126        }
127        
128        /** Get finishing time of the current (partial) solution */
129        public int getFinishingTime() {
130            int ret = 0;
131            for (Enumeration e=assignedVariables().elements();e.hasMoreElements();) {
132                ret = Math.max(ret,((Location)((Operation)e.nextElement()).getAssignment()).getFinishingTime());
133            }
134            return ret;
135        }
136        
137        /** Get information table */
138        public Hashtable getInfo() {
139            Hashtable ret = super.getInfo();
140            ret.put("Finishing time", String.valueOf(getFinishingTime()));
141            return ret;
142        }
143        
144        /** Save the solution into the given file */
145        public void save(String file) throws java.io.IOException {
146            PrintWriter writer = new PrintWriter(new FileWriter(file));
147            for (int i=0;i<countMachines();i++) {
148                Machine m = getMachine(i);
149                Vector ops = (Vector)m.variables().clone();
150                Collections.sort(ops, new OperationComparator());
151                for (Enumeration e=ops.elements();e.hasMoreElements();) {
152                    Operation op = (Operation)e.nextElement();
153                    if (op.getAssignment()!=null)
154                        writer.print((op.getJobNumber()<10?" ":"")+op.getJobNumber()+" ");
155                }
156                writer.println();
157            }
158            writer.println(";");
159            Hashtable info = getInfo();
160            for (Enumeration e=info.keys();e.hasMoreElements(); ) {
161                Object key = e.nextElement();
162                Object value = info.get(key);
163                writer.println("; "+key+": "+value);
164            }
165            writer.println(";");
166            for (int i=0;i<countJobs();i++) {
167                Job job = getJob(i);
168                writer.print("; ");
169                for (Enumeration e=job.variables().elements();e.hasMoreElements();) {
170                    Operation op = (Operation)e.nextElement();
171                    Location loc = (Location)op.getAssignment();
172                    writer.print((loc==null?"----":ToolBox.trim(String.valueOf(loc.getStartTime()), 4))+" ");
173                }
174                writer.println();
175            }
176            writer.flush();writer.close();
177        }
178        
179        private static class OperationComparator implements Comparator {
180            public int compare(Object o1, Object o2) {
181                Operation op1 = (Operation)o1;
182                Operation op2 = (Operation)o2;
183                Location loc1 = (Location)op1.getAssignment();
184                Location loc2 = (Location)op2.getAssignment();
185                if (loc1==null) {
186                    if (loc2==null) return 0;
187                    else return -1;
188                }
189                if (loc2==null) return 1;
190                return (loc1.getStartTime()<loc2.getStartTime()?-1:loc1.getStartTime()==loc2.getStartTime()?0:1);
191            }
192        }
193    }