001 /*
002 * Java Genetic Algorithm Library (jenetics-7.1.1).
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> +<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 * <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 }
|