001    package net.sf.cpsolver.ifs.example.csp;
002    
003    import java.util.*;
004    
005    import net.sf.cpsolver.ifs.model.*;
006    import net.sf.cpsolver.ifs.util.*;
007    
008    /**
009     * Random Binary CSP with kernels.
010     * <br><br>
011     * This class only implements the generation of Structured CSP problem.<br>
012     * In Structured CSP, variables are divided into several kernels (some variables may remain ouside kernels). 
013     * Different constraints (in density and tightnes) are generated according to whether variables are from the same kernel or not.
014     * <br><br>
015     * Model parameters:
016     * <br>
017     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
018     * <tr><td>CSP.NrVariables</td><td>{@link Integer}</td><td>Number of variables</td></tr>
019     * <tr><td>CSP.DomainSize</td><td>{@link Integer}</td><td>Number of values for each variable</td></tr>
020     * <tr><td>CSP.NrKernels</td><td>{@link Integer}</td><td>Number of kernels</td></tr>
021     * <tr><td>CSP.KernelSize</td><td>{@link Integer}</td><td>Number of variables in each kernel</td></tr>
022     * <tr><td>CSP.Tightness</td><td>{@link Double}</td><td>Tightness of constraints outside kernels</td></tr>
023     * <tr><td>CSP.KernelTightness</td><td>{@link Double}</td><td>Tightness of constraints inside a kernel</td></tr>
024     * <tr><td>CSP.Density</td><td>{@link Double}</td><td>Density of constraints outside kernels</td></tr>
025     * <tr><td>CSP.KernelDensity</td><td>{@link Double}</td><td>Density of constraints inside a kernel</td></tr>
026     * <tr><td>General.MPP</td><td>{@link String}</td><td>Minimal perturbation problem --> generate initial assignment</td></tr>
027     * </table>
028     * <br>
029     *
030     * @version
031     * IFS 1.1 (Iterative Forward Search)<br>
032     * Copyright (C) 2006 Tomáš Müller<br>
033     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
034     * Lazenska 391, 76314 Zlin, Czech Republic<br>
035     * <br>
036     * This library is free software; you can redistribute it and/or
037     * modify it under the terms of the GNU Lesser General Public
038     * License as published by the Free Software Foundation; either
039     * version 2.1 of the License, or (at your option) any later version.
040     * <br><br>
041     * This library is distributed in the hope that it will be useful,
042     * but WITHOUT ANY WARRANTY; without even the implied warranty of
043     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
044     * Lesser General Public License for more details.
045     * <br><br>
046     * You should have received a copy of the GNU Lesser General Public
047     * License along with this library; if not, write to the Free Software
048     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
049     */
050    public class StructuredCSPModel extends Model {
051        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(StructuredCSPModel.class);
052        private DataProperties iProperties = null;
053        
054        /** Constructor */
055        public StructuredCSPModel(DataProperties properties, long seed) {
056            iProperties = properties;
057            generate(seed);
058        }
059        
060        private void swap(Variable[][] allPairs, int first, int second) {
061            Variable[] a = allPairs[first];
062            allPairs[first]=allPairs[second];
063            allPairs[second]=a;
064        }
065    
066        private void buildBinaryConstraintGraph(Vector variables, Vector constraints, Random rnd) {
067            int numberOfAllPairs = variables.size()*(variables.size()-1)/2;
068            Variable[][] allPairs = new Variable[numberOfAllPairs][];
069            int idx=0;
070            for (Enumeration i1=variables.elements();i1.hasMoreElements();) {
071                Variable v1 = (Variable)i1.nextElement();
072                for (Enumeration i2=variables.elements();i2.hasMoreElements();) {
073                    Variable v2 = (Variable)i2.nextElement();
074                    if (v1.getId()>=v2.getId()) continue;
075                    allPairs[idx++]=new Variable[] {v1,v2};
076                }
077            }
078            idx = 0;
079            for (Enumeration i1=constraints.elements();i1.hasMoreElements();) {
080                CSPBinaryConstraint c = (CSPBinaryConstraint) i1.nextElement();
081                swap(allPairs, idx, idx+(int)(rnd.nextDouble()*(numberOfAllPairs-idx)));
082                    idx++;
083            }
084            idx = 0;
085            for (Enumeration i1=constraints.elements();i1.hasMoreElements();) {
086                CSPBinaryConstraint c = (CSPBinaryConstraint) i1.nextElement();
087                c.addVariable(allPairs[idx][0]);
088                c.addVariable(allPairs[idx][1]);
089                idx++;
090            }
091        }
092        
093        private void buildBinaryConstraintGraph2(Vector variables, int numberOfAllPairs, Vector constraints, Random rnd) {
094            Variable[][] allPairs = new Variable[numberOfAllPairs][];
095            int idx=0;
096            for (Enumeration i1=variables.elements();i1.hasMoreElements();) {
097                CSPVariable v1 = (CSPVariable)i1.nextElement();
098                for (Enumeration i2=variables.elements();i2.hasMoreElements();) {
099                    CSPVariable v2 = (CSPVariable)i2.nextElement();
100                    if (v1.getId()>=v2.getId()) continue;
101                    if (v1.getKernelId()>=0 && v1.getKernelId()==v2.getKernelId()) continue;
102                    allPairs[idx++]=new Variable[] {v1,v2};
103                }
104            }
105            idx = 0;
106            for (Enumeration i1=constraints.elements();i1.hasMoreElements();) {
107                CSPBinaryConstraint c = (CSPBinaryConstraint) i1.nextElement();
108                swap(allPairs, idx, idx+(int)(rnd.nextDouble()*(numberOfAllPairs-idx)));
109                    idx++;
110            }
111            idx = 0;
112            for (Enumeration i1=constraints.elements();i1.hasMoreElements();) {
113                CSPBinaryConstraint c = (CSPBinaryConstraint) i1.nextElement();
114                c.addVariable(allPairs[idx][0]);
115                c.addVariable(allPairs[idx][1]);
116                idx++;
117            }
118        }
119    
120        private void generate(long seed) {
121            int nrVariables = iProperties.getPropertyInt("CSP.NrVariables", 60);
122            int nrValues = iProperties.getPropertyInt("CSP.DomainSize", 15);
123            int nrKernels = iProperties.getPropertyInt("CSP.NrKernels", 2);
124            int nrKernelVariables = iProperties.getPropertyInt("CSP.KernelSize", 8);
125            
126            int nrPairValues = nrValues*nrValues;
127            float tightnessPerc = iProperties.getPropertyFloat("CSP.Tightness", 0.01f);
128            float kernelTightnessPerc = iProperties.getPropertyFloat("CSP.KernelTightness", 0.097f);
129            int nrCompatiblePairs = (int)Math.round((1.0-tightnessPerc)*nrPairValues);
130            int kernelNrCompatiblePairs = (int)Math.round((1.0-kernelTightnessPerc)*nrPairValues);
131            
132            int nrPairVariables = (nrVariables*(nrVariables-1))/2;
133            int nrPairKernelVariables = (nrKernelVariables*(nrKernelVariables-1))/2;
134            nrPairVariables -= nrKernels * nrPairKernelVariables;
135            float densityPerc = iProperties.getPropertyFloat("CSP.Density", 0.01f);
136            float densityKernelPerc = iProperties.getPropertyFloat("CSP.KernelDensity", 0.097f);
137            int density = (int)Math.round(densityPerc*nrPairVariables);
138            int kernelDensity = (int)Math.round(densityKernelPerc*nrPairKernelVariables);
139           
140            Random rnd = new Random(seed);
141            Vector generalVariables = new Vector(nrVariables-(nrKernels*nrKernelVariables));
142            int varId = 1;
143            for (int i=0;i<nrVariables-(nrKernels*nrKernelVariables);i++) {
144                CSPVariable var = new CSPVariable(varId++,nrValues);
145                generalVariables.addElement(var);
146                addVariable(var);
147            }
148            sLogger.debug("Created "+generalVariables.size()+" general variables.");
149            Vector[] kernelVariables = new Vector[nrKernels];
150            for (int k=0;k<nrKernels;k++) {
151                kernelVariables[k]=new Vector(nrKernelVariables);
152                for (int i=0;i<nrKernelVariables;i++) {
153                    CSPVariable var = new CSPVariable(varId++,nrValues,k);
154                    kernelVariables[k].addElement(var);
155                    addVariable(var);
156                }
157                if (k==0) sLogger.debug("Created "+kernelVariables[0].size()+" kernel variables (per kernel).");
158            }
159            sLogger.debug("Created "+variables().size()+" variables at total.");
160            int constId = 1;
161            Vector generalConstraints = new Vector(density);
162            for (int i=0;i<density;i++) {
163                CSPBinaryConstraint c = new CSPBinaryConstraint(constId++,nrCompatiblePairs);
164                generalConstraints.addElement(c);
165                addConstraint(c);
166            }
167            sLogger.debug("Created "+generalConstraints.size()+" general constraints (tightness="+tightnessPerc+").");
168            Vector[] kernelConstraints = new Vector[nrKernels];
169            for (int k=0;k<nrKernels;k++) {
170                kernelConstraints[k] = new Vector(kernelDensity);
171                for (int i=0;i<kernelDensity;i++) {
172                    CSPBinaryConstraint c = new CSPBinaryConstraint(constId++,kernelNrCompatiblePairs);
173                    kernelConstraints[k].addElement(c);
174                    addConstraint(c);
175                }
176                if (k==0) sLogger.debug("Created "+kernelConstraints[0].size()+" kernel constraints (per kernel, tightness="+kernelTightnessPerc+").");
177            }
178            sLogger.debug("Created "+constraints().size()+" constraints at total.");
179            
180            for (int k=0;k<nrKernels;k++) {
181                buildBinaryConstraintGraph(kernelVariables[k], kernelConstraints[k], rnd);
182            }
183            buildBinaryConstraintGraph2(variables(), nrPairVariables, generalConstraints, rnd);
184            
185            for (Enumeration i=constraints().elements();i.hasMoreElements();) {
186                CSPBinaryConstraint constraint = (CSPBinaryConstraint)i.nextElement();
187                constraint.init(rnd);
188            }
189            
190            if (iProperties.getPropertyBoolean("General.MPP",false)) {
191                for (Enumeration i=variables().elements();i.hasMoreElements();) {
192                    CSPVariable variable = (CSPVariable)i.nextElement();
193                    variable.generateInitialValue(rnd);
194                }
195            }
196        }
197        
198        /** Return information table */
199        public Hashtable getInfo() {
200            Hashtable ret = super.getInfo();
201            ret.put("Solution value", String.valueOf(getTotalValue()));
202            return ret;
203        }
204    }