MathOp.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-7.1.0).
003  * Copyright (c) 2007-2022 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.prog.op;
021 
022 import static java.lang.Math.abs;
023 import static java.lang.Math.acos;
024 import static java.lang.Math.asin;
025 import static java.lang.Math.atan;
026 import static java.lang.Math.cbrt;
027 import static java.lang.Math.ceil;
028 import static java.lang.Math.cos;
029 import static java.lang.Math.cosh;
030 import static java.lang.Math.exp;
031 import static java.lang.Math.floor;
032 import static java.lang.Math.hypot;
033 import static java.lang.Math.log;
034 import static java.lang.Math.log10;
035 import static java.lang.Math.max;
036 import static java.lang.Math.min;
037 import static java.lang.Math.pow;
038 import static java.lang.Math.rint;
039 import static java.lang.Math.signum;
040 import static java.lang.Math.sin;
041 import static java.lang.Math.sinh;
042 import static java.lang.Math.sqrt;
043 import static java.lang.Math.tan;
044 import static java.lang.Math.tanh;
045 import static java.util.Objects.requireNonNull;
046 import static io.jenetics.prog.op.Numbers.box;
047 
048 import java.util.Objects;
049 import java.util.Optional;
050 import java.util.Set;
051 import java.util.function.Function;
052 import java.util.stream.Collectors;
053 import java.util.stream.Stream;
054 
055 import io.jenetics.ext.util.Tree;
056 import 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  */
067 public 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[11.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      <pre>{@code
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      * }</pre>
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 }