001/*
002 * Java Genetic Algorithm Library (jenetics-8.1.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.prog.op;
021
022import static java.lang.Math.abs;
023import static java.lang.Math.acos;
024import static java.lang.Math.asin;
025import static java.lang.Math.atan;
026import static java.lang.Math.cbrt;
027import static java.lang.Math.ceil;
028import static java.lang.Math.cos;
029import static java.lang.Math.cosh;
030import static java.lang.Math.exp;
031import static java.lang.Math.floor;
032import static java.lang.Math.hypot;
033import static java.lang.Math.log;
034import static java.lang.Math.log10;
035import static java.lang.Math.max;
036import static java.lang.Math.min;
037import static java.lang.Math.pow;
038import static java.lang.Math.rint;
039import static java.lang.Math.signum;
040import static java.lang.Math.sin;
041import static java.lang.Math.sinh;
042import static java.lang.Math.sqrt;
043import static java.lang.Math.tan;
044import static java.lang.Math.tanh;
045import static java.util.Objects.requireNonNull;
046import static io.jenetics.prog.op.Numbers.box;
047
048import java.util.Objects;
049import java.util.Optional;
050import java.util.Set;
051import java.util.function.Function;
052import java.util.stream.Collectors;
053import java.util.stream.Stream;
054
055import io.jenetics.ext.util.Tree;
056import io.jenetics.ext.util.TreeNode;
057
058/**
059 * This class contains operations for performing basic numeric operations.
060 *
061 * @see Math
062 *
063 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
064 * @version 5.0
065 * @since 3.9
066 */
067public enum MathOp implements Op<Double> {
068
069
070        /* *************************************************************************
071         * Arithmetic operations
072         * ************************************************************************/
073
074        /**
075         * Return the absolute value of a double value.
076         * <em>This operation has arity 1.</em>
077         *
078         * @see Math#abs(double)
079         */
080        ABS("abs", 1, v -> abs(v[0])),
081
082        /**
083         * Return the negation value of a double value.
084         * <em>This operation has arity 1.</em>
085         */
086        NEG("neg", 1, v -> -v[0]),
087
088        /**
089         * The identity function.
090         */
091        ID("id", 1, v -> v[0]),
092
093        /**
094         * Return the minimum of two values.
095         * <em>This operation has arity 2.</em>
096         *
097         * @see Math#min(double, double)
098         */
099        MIN("min", 2, v -> min(v[0], v[1])),
100
101        /**
102         * Return the maximum of two values
103         * <em>This operation has arity 2.</em>
104         *
105         * @see Math#max(double, double)
106         */
107        MAX("max", 2, v -> max(v[0], v[1])),
108
109        /**
110         * Returns the smallest (closest to negative infinity) double value that is
111         * greater than or equal to the argument and is equal to a mathematical
112         * integer.
113         * <em>This operation has arity 1.</em>
114         *
115         * @see Math#ceil(double)
116         */
117        CEIL("ceil", 1, v -> ceil(v[0])),
118
119        /**
120         * Returns the largest (closest to positive infinity) double value that is
121         * less than or equal to the argument and is equal to a mathematical integer.
122         * <em>This operation has arity 1.</em>
123         *
124         * @see Math#floor(double)
125         */
126        FLOOR("floor", 1, v -> floor(v[0])),
127
128        /**
129         * Returns the signum function of the argument; zero if the argument is
130         * zero, 1.0 if the argument is greater than zero, -1.0 if the argument is
131         * less than zero.
132         * <em>This operation has arity 1.</em>
133         *
134         * @see Math#signum(double)
135         */
136        SIGNUM("signum", 1, v -> signum(v[0])),
137
138        /**
139         * Returns the double value that is closest in value to the argument and is
140         * equal to a mathematical integer.
141         * <em>This operation has arity 1.</em>
142         *
143         * @see Math#rint(double)
144         */
145        RINT("rint", 1, v -> rint(v[0])),
146
147        /**
148         * Returns the sum of its arguments.
149         * <em>This operation has arity 2.</em>
150         */
151        ADD("add", 2, v -> v[0] + v[1]),
152
153        /**
154         * Return the diff of its arguments.
155         * <em>This operation has arity 2.</em>
156         */
157        SUB("sub", 2, v -> v[0] - v[1]),
158
159        /**
160         * Returns the product of its arguments.
161         * <em>This operation has arity 2.</em>
162         */
163        MUL("mul", 2, v -> v[0]*v[1]),
164
165        /**
166         * Returns the quotient of its arguments.
167         * <em>This operation has arity 2.</em>
168         */
169        DIV("div", 2, v -> v[0]/v[1]),
170
171        /**
172         * Returns the modulo of its arguments.
173         * <em>This operation has arity 2.</em>
174         */
175        MOD("mod", 2, v -> v[0]%v[1]),
176
177        /**
178         * Returns the value of the first argument raised to the power of the second
179         * argument.
180         * <em>This operation has arity 2.</em>
181         *
182         * @see Math#pow(double, double)
183         */
184        POW("pow", 2, v -> pow(v[0], v[1])),
185
186        /**
187         * Returns the square value of a given double value.
188         * <em>This operation has arity 1.</em>
189         */
190        SQR("sqr", 1, v -> v[0]*v[0]),
191
192        /**
193         * Returns the correctly rounded positive square root of a double value.
194         * <em>This operation has arity 1.</em>
195         *
196         * @see Math#sqrt(double)
197         */
198        SQRT("sqrt", 1, v -> sqrt(v[0])),
199
200        /**
201         * Returns the cube root of a double value.
202         * <em>This operation has arity 1.</em>
203         *
204         * @see Math#cbrt(double)
205         */
206        CBRT("cbrt", 1, v -> cbrt(v[0])),
207
208        /**
209         * Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>) without
210         * intermediate overflow or underflow.
211         * <em>This operation has arity 2.</em>
212         *
213         * @see Math#hypot(double, double)
214         */
215        HYPOT("hypot", 2, v -> hypot(v[0], v[1])),
216
217
218        /* *************************************************************************
219         * Exponential/logarithmic operations
220         * ************************************************************************/
221
222        /**
223         * Returns Euler's number e raised to the power of a double value.
224         * <em>This operation has arity 1.</em>
225         *
226         * @see Math#exp(double)
227         */
228        EXP("exp", 1, v -> exp(v[0])),
229
230        /**
231         * Returns the natural logarithm (base e) of a double value.
232         * <em>This operation has arity 1.</em>
233         *
234         * @see Math#log(double)
235         */
236        LOG("log", 1, v -> log(v[0])),
237
238        /**
239         * Returns the base 10 logarithm of a double value.
240         * <em>This operation has arity 1.</em>
241         *
242         * @see Math#log10(double)
243         */
244        LOG10("log10", 1, v -> log10(v[0])),
245
246
247        /* *************************************************************************
248         * Trigonometric operations
249         * ************************************************************************/
250
251        /**
252         * Returns the trigonometric sine of an angle.
253         * <em>This operation has arity 1.</em>
254         *
255         * @see Math#sin(double)
256         */
257        SIN("sin", 1, v -> sin(v[0])),
258
259        /**
260         * Returns the trigonometric cosine of an angle.
261         * <em>This operation has arity 1.</em>
262         *
263         * @see Math#cos(double)
264         */
265        COS("cos", 1, v -> cos(v[0])),
266
267        /**
268         * Returns the trigonometric tangent of an angle.
269         * <em>This operation has arity 1.</em>
270         *
271         * @see Math#tan(double)
272         */
273        TAN("tan", 1, v -> tan(v[0])),
274
275        /**
276         * Returns the arc cosine of a double value.
277         * <em>This operation has arity 1.</em>
278         *
279         * @see Math#acos(double)
280         */
281        ACOS("acos", 1, v -> acos(v[0])),
282
283        /**
284         * Returns the arc sine of a double value.
285         * <em>This operation has arity 1.</em>
286         *
287         * @see Math#asin(double)
288         */
289        ASIN("asin", 1, v -> asin(v[0])),
290
291        /**
292         * Returns the arc tangent of a value.
293         * <em>This operation has arity 1.</em>
294         *
295         * @see Math#atan(double)
296         */
297        ATAN("atan", 1, v -> atan(v[0])),
298
299        /**
300         * Returns the hyperbolic cosine of a double value.
301         * <em>This operation has arity 1.</em>
302         *
303         * @see Math#cosh(double)
304         */
305        COSH("cosh", 1, v -> cosh(v[0])),
306
307        /**
308         * Returns the hyperbolic sine of a double value.
309         * <em>This operation has arity 1.</em>
310         *
311         * @see Math#sinh(double)
312         */
313        SINH("sinh", 1, v -> sinh(v[0])),
314
315        /**
316         * Returns the hyperbolic tangent of a double value.
317         * <em>This operation has arity 1.</em>
318         *
319         * @see Math#tanh(double)
320         */
321        TANH("tanh", 1, v -> tanh(v[0])),
322
323        /* *************************************************************************
324         * Conditional functions
325         * ************************************************************************/
326
327        /**
328         * Returns +1.0 if its first argument is greater than its second argument
329         * and returns -1.0 otherwise.
330         *
331         * @since 5.0
332         */
333        GT("gt", 2, v -> v[0] > v[1] ? 1.0 : -1.0);
334
335        /* *************************************************************************
336         * Additional mathematical constants.
337         * ************************************************************************/
338
339        /**
340         * The double value that is closer than any other to pi, the ratio of the
341         * circumference of a circle to its diameter. <em>This is a terminal
342         * operation.</em>
343         *
344         * @see Math#PI
345         */
346        public static final Const<Double> PI = Const.of("π", Math.PI);
347
348        /**
349         * The double value that is closer than any other to e, the base of the
350         * natural logarithms. <em>This is a terminal operation.</em>
351         *
352         * @see Math#E
353         */
354        public static final Const<Double> E = Const.of("e", Math.E);
355
356        /**
357         * The names of all defined operation names.
358         *
359         * @since 7.0
360         */
361        public static final Set<String> NAMES = Stream.of(MathOp.values())
362                .map(MathOp::toString)
363                .collect(Collectors.toUnmodifiableSet());
364
365        private final String _name;
366        private final int _arity;
367        private final Function<Double[], Double> _function;
368
369        MathOp(
370                final String name,
371                final int arity,
372                final Function<Double[], Double> function
373        ) {
374                assert name != null;
375                assert arity >= 0;
376                assert function != null;
377
378                _name = name;
379                _function = function;
380                _arity = arity;
381        }
382
383        @Override
384        public int arity() {
385                return _arity;
386        }
387
388        @Override
389        public Double apply(final Double[] args) {
390                return _function.apply(args);
391        }
392
393        /**
394         * Evaluates the operation with the given arguments.
395         *
396         * @since 5.0
397         *
398         * @see #apply(Double[])
399         *
400         * @param args the operation arguments
401         * @return the evaluated operation
402         */
403        public double eval(final double... args) {
404                return apply(box(args));
405        }
406
407        @Override
408        public String toString() {
409                return _name;
410        }
411
412        /**
413         * Converts the string representation of an operation to the operation
414         * object. It is used for converting the string representation of a tree to
415         * an operation tree. <b>If you use it that way, you should not forget to
416         * re-index the tree variables.</b>
417         *
418         * {@snippet lang="java":
419         * final TreeNode<Op<Double>> tree = TreeNode.parse(
420         *     "add(mul(x,y),sub(y,x))",
421         *     MathOp::toMathOp
422         * );
423         *
424         * assert Program.eval(tree, 10.0, 5.0) == 100.0;
425         * Var.reindex(tree);
426         * assert Program.eval(tree, 10.0, 5.0) == 45.0;
427         * }
428         *
429         * @since 5.0
430         *
431         * @see Var#reindex(TreeNode)
432         * @see Program#eval(Tree, Object[])
433         *
434         * @param string the string representation of an operation which should be
435         *        converted
436         * @return the operation, converted from the given string
437         * @throws IllegalArgumentException if the given {@code value} doesn't
438         *         represent a mathematical expression
439         * @throws NullPointerException if the given string {@code value} is
440         *         {@code null}
441         */
442        public static Op<Double> toMathOp(final String string) {
443                requireNonNull(string);
444
445                final Op<Double> result;
446                final Optional<Const<Double>> cop = toConst(string);
447                if (cop.isPresent()) {
448                        result = cop.orElseThrow(AssertionError::new);
449                } else {
450                        final Optional<Op<Double>> mop = toOp(string);
451                        result = mop.isPresent()
452                                ? mop.orElseThrow(AssertionError::new)
453                                : Var.parse(string);
454                }
455
456                return result;
457        }
458
459        static Optional<Const<Double>> toConst(final String string) {
460                return Numbers.toDoubleOptional(string)
461                        .map(Const::of);
462        }
463
464        private static Optional<Op<Double>> toOp(final String string) {
465                return Stream.of(values())
466                        .filter(op -> Objects.equals(op._name, string))
467                        .map(op -> (Op<Double>)op)
468                        .findFirst();
469        }
470
471}