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