1 package net.bmahe.genetics4j.gp.math;
2
3 import java.util.Arrays;
4 import java.util.List;
5 import java.util.Objects;
6
7 import org.apache.commons.lang3.Validate;
8 import org.apache.logging.log4j.LogManager;
9 import org.apache.logging.log4j.Logger;
10
11 import net.bmahe.genetics4j.core.chromosomes.TreeNode;
12 import net.bmahe.genetics4j.gp.InputSpec;
13 import net.bmahe.genetics4j.gp.Operation;
14 import net.bmahe.genetics4j.gp.OperationFactories;
15 import net.bmahe.genetics4j.gp.OperationFactory;
16 import net.bmahe.genetics4j.gp.spec.mutation.ImmutableRule;
17 import net.bmahe.genetics4j.gp.spec.mutation.Rule;
18 import net.bmahe.genetics4j.gp.utils.TreeNodeUtils;
19
20 public class SimplificationRules {
21 public static final Logger logger = LogManager.getLogger(SimplificationRules.class);
22
23 public static final double DEFAULT_EPSILON = 0.0001;
24
25 protected static boolean isOperation(final TreeNode<Operation<?>> node, final String name) {
26 Objects.requireNonNull(node);
27 Validate.notBlank(name);
28 return name.equals(node.getData().getName());
29 }
30
31 protected static boolean hasChildOperation(final TreeNode<Operation<?>> node, final int childIndex,
32 final String name) {
33 Objects.requireNonNull(node);
34 Validate.isTrue(childIndex >= 0);
35 Validate.notBlank(name);
36
37 if (node.getChildren().size() <= childIndex) {
38 return false;
39 }
40
41 final TreeNode<Operation<?>> child = node.getChild(childIndex);
42 return name.equals(child.getData().getName());
43 }
44
45 @SuppressWarnings("unchecked")
46 protected static <T> T getChildAs(final TreeNode<Operation<?>> node, final int childIndex, final Class<T> clazz) {
47 final TreeNode<Operation<?>> child = node.getChild(childIndex);
48 final Operation<?> operation = child.getData();
49 return (T) operation;
50 }
51
52 protected static boolean isEqual(final double v1, final double v2, final double epsilon) {
53 Validate.isTrue(epsilon >= 0);
54
55 return Math.abs(v2 - v1) < epsilon;
56 }
57
58 protected static boolean isEqual(final double v1, final double v2) {
59 return isEqual(v1, v2, DEFAULT_EPSILON);
60 }
61
62 @SuppressWarnings("unchecked")
63 public static final Rule ADD_TWO_COEFFCIENTS = ImmutableRule.of(
64 t -> isOperation(t, Functions.NAME_ADD) && hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT)
65 && hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT),
66 (program, t) -> {
67
68 final InputSpec inputSpec = program.inputSpec();
69
70 final CoefficientOperation<Double> firstCoefficient = getChildAs(t, 0, CoefficientOperation.class);
71 final Double firstValue = firstCoefficient.value();
72
73 final CoefficientOperation<Double> secondCoefficient = getChildAs(t, 1, CoefficientOperation.class);
74 final Double secondValue = secondCoefficient.value();
75
76 final OperationFactory coefficientFactory = OperationFactories
77 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, firstValue + secondValue);
78
79 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
80
81 return new TreeNode<>(newOperation);
82 });
83
84 @SuppressWarnings("unchecked")
85 public static final Rule MUL_TWO_COEFFICIENTS = ImmutableRule.of(
86 t -> isOperation(t, Functions.NAME_MUL) && hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT)
87 && hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT),
88 (program, t) -> {
89
90 final InputSpec inputSpec = program.inputSpec();
91
92 final CoefficientOperation<Double> firstCoefficient = getChildAs(t, 0, CoefficientOperation.class);
93 final Double firstValue = firstCoefficient.value();
94
95 final CoefficientOperation<Double> secondCoefficient = getChildAs(t, 1, CoefficientOperation.class);
96 final Double secondValue = secondCoefficient.value();
97
98 final OperationFactory coefficientFactory = OperationFactories
99 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, firstValue * secondValue);
100
101 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
102
103 return new TreeNode<>(newOperation);
104 });
105
106 @SuppressWarnings("unchecked")
107 public static final Rule SUB_TWO_COEFFICIENTS = ImmutableRule.of(
108 t -> isOperation(t, Functions.NAME_SUB) && hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT)
109 && hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT),
110 (program, t) -> {
111
112 final InputSpec inputSpec = program.inputSpec();
113
114 final CoefficientOperation<Double> firstCoefficient = getChildAs(t, 0, CoefficientOperation.class);
115 final Double firstValue = firstCoefficient.value();
116
117 final CoefficientOperation<Double> secondCoefficient = getChildAs(t, 1, CoefficientOperation.class);
118 final Double secondValue = secondCoefficient.value();
119
120 final OperationFactory coefficientFactory = OperationFactories
121 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, firstValue - secondValue);
122
123 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
124
125 return new TreeNode<>(newOperation);
126 });
127
128 @SuppressWarnings("unchecked")
129 public static final Rule SUB_INPUT_FROM_SAME_INPUT = ImmutableRule.of(t -> {
130 if (isOperation(t, Functions.NAME_SUB) == false) {
131 return false;
132 }
133
134 if (hasChildOperation(t, 0, Terminals.TYPE_INPUT) == false) {
135 return false;
136 }
137
138 if (hasChildOperation(t, 1, Terminals.TYPE_INPUT) == false) {
139 return false;
140 }
141
142 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
143
144 final InputOperation<?> secondInput = (InputOperation<Double>) t.getChild(1).getData();
145
146 return firstInput.index() == secondInput.index();
147 }, (program, t) -> {
148
149 final InputSpec inputSpec = program.inputSpec();
150
151 final OperationFactory coefficientFactory = OperationFactories
152 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
153
154 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
155
156 return new TreeNode<>(newOperation);
157 });
158
159 @SuppressWarnings("unchecked")
160 public static final Rule SUB_ZERO_FROM_INPUT = ImmutableRule.of(t -> {
161 if (isOperation(t, Functions.NAME_SUB) == false) {
162 return false;
163 }
164
165 if (hasChildOperation(t, 0, Terminals.TYPE_INPUT) == false) {
166 return false;
167 }
168
169 if (hasChildOperation(t, 1, Terminals.TYPE_INPUT) == false) {
170 return false;
171 }
172
173 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
174 return false;
175 }
176
177 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
178 return false;
179 }
180
181 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
182
183 return isEqual(firstCoefficient.value(), 0.0d);
184 }, (program, t) -> {
185
186 final InputSpec inputSpec = program.inputSpec();
187
188 final OperationFactory coefficientFactory = OperationFactories
189 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
190
191 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
192
193 return new TreeNode<>(newOperation);
194 });
195
196 @SuppressWarnings("unchecked")
197 public static final Rule DIV_TWO_COEFFICIENT_FINITE = ImmutableRule.of(t -> {
198 if (isOperation(t, Functions.NAME_DIV) == false) {
199 return false;
200 }
201
202 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
203 return false;
204 }
205
206 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
207 return false;
208 }
209
210 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
211
212 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
213
214 return Double.isFinite(firstCoefficient.value() / secondCoefficient.value());
215 }, (program, t) -> {
216
217 final InputSpec inputSpec = program.inputSpec();
218
219 final CoefficientOperation<Double> firstCoefficient = getChildAs(t, 0, CoefficientOperation.class);
220 final Double firstValue = firstCoefficient.value();
221
222 final CoefficientOperation<Double> secondCoefficient = getChildAs(t, 1, CoefficientOperation.class);
223 final Double secondValue = secondCoefficient.value();
224
225 final OperationFactory coefficientFactory = OperationFactories
226 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, firstValue / secondValue);
227
228 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
229
230 return new TreeNode<>(newOperation);
231 });
232
233 @SuppressWarnings("unchecked")
234 public static final Rule ADD_INPUT_TO_SAME_INPUT = ImmutableRule.of(t -> {
235 boolean result = isOperation(t, Functions.NAME_ADD) && hasChildOperation(t, 0, Terminals.TYPE_INPUT)
236 && hasChildOperation(t, 1, Terminals.TYPE_INPUT);
237
238 if (result == false) {
239 return false;
240 }
241
242 final InputOperation<?> firstInput = getChildAs(t, 0, InputOperation.class);
243 final InputOperation<?> secondInput = getChildAs(t, 1, InputOperation.class);
244
245 return firstInput.index() == secondInput.index();
246 }, (program, t) -> {
247
248 final InputSpec inputSpec = program.inputSpec();
249
250 final TreeNode<Operation<?>> multBaseTreeNode = new TreeNode<>(Functions.MUL.build(inputSpec));
251
252 final OperationFactory coefficientFactory = OperationFactories
253 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 2.0d);
254 final TreeNode<Operation<?>> timesTwoTreeNode = new TreeNode<>(coefficientFactory.build(inputSpec));
255 multBaseTreeNode.addChild(timesTwoTreeNode);
256
257 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
258 final TreeNode<Operation<?>> firstInputTreeNode = new TreeNode<>(firstInput);
259 multBaseTreeNode.addChild(firstInputTreeNode);
260
261 return multBaseTreeNode;
262 });
263
264 @SuppressWarnings("unchecked")
265 public static final Rule MULTIPLY_INPUT_WITH_SAME_INPUT = ImmutableRule.of(t -> {
266
267 if (isOperation(t, Functions.NAME_MUL) == false) {
268 return false;
269 }
270
271 if (hasChildOperation(t, 0, Terminals.TYPE_INPUT) == false) {
272 return false;
273 }
274 if (hasChildOperation(t, 1, Terminals.TYPE_INPUT) == false) {
275 return false;
276 }
277
278 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
279
280 final InputOperation<?> secondInput = (InputOperation<Double>) t.getChild(1).getData();
281
282 return firstInput.index() == secondInput.index();
283 }, (program, t) -> {
284
285 final InputSpec inputSpec = program.inputSpec();
286
287 final TreeNode<Operation<?>> expBaseTreeNode = new TreeNode<>(Functions.EXP.build(inputSpec));
288
289 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
290 final TreeNode<Operation<?>> firstInputTreeNode = new TreeNode<>(firstInput);
291 expBaseTreeNode.addChild(firstInputTreeNode);
292
293 final OperationFactory coefficientFactory = OperationFactories
294 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 2.0d);
295 final TreeNode<Operation<?>> twoTreeNode = new TreeNode<>(coefficientFactory.build(inputSpec));
296 expBaseTreeNode.addChild(twoTreeNode);
297
298 return expBaseTreeNode;
299 });
300
301 @SuppressWarnings("unchecked")
302 public static final Rule MULTIPLY_INPUT_WITH_EXP_SAME_INPUT_COEFF = ImmutableRule.of(t -> {
303
304
305 if (isOperation(t, Functions.NAME_MUL) == false) {
306 return false;
307 }
308 if (hasChildOperation(t, 0, Functions.NAME_EXP) == false) {
309 return false;
310 }
311 if (hasChildOperation(t, 1, Terminals.TYPE_INPUT) == false) {
312 return false;
313 }
314
315 final TreeNode<Operation<?>> expTreeNode = t.getChild(0);
316 if (hasChildOperation(expTreeNode, 0, Terminals.TYPE_INPUT) == false) {
317 return false;
318 }
319 if (hasChildOperation(expTreeNode, 1, Terminals.TYPE_COEFFICIENT) == false) {
320 return false;
321 }
322
323 final InputOperation<?> expInput = getChildAs(expTreeNode, 0, InputOperation.class);
324 final InputOperation<?> secondInput = getChildAs(t, 1, InputOperation.class);
325
326 return expInput.index() == secondInput.index();
327 }, (program, t) -> {
328
329 final InputSpec inputSpec = program.inputSpec();
330 final TreeNode<Operation<?>> originalExpTreeNode = t.getChild(0);
331 final CoefficientOperation<Double> originalCoefficientExp = getChildAs(
332 originalExpTreeNode,
333 1,
334 CoefficientOperation.class);
335
336 final TreeNode<Operation<?>> expBaseTreeNode = new TreeNode<>(Functions.EXP.build(inputSpec));
337
338 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
339 final TreeNode<Operation<?>> firstInputTreeNode = new TreeNode<>(firstInput);
340 expBaseTreeNode.addChild(firstInputTreeNode);
341
342 final OperationFactory coefficientFactory = OperationFactories
343 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, originalCoefficientExp.value() + 1.0d);
344 final TreeNode<Operation<?>> newCoeffTreeNode = new TreeNode<>(coefficientFactory.build(inputSpec));
345 expBaseTreeNode.addChild(newCoeffTreeNode);
346
347 return expBaseTreeNode;
348 });
349
350 @SuppressWarnings("unchecked")
351 public static final Rule MUL_1_WITH_ANYTHING = ImmutableRule.of(t -> {
352 if (isOperation(t, Functions.NAME_MUL) == false) {
353 return false;
354 }
355
356 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
357 return false;
358 }
359
360 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
361
362 return firstCoefficient.value() < 1 + 0.0001 && firstCoefficient.value() > 1 - .0001;
363 }, (program, t) -> t.getChild(1));
364
365 @SuppressWarnings("unchecked")
366 public static final Rule MUL_ANYTHING_WITH_1 = ImmutableRule.of(t -> {
367 if (isOperation(t, Functions.NAME_MUL) == false) {
368 return false;
369 }
370
371 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
372 return false;
373 }
374
375 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
376
377 return isEqual(secondCoefficient.value(), 1);
378 }, (program, t) -> t.getChild(0));
379
380 @SuppressWarnings("unchecked")
381 public static final Rule ADD_0_WITH_ANYTHING = ImmutableRule.of(t -> {
382 if (isOperation(t, Functions.NAME_ADD) == false) {
383 return false;
384 }
385
386 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
387 return false;
388 }
389
390 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
391
392 return isEqual(firstCoefficient.value(), 0.0d);
393 }, (program, t) -> t.getChild(1));
394
395 @SuppressWarnings("unchecked")
396 public static final Rule ADD_ANYTHING_WITH_0 = ImmutableRule.of(t -> {
397 if (isOperation(t, Functions.NAME_ADD) == false) {
398 return false;
399 }
400
401 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
402 return false;
403 }
404
405 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
406
407 return isEqual(secondCoefficient.value(), 0.0d);
408 }, (program, t) -> t.getChild(0));
409
410 @SuppressWarnings("unchecked")
411 public static final Rule MUL_0_WITH_ANYTHING = ImmutableRule.of(t -> {
412 if (isOperation(t, Functions.NAME_MUL) == false) {
413 return false;
414 }
415
416 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
417 return false;
418 }
419
420 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
421
422 return isEqual(firstCoefficient.value(), 0.0d);
423 }, (program, t) -> {
424
425 final InputSpec inputSpec = program.inputSpec();
426
427 final OperationFactory zeroFactory = OperationFactories
428 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
429
430 return new TreeNode<>(zeroFactory.build(inputSpec));
431 });
432
433 @SuppressWarnings("unchecked")
434 public static final Rule MUL_ANYTHING_WITH_0 = ImmutableRule.of(t -> {
435 if (isOperation(t, Functions.NAME_MUL) == false) {
436 return false;
437 }
438
439 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
440 return false;
441 }
442
443 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
444
445 return secondCoefficient.value() < 1 + 0.0001 && secondCoefficient.value() > 1 - .0001;
446 }, (program, t) -> {
447 final InputSpec inputSpec = program.inputSpec();
448
449 final OperationFactory zeroFactory = OperationFactories
450 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
451
452 return new TreeNode<>(zeroFactory.build(inputSpec));
453 });
454
455 @SuppressWarnings("unchecked")
456 public static final Rule POW_0 = ImmutableRule.of(t -> {
457 if (isOperation(t, Functions.NAME_POW) == false) {
458 return false;
459 }
460
461 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
462 return false;
463 }
464
465 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
466
467 return isEqual(secondCoefficient.value(), 0);
468 }, (program, t) -> {
469 final InputSpec inputSpec = program.inputSpec();
470
471 final OperationFactory oneFactory = OperationFactories
472 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 1.0d);
473
474 return new TreeNode<>(oneFactory.build(inputSpec));
475 });
476
477 @SuppressWarnings("unchecked")
478 public static final Rule POW_1 = ImmutableRule.of(t -> {
479 if (isOperation(t, Functions.NAME_POW) == false) {
480 return false;
481 }
482
483 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
484 return false;
485 }
486
487 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
488
489 return isEqual(secondCoefficient.value(), 1);
490 }, (program, t) -> t.getChild(0));
491
492 @SuppressWarnings("unchecked")
493 public static final Rule COS_OF_COEFFICIENT = ImmutableRule.of(t -> {
494 if (isOperation(t, Functions.NAME_COS) == false) {
495 return false;
496 }
497
498 return hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT);
499 }, (program, t) -> {
500
501 final InputSpec inputSpec = program.inputSpec();
502
503 final CoefficientOperation<Double> cosCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
504
505 final double cosValue = Math.cos(cosCoefficient.value());
506
507 final OperationFactory cosValueOperationFactory = OperationFactories
508 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, cosValue);
509
510 return new TreeNode<>(cosValueOperationFactory.build(inputSpec));
511 });
512
513 @SuppressWarnings("unchecked")
514 public static final Rule SIN_OF_COEFFICIENT = ImmutableRule.of(t -> {
515 if (isOperation(t, Functions.NAME_SIN) == false) {
516 return false;
517 }
518
519 return hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT);
520 }, (program, t) -> {
521
522 final InputSpec inputSpec = program.inputSpec();
523
524 final CoefficientOperation<Double> sinCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
525
526 final double sinValue = Math.sin(sinCoefficient.value());
527
528 final OperationFactory sinValueOperationFactory = OperationFactories
529 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, sinValue);
530
531 return new TreeNode<>(sinValueOperationFactory.build(inputSpec));
532 });
533
534 public static final Rule SUB_SAME_BRANCHES = ImmutableRule.of(t -> {
535 if (isOperation(t, Functions.NAME_SUB) == false) {
536 return false;
537 }
538
539 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
540 }, (program, t) -> {
541
542 final InputSpec inputSpec = program.inputSpec();
543
544 final OperationFactory zeroFactory = OperationFactories
545 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
546
547 return new TreeNode<>(zeroFactory.build(inputSpec));
548 });
549
550 public static final Rule ADD_SAME_BRANCHES = ImmutableRule.of(t -> {
551 if (isOperation(t, Functions.NAME_ADD) == false) {
552 return false;
553 }
554
555 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
556 }, (program, t) -> {
557
558 final InputSpec inputSpec = program.inputSpec();
559
560 final TreeNode<Operation<?>> baseAdd = new TreeNode<>(Functions.ADD.build(inputSpec));
561
562 final OperationFactory twoFactory = OperationFactories
563 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 2.0d);
564 baseAdd.addChild(new TreeNode<>(twoFactory.build(inputSpec)));
565
566 baseAdd.addChild(t.getChild(0));
567
568 return baseAdd;
569 });
570
571 public static final Rule DIV_SAME_BRANCHES = ImmutableRule.of(t -> {
572 if (isOperation(t, Functions.NAME_DIV) == false) {
573 return false;
574 }
575
576 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
577 }, (program, t) -> {
578
579 final InputSpec inputSpec = program.inputSpec();
580
581 final OperationFactory oneFactory = OperationFactories
582 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 1.0d);
583
584 return new TreeNode<>(oneFactory.build(inputSpec));
585 });
586
587 @SuppressWarnings("unchecked")
588 public static final Rule EXP_OF_COEFFICIENT = ImmutableRule.of(t -> {
589 if (isOperation(t, Functions.NAME_EXP) == false) {
590 return false;
591 }
592
593 return hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT);
594 }, (program, t) -> {
595
596 final InputSpec inputSpec = program.inputSpec();
597
598 final CoefficientOperation<Double> expCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
599
600 final double expValue = Math.exp(expCoefficient.value());
601
602 final OperationFactory expValueOperationFactory = OperationFactories
603 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, expValue);
604
605 return new TreeNode<>(expValueOperationFactory.build(inputSpec));
606 });
607
608 @SuppressWarnings("unchecked")
609 public static final Rule POW_TWO_COEFFICIENTS = ImmutableRule.of(
610 t -> isOperation(t, Functions.NAME_POW) && hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT)
611 && hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT),
612 (program, t) -> {
613
614 final InputSpec inputSpec = program.inputSpec();
615
616 final CoefficientOperation<Double> firstCoefficient = getChildAs(t, 0, CoefficientOperation.class);
617 final Double firstValue = firstCoefficient.value();
618
619 final CoefficientOperation<Double> secondCoefficient = getChildAs(t, 1, CoefficientOperation.class);
620 final Double secondValue = secondCoefficient.value();
621
622 final OperationFactory coefficientFactory = OperationFactories
623 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, Math.pow(firstValue, secondValue));
624
625 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
626
627 return new TreeNode<>(newOperation);
628 });
629
630
631
632
633 public static final Rule MUL_SAME_BRANCHES = ImmutableRule.of(t -> {
634 if (isOperation(t, Functions.NAME_MUL) == false) {
635 return false;
636 }
637
638 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
639 }, (program, t) -> {
640
641 final InputSpec inputSpec = program.inputSpec();
642
643 final TreeNode<Operation<?>> powNode = new TreeNode<>(Functions.POW.build(inputSpec));
644
645 powNode.addChild(t.getChild(0));
646 powNode.addChild(
647 new TreeNode<>(
648 OperationFactories.ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 2.0d).build(inputSpec)));
649
650 return powNode;
651 });
652
653 public static final Rule COS_PI = ImmutableRule.of(t -> {
654 if (isOperation(t, Functions.NAME_COS) == false) {
655 return false;
656 }
657
658 return hasChildOperation(t, 0, Terminals.NAME_PI);
659 }, (program, t) -> {
660
661 final InputSpec inputSpec = program.inputSpec();
662
663 final OperationFactory minusOneFactory = OperationFactories
664 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, -1.0d);
665
666 return new TreeNode<>(minusOneFactory.build(inputSpec));
667 });
668
669 public static final Rule SIN_PI = ImmutableRule.of(t -> {
670 if (isOperation(t, Functions.NAME_SIN) == false) {
671 return false;
672 }
673
674 return hasChildOperation(t, 0, Terminals.NAME_PI);
675 }, (program, t) -> {
676
677 final InputSpec inputSpec = program.inputSpec();
678
679 final OperationFactory zeroFactory = OperationFactories
680 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, -0.0d);
681
682 return new TreeNode<>(zeroFactory.build(inputSpec));
683 });
684
685 public static final List<Rule> SIMPLIFY_RULES = Arrays.asList(
686 MUL_SAME_BRANCHES,
687 ADD_TWO_COEFFCIENTS,
688 MUL_TWO_COEFFICIENTS,
689 SUB_TWO_COEFFICIENTS,
690 SUB_INPUT_FROM_SAME_INPUT,
691 SUB_ZERO_FROM_INPUT,
692 DIV_TWO_COEFFICIENT_FINITE,
693 ADD_INPUT_TO_SAME_INPUT,
694 MULTIPLY_INPUT_WITH_SAME_INPUT,
695 MUL_1_WITH_ANYTHING,
696 MUL_ANYTHING_WITH_1,
697 MUL_0_WITH_ANYTHING,
698 MUL_ANYTHING_WITH_0,
699 POW_0,
700 POW_1,
701 COS_OF_COEFFICIENT,
702 SIN_OF_COEFFICIENT,
703 SUB_SAME_BRANCHES,
704 ADD_SAME_BRANCHES,
705 DIV_SAME_BRANCHES,
706 EXP_OF_COEFFICIENT,
707 POW_TWO_COEFFICIENTS,
708 ADD_0_WITH_ANYTHING,
709 ADD_ANYTHING_WITH_0,
710 COS_PI,
711 SIN_PI);
712
713 }