001    package org.jaga.individualRepresentation.greycodedNumbers;
002    
003    import org.jaga.definitions.*;
004    import org.jaga.util.*;
005    
006    /**
007     * TODO: Complete these comments.
008     *
009     * <p><u>Project:</u> JAGA - Java API for Genetic Algorithms.</p>
010     *
011     * <p><u>Company:</u> University College London and JAGA.Org
012     *    (<a href="http://www.jaga.org" target="_blank">http://www.jaga.org</a>).
013     * </p>
014     *
015     * <p><u>Copyright:</u> (c) 2004 by G. Paperin.<br/>
016     *    This program is free software; you can redistribute it and/or modify
017     *    it under the terms of the GNU General Public License as published by
018     *    the Free Software Foundation, ONLY if you include a note of the original
019     *    author(s) in any redistributed/modified copy.<br/>
020     *    This program is distributed in the hope that it will be useful,
021     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
022     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     *    GNU General Public License for more details.<br/>
024     *    You should have received a copy of the GNU General Public License
025     *    along with this program; if not, write to the Free Software
026     *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
027     *    or see http://www.gnu.org/licenses/gpl.html</p>
028     *
029     * @author Greg Paperin (greg@jaga.org)
030     *
031     * @version JAGA public release 1.0 beta
032     */
033    
034    public class NDecimalsIndividualSimpleFactory implements IndividualsFactory {
035    
036            private int individualSize = 1;
037            private double decimalScale = 1000000;  // 10^6 i.e., 6 digits
038            private int precision = 64;  // bits
039            private RangeConstraint [] constraints = new RangeConstraint [] {null};
040    
041            public NDecimalsIndividualSimpleFactory() {}
042    
043            public NDecimalsIndividualSimpleFactory(int varsPerIndividual, int decPrecision,
044                                                                                            int representationLen) {
045                    setIndividualSize(varsPerIndividual);
046                    setDecimalScale(decPrecision);
047                    setPrecision(representationLen);
048            }
049    
050            public int getDecimalScale() {
051                    double scal = Math.log(decimalScale) / Math.log(10); // i.e. log(10, scale)
052                    return (byte) scal;
053            }
054    
055            public void setDecimalScale(int val) {
056                    if (val < 0 || 20 < val)
057                            throw new IllegalArgumentException("Decimal scale (" + val
058                                                                                               + ") not supported, use 10^0 - 10^20");
059                    decimalScale = Math.pow(10, val);
060            }
061    
062            public int getIndividualSize() {
063                    return individualSize;
064            }
065    
066            public void setIndividualSize(int size) {
067                    RangeConstraint [] newConstraints = new RangeConstraint[size];
068    
069                    for (int i = 0; i < Math.min(size, this.individualSize); i++)
070                            newConstraints[i] = this.constraints[i];
071    
072                    for (int i = Math.min(size, this.individualSize); i < size; i++)
073                            newConstraints[i] = null;
074    
075                    this.individualSize = size;
076                    this.constraints = newConstraints;
077            }
078    
079            /**
080             * Gets the constraint for individuals' variable with specified index.
081             *
082             * @param variableIndex the index of the variable inside the individuals to
083             * which the constraint applies.
084             *
085             * @return the constraint vor variables at the specified index.
086             */
087            public RangeConstraint getConstraint(int variableIndex) {
088                    return constraints[variableIndex];
089            }
090    
091            /**
092             * Sets the constraints for individuals' variable at the specified index.
093             *
094             * @param variableIndex index of the variable to which the consteraint applies.
095             * @param constraint the constraint.
096             */
097            public void setConstraint(int variableIndex, RangeConstraint constraint) {
098                    constraints[variableIndex] = constraint;
099            }
100    
101            public int getPrecision() {
102                    return precision;
103            }
104    
105            public void setPrecision(int val) {
106                    precision = val;
107            }
108    
109            /**
110             * Checks if the values of the specified individual are in the ranges
111             * specified by constraints of this factory.
112             *
113             * @param indiv some individual
114             *
115             * @return <code>true</code> if all values encoded by this individual are inside the
116             * ranges specified by the constrains applicable to this factory;
117             * <code>false</code> otherwise.
118             */
119            public boolean valid(NDecimalsIndividual indiv) {
120    
121                    // check if individual's settings match this factiory:
122                    if (indiv.getDecimalScale() != this.getDecimalScale()
123                                    || indiv.getSize() != this.getIndividualSize()
124                                    || indiv.getPrecision() != this.getPrecision()) {
125                            throw new IllegalArgumentException("The given individual (" + indiv
126                                                                                             + ") is likely not created by this factory.");
127                    }
128    
129                    // check all values of the individual:
130                    for (int i = 0; i < indiv.getSize(); i++) {
131                            double minmax[] = getAllowedRange(i);
132                            double val = indiv.getDoubleValue(i);
133                            if (val < minmax[0])
134                                    return false;
135                            if (val > minmax[1])
136                                    return false;
137                    }
138                    return true;
139            }
140    
141            public Individual createDefaultIndividual(GAParameterSet params) {
142                    // Create a default individual:
143                    NDecimalsIndividual indiv = new NDecimalsIndividual(individualSize, decimalScale, precision);
144    
145                    // If some value is out of range, set it in the middle of range:
146                    for (int valInd = 0; valInd < individualSize; valInd++) {
147                            double [] minmax = getAllowedRange(valInd);
148                            if (indiv.getDoubleValue(valInd) < minmax[0] || minmax[1] < indiv.getDoubleValue(valInd)) {
149                                    double val = 0.5 * minmax[0] + 0.5 * minmax[1];
150                                    indiv.setDoubleValue(valInd, val);
151                            }
152                    }
153    
154                    return indiv;
155            }
156    
157            public Individual createRandomIndividual(GAParameterSet params) {
158                    // create an individual:
159                    NDecimalsIndividual indiv = new NDecimalsIndividual(individualSize, decimalScale, precision);
160    
161                    // set all values to uniformly distributed random values:
162                    for (int valInd = 0; valInd < individualSize; valInd++) {
163                            double [] minmax = getAllowedRange(valInd);
164                            double val = params.getRandomGenerator().nextDouble(minmax[0], minmax[1]);
165                            indiv.setDoubleValue(valInd, val);
166                    }
167                    return indiv;
168            }
169    
170            public Individual createSpecificIndividual(Object init, GAParameterSet params) {
171    
172                    if (null == init)
173                            throw new NullPointerException("Initialisation value for NDecimalsIndividual my not be null");
174    
175                    if (init instanceof NDecimalsIndividual)
176                            return createSpecificIndividual((NDecimalsIndividual) init);
177    
178                    if (init instanceof BitString)
179                                            return createSpecificIndividual((BitString) init);
180    
181                    if (init instanceof BitString)
182                                            return createSpecificIndividual((BitString) init);
183    
184                    if (init instanceof double [])
185                            return createSpecificIndividual((double []) init);
186    
187                    throw new ClassCastException("Initialisation value for NDecimalsIndividual "
188                                                                             + "must be of type BitString or Double (but is "
189                                                                             + init.getClass() + ")");
190            }
191    
192            public Individual createSpecificIndividual(NDecimalsIndividual initVal) {
193                    NDecimalsIndividual indiv = new NDecimalsIndividual(individualSize, decimalScale, precision);
194                    indiv.setBitStringRepresentation(initVal.getBitStringRepresentation());
195                    return indiv;
196            }
197    
198            public Individual createSpecificIndividual(BitString initVal) {
199                    NDecimalsIndividual indiv = new NDecimalsIndividual(individualSize, decimalScale, precision);
200                    indiv.setBitStringRepresentation(initVal);
201                    return indiv;
202            }
203    
204            public Individual createSpecificIndividual(double [] initVal) {
205                    NDecimalsIndividual indiv = new NDecimalsIndividual(individualSize, decimalScale, precision);
206                    for (int i = 0; i < individualSize; i++) {
207                            indiv.setDoubleValue(i, initVal[i]);
208                    }
209                    return indiv;
210            }
211    
212            private double [] getAllowedRange(int varInd) throws IllegalArgumentException {
213    
214                    // use these if no constraint applies:
215                    final double veryLargePositive = 0.99 * (Long.MAX_VALUE / decimalScale);
216                    final double veryLargeNegative = 0.99 * (Long.MIN_VALUE / decimalScale);
217    
218                    // get constraint:
219                    RangeConstraint constr = constraints[varInd];
220    
221                    // return range:
222                    if (null == constr)
223                            return new double[] {veryLargeNegative, veryLargePositive};
224    
225                    return new double [] {Math.max(constr.getMinValue(), veryLargeNegative),
226                                                              Math.min(constr.getMaxValue(), veryLargePositive)};
227            }
228    
229    }