001/*
002 * Java Genetic Algorithm Library (jenetics-8.0.0).
003 * Copyright (c) 2007-2024 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 */
020package io.jenetics.ext.moea;
021
022import java.util.Comparator;
023import java.util.List;
024
025import io.jenetics.Optimize;
026
027/**
028 * This interface allows creating a 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 * {@snippet lang="java":
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 * }
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
060public 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 don'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 don'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 don'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 don'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 don'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 don'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 don'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 don'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 don'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 don'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 don'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 don'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 don'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}