VecFactory.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.3.0).
003  * Copyright (c) 2007-2021 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.ext.moea;
021 
022 import java.util.Comparator;
023 import java.util.List;
024 
025 import io.jenetics.Optimize;
026 
027 /**
028  * This interface allows to create vector object from a given array type
029  * {@code T}. It is useful if you need some additional parametrization of the
030  * created vectors.
031  <p>
032  * As the following example shows, only one {@code VecFactory} instance should
033  * be used for creating the vectors for a given multi-objective <em>problem</em>.
034  <pre>{@code
035  * private static final VecFactory<double[]> FACTORY = VecFactory.ofDoubleVec(
036  *     Optimize.MAXIMUM,
037  *     Optimize.MINIMUM,
038  *     Optimize.MINIMUM,
039  *     Optimize.MAXIMUM
040  * );
041  *
042  * // The fitness function.
043  * static Vec<double[]> fitness(final double[] x) {
044  *     final double[] result = new double[4];
045  *     // ...
046  *     return FACTORY.newVec(result);
047  * }
048  * }</pre>
049  * In the example above, the first dimension of the created vector is maximized,
050  * the following two are minimized and the last vector component is again
051  * maximized.
052  *
053  @see Vec
054  *
055  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
056  @version 6.0
057  @since 5.2
058  */
059 @FunctionalInterface
060 public interface VecFactory<T> {
061 
062     /**
063      * Create a new {@link Vec} object from the given {@code array}.
064      *
065      @param array the array used in the created vector
066      @return a new {@link Vec} object from the given {@code array}
067      @throws NullPointerException if the given {@code array} is {@code null}
068      @throws IllegalArgumentException if the {@code array} length is zero or
069      *         doesn't match the required length of the actual factory
070      */
071     Vec<T> newVec(final T array);
072 
073     /**
074      * Create a new factory for {@code int[]} vectors. Additionally you can
075      * specify the optimization direction (maximization or minimization) for
076      * each dimension. The dimensionality of the created vectors must be exactly
077      * the same as the given length of the given {@code optimizes}. If the
078      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
079      *
080      @see #ofIntVec(Optimize...)
081      *
082      * @apiNote
083      * Only one factory instance should be used for a given multi-objective
084      <em>problem</em>.
085      *
086      @param optimizes the optimization <em>direction</em> for each dimension
087      @return a new factory for {@code int[]} vectors
088      @throws NullPointerException if the given {@code optimizes} is
089      *         {@code null}
090      @throws IllegalArgumentException if the {@code optimizes} length is zero
091      */
092     static VecFactory<int[]> ofIntVec(final List<Optimize> optimizes) {
093         return new GeneralIntVecFactory(optimizes);
094     }
095 
096     /**
097      * Create a new factory for {@code int[]} vectors. Additionally you can
098      * specify the optimization direction (maximization or minimization) for
099      * each dimension. The dimensionality of the created vectors must be exactly
100      * the same as the given length of the given {@code optimizes}. If the
101      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
102      *
103      @see #ofIntVec(List)
104      *
105      * @apiNote
106      * Only one factory instance should be used for a given multi-objective
107      <em>problem</em>.
108      *
109      @param optimizes the optimization <em>direction</em> for each dimension
110      @return a new factory for {@code int[]} vectors
111      @throws NullPointerException if the given {@code optimizes} is
112      *         {@code null}
113      @throws IllegalArgumentException if the {@code optimizes} length is zero
114      */
115     static VecFactory<int[]> ofIntVec(final Optimize... optimizes) {
116         return ofIntVec(List.of(optimizes));
117     }
118 
119     /**
120      * Create a new factory for {@code int[]} vectors, where all dimensions are
121      * maximized.
122      *
123      @see Vec#of(int...)
124      *
125      @return a new factory for {@code int[]} vectors, where all dimensions are
126      *            maximized
127      */
128     static VecFactory<int[]> ofIntVec() {
129         return Vec::of;
130     }
131 
132     /**
133      * Create a new factory for {@code long[]} vectors. Additionally you can
134      * specify the optimization direction (maximization or minimization) for
135      * each dimension. The dimensionality of the created vectors must be exactly
136      * the same as the given length of the given {@code optimizes}. If the
137      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
138      *
139      @see #ofLongVec(Optimize...)
140      *
141      * @apiNote
142      * Only one factory instance should be used for a given multi-objective
143      <em>problem</em>.
144      *
145      @param optimizes the optimization <em>direction</em> for each dimension
146      @return a new factory for {@code long[]} vectors
147      @throws NullPointerException if the given {@code optimizes} is
148      *         {@code null}
149      @throws IllegalArgumentException if the {@code optimizes} length is zero
150      */
151     static VecFactory<long[]> ofLongVec(final List<Optimize> optimizes) {
152         return new GeneralLongVecFactory(optimizes);
153     }
154 
155     /**
156      * Create a new factory for {@code long[]} vectors. Additionally you can
157      * specify the optimization direction (maximization or minimization) for
158      * each dimension. The dimensionality of the created vectors must be exactly
159      * the same as the given length of the given {@code optimizes}. If the
160      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
161      *
162      @see #ofLongVec(List)
163      *
164      * @apiNote
165      * Only one factory instance should be used for a given multi-objective
166      <em>problem</em>.
167      *
168      @param optimizes the optimization <em>direction</em> for each dimension
169      @return a new factory for {@code long[]} vectors
170      @throws NullPointerException if the given {@code optimizes} is
171      *         {@code null}
172      @throws IllegalArgumentException if the {@code optimizes} length is zero
173      */
174     static VecFactory<long[]> ofLongVec(final Optimize... optimizes) {
175         return ofLongVec(List.of(optimizes));
176     }
177 
178     /**
179      * Create a new factory for {@code long[]} vectors, where all dimensions are
180      * maximized.
181      *
182      @see Vec#of(long...)
183      *
184      @return a new factory for {@code long[]} vectors, where all dimensions are
185      *            maximized
186      */
187     static VecFactory<long[]> ofLongVec() {
188         return Vec::of;
189     }
190 
191     /**
192      * Create a new factory for {@code double[]} vectors. Additionally you can
193      * specify the optimization direction (maximization or minimization) for
194      * each dimension. The dimensionality of the created vectors must be exactly
195      * the same as the given length of the given {@code optimizes}. If the
196      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
197      *
198      @see #ofDoubleVec(Optimize...)
199      *
200      * @apiNote
201      * Only one factory instance should be used for a given multi-objective
202      <em>problem</em>.
203      *
204      @param optimizes the optimization <em>direction</em> for each dimension
205      @return a new factory for {@code double[]} vectors
206      @throws NullPointerException if the given {@code optimizes} is
207      *         {@code null}
208      @throws IllegalArgumentException if the {@code optimizes} length is zero
209      */
210     static VecFactory<double[]> ofDoubleVec(final List<Optimize> optimizes) {
211         return new GeneralDoubleVecFactory(optimizes);
212     }
213 
214     /**
215      * Create a new factory for {@code double[]} vectors. Additionally you can
216      * specify the optimization direction (maximization or minimization) for
217      * each dimension. The dimensionality of the created vectors must be exactly
218      * the same as the given length of the given {@code optimizes}. If the
219      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
220      *
221      @see #ofDoubleVec(List)
222      *
223      * @apiNote
224      * Only one factory instance should be used for a given multi-objective
225      <em>problem</em>.
226      *
227      @param optimizes the optimization <em>direction</em> for each dimension
228      @return a new factory for {@code double[]} vectors
229      @throws NullPointerException if the given {@code optimizes} is
230      *         {@code null}
231      @throws IllegalArgumentException if the {@code optimizes} length is zero
232      */
233     static VecFactory<double[]> ofDoubleVec(final Optimize... optimizes) {
234         return ofDoubleVec(List.of(optimizes));
235     }
236 
237     /**
238      * Create a new factory for {@code double[]} vectors, where all dimensions
239      * are maximized.
240      *
241      @see Vec#of(double...)
242      *
243      @return a new factory for {@code double[]} vectors, where all dimensions
244      *         are maximized
245      */
246     static VecFactory<double[]> ofDoubleVec() {
247         return Vec::of;
248     }
249 
250     /**
251      * Create a new factory for {@code T[]} vectors. Additionally you can
252      * specify the optimization direction (maximization or minimization) for
253      * each dimension. The dimensionality of the created vectors must be exactly
254      * the same as the given length of the given {@code optimizes}. If the
255      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
256      *
257      @see #ofObjectVec(Comparator, ElementDistance, Optimize...)
258      *
259      @param comparator the array element comparator
260      @param distance the element distance function
261      @param optimizes the optimization <em>direction</em> for each dimension
262      @param <T> the array element type
263      @return  a new factory for {@code T[]} vectors
264      @throws NullPointerException if one of the arguments is {@code null}
265      @throws IllegalArgumentException if the {@code optimizes} length is zero
266      */
267     static <T> VecFactory<T[]> ofObjectVec(
268         final Comparator<? super T> comparator,
269         final ElementDistance<T[]> distance,
270         final List<Optimize> optimizes
271     ) {
272         return new GeneralObjectVecFactory<>(comparator, distance, optimizes);
273     }
274 
275     /**
276      * Create a new factory for {@code T[]} vectors. Additionally you can
277      * specify the optimization direction (maximization or minimization) for
278      * each dimension. The dimensionality of the created vectors must be exactly
279      * the same as the given length of the given {@code optimizes}. If the
280      * lengths doesn't match, an {@link IllegalArgumentException} is thrown.
281      *
282      @see #ofObjectVec(Comparator, ElementDistance, List)
283      *
284      @param comparator the array element comparator
285      @param distance the element distance function
286      @param optimizes the optimization <em>direction</em> for each dimension
287      @param <T> the array element type
288      @return  a new factory for {@code T[]} vectors
289      @throws NullPointerException if one of the arguments is {@code null}
290      @throws IllegalArgumentException if the {@code optimizes} length is zero
291      */
292     static <T> VecFactory<T[]> ofObjectVec(
293         final Comparator<? super T> comparator,
294         final ElementDistance<T[]> distance,
295         final Optimize... optimizes
296     ) {
297         return ofObjectVec(comparator, distance, List.of(optimizes));
298     }
299 
300     /**
301      * Create a new factory for {@code T[]} vectors with comparable element
302      * types. Additionally you can specify the optimization direction
303      * (maximization or minimization) for each dimension. The dimensionality of
304      * the created vectors must be exactly the same as the given length of the
305      * given {@code optimizes}. If the lengths doesn't match, an
306      {@link IllegalArgumentException} is thrown.
307      *
308      @since 6.0
309      *
310      @see #ofObjectVec(Comparator, ElementDistance, List)
311      *
312      @param distance the element distance function
313      @param optimizes the optimization <em>direction</em> for each dimension
314      @param <T> the array element type
315      @return a new factory for {@code T[]} vectors
316      @throws NullPointerException if one of the arguments is {@code null}
317      @throws IllegalArgumentException if the {@code optimizes} length is zero
318      */
319     static <T extends Comparable<? super T>> VecFactory<T[]> ofObjectVec(
320         final ElementDistance<T[]> distance,
321         final List<Optimize> optimizes
322     ) {
323         return ofObjectVec(
324             Comparator.naturalOrder(),
325             distance,
326             optimizes
327         );
328     }
329 
330     /**
331      * Create a new factory for {@code T[]} vectors with comparable element
332      * types. Additionally you can specify the optimization direction
333      * (maximization or minimization) for each dimension. The dimensionality of
334      * the created vectors must be exactly the same as the given length of the
335      * given {@code optimizes}. If the lengths doesn't match, an
336      {@link IllegalArgumentException} is thrown.
337      *
338      @since 6.0
339      *
340      @see #ofObjectVec(Comparator, ElementDistance, List)
341      *
342      @param distance the element distance function
343      @param optimizes the optimization <em>direction</em> for each dimension
344      @param <T> the array element type
345      @return a new factory for {@code T[]} vectors
346      @throws NullPointerException if one of the arguments is {@code null}
347      @throws IllegalArgumentException if the {@code optimizes} length is zero
348      */
349     static <T extends Comparable<? super T>> VecFactory<T[]> ofObjectVec(
350         final ElementDistance<T[]> distance,
351         final Optimize... optimizes
352     ) {
353         return ofObjectVec(
354             Comparator.naturalOrder(),
355             distance,
356             optimizes
357         );
358     }
359 
360     /**
361      * Create a new factory for {@code T[]} vectors with comparable element
362      * types. Additionally you can specify the optimization direction
363      * (maximization or minimization) for each dimension. The dimensionality of
364      * the created vectors must be exactly the same as the given length of the
365      * given {@code optimizes}. If the lengths doesn't match, an
366      {@link IllegalArgumentException} is thrown.
367      *
368      @since 6.0
369      *
370      @see #ofObjectVec(Comparator, ElementDistance, List)
371      *
372      @param optimizes the optimization <em>direction</em> for each dimension
373      @param <T> the array element type
374      @return a new factory for {@code T[]} vectors
375      @throws NullPointerException if one of the arguments is {@code null}
376      @throws IllegalArgumentException if the {@code optimizes} length is zero
377      */
378     static <T extends Comparable<? super T>> VecFactory<T[]>
379     ofObjectVec(final List<Optimize> optimizes) {
380         return ofObjectVec(VecFactory::dist, optimizes);
381     }
382 
383     private static <T extends Comparable<? super T>>
384     double dist(final T[] u, final T[] v, final int i) {
385         return Integer.compare(u[i].compareTo(v[i])0);
386     }
387 
388     /**
389      * Create a new factory for {@code T[]} vectors with comparable element
390      * types. Additionally you can specify the optimization direction
391      * (maximization or minimization) for each dimension. The dimensionality of
392      * the created vectors must be exactly the same as the given length of the
393      * given {@code optimizes}. If the lengths doesn't match, an
394      {@link IllegalArgumentException} is thrown.
395      *
396      @since 6.0
397      *
398      @see #ofObjectVec(Comparator, ElementDistance, List)
399      *
400      @param optimizes the optimization <em>direction</em> for each dimension
401      @param <T> the array element type
402      @return a new factory for {@code T[]} vectors
403      @throws NullPointerException if one of the arguments is {@code null}
404      @throws IllegalArgumentException if the {@code optimizes} length is zero
405      */
406     static <T extends Comparable<? super T>> VecFactory<T[]>
407     ofObjectVec(final Optimize... optimizes) {
408         return ofObjectVec(VecFactory::dist, optimizes);
409     }
410 
411     /**
412      * Create a new factory for {@code T[]} vectors with comparable element
413      * types. Additionally you can specify the optimization direction
414      * (maximization or minimization) for each dimension. The dimensionality of
415      * the created vectors must be exactly the same as the given length of the
416      * given {@code optimizes}. If the lengths doesn't match, an
417      {@link IllegalArgumentException} is thrown.
418      *
419      @since 6.0
420      *
421      @see Vec#of(Comparable[])
422      *
423      @param <T> the array element type
424      @return a new factory for {@code T[]} vectors
425      @throws NullPointerException if one of the arguments is {@code null}
426      @throws IllegalArgumentException if the {@code optimizes} length is zero
427      */
428     static <T extends Comparable<? super T>> VecFactory<T[]> ofObjectVec() {
429         return Vec::of;
430     }
431 
432 }