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