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> +<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}