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().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 final public static 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 final public static 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 final public static 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 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).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 final public static 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 final public static 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 final public static 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<Operation<?>>(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<Operation<?>>(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<Operation<?>>(firstInput);
259 multBaseTreeNode.addChild(firstInputTreeNode);
260
261 return multBaseTreeNode;
262 });
263
264 @SuppressWarnings("unchecked")
265 final public static 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<Operation<?>>(Functions.EXP.build(inputSpec));
288
289 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
290 final TreeNode<Operation<?>> firstInputTreeNode = new TreeNode<Operation<?>>(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<Operation<?>>(coefficientFactory.build(inputSpec));
296 expBaseTreeNode.addChild(twoTreeNode);
297
298 return expBaseTreeNode;
299 });
300
301 @SuppressWarnings("unchecked")
302 final public static 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<Operation<?>>(Functions.EXP.build(inputSpec));
337
338 final InputOperation<?> firstInput = (InputOperation<Double>) t.getChild(0).getData();
339 final TreeNode<Operation<?>> firstInputTreeNode = new TreeNode<Operation<?>>(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<Operation<?>>(coefficientFactory.build(inputSpec));
345 expBaseTreeNode.addChild(newCoeffTreeNode);
346
347 return expBaseTreeNode;
348 });
349
350 @SuppressWarnings("unchecked")
351 final public static 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) -> {
364
365 return t.getChild(1);
366 });
367
368 @SuppressWarnings("unchecked")
369 final public static Rule MUL_ANYTHING_WITH_1 = ImmutableRule.of((t) -> {
370 if (isOperation(t, Functions.NAME_MUL) == false) {
371 return false;
372 }
373
374 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
375 return false;
376 }
377
378 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
379
380 return isEqual(secondCoefficient.value(), 1);
381 }, (program, t) -> {
382
383 return t.getChild(0);
384 });
385
386 @SuppressWarnings("unchecked")
387 final public static Rule ADD_0_WITH_ANYTHING = ImmutableRule.of((t) -> {
388 if (isOperation(t, Functions.NAME_ADD) == false) {
389 return false;
390 }
391
392 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
393 return false;
394 }
395
396 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
397
398 return isEqual(firstCoefficient.value(), 0.0d);
399 }, (program, t) -> {
400
401 return t.getChild(1);
402 });
403
404 @SuppressWarnings("unchecked")
405 final public static Rule ADD_ANYTHING_WITH_0 = ImmutableRule.of((t) -> {
406 if (isOperation(t, Functions.NAME_ADD) == false) {
407 return false;
408 }
409
410 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
411 return false;
412 }
413
414 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
415
416 return isEqual(secondCoefficient.value(), 0.0d);
417 }, (program, t) -> {
418
419 return t.getChild(0);
420 });
421
422 @SuppressWarnings("unchecked")
423 final public static Rule MUL_0_WITH_ANYTHING = ImmutableRule.of((t) -> {
424 if (isOperation(t, Functions.NAME_MUL) == false) {
425 return false;
426 }
427
428 if (hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT) == false) {
429 return false;
430 }
431
432 final CoefficientOperation<Double> firstCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
433
434 return isEqual(firstCoefficient.value(), 0.0d);
435 }, (program, t) -> {
436
437 final InputSpec inputSpec = program.inputSpec();
438
439 final OperationFactory zeroFactory = OperationFactories
440 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
441
442 return new TreeNode<>(zeroFactory.build(inputSpec));
443 });
444
445 @SuppressWarnings("unchecked")
446 final public static Rule MUL_ANYTHING_WITH_0 = ImmutableRule.of((t) -> {
447 if (isOperation(t, Functions.NAME_MUL) == false) {
448 return false;
449 }
450
451 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
452 return false;
453 }
454
455 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
456
457 return secondCoefficient.value() < 1 + 0.0001 && secondCoefficient.value() > 1 - .0001;
458 }, (program, t) -> {
459 final InputSpec inputSpec = program.inputSpec();
460
461 final OperationFactory zeroFactory = OperationFactories
462 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
463
464 return new TreeNode<>(zeroFactory.build(inputSpec));
465 });
466
467 @SuppressWarnings("unchecked")
468 final public static Rule POW_0 = ImmutableRule.of((t) -> {
469 if (isOperation(t, Functions.NAME_POW) == false) {
470 return false;
471 }
472
473 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
474 return false;
475 }
476
477 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
478
479 return isEqual(secondCoefficient.value(), 0);
480 }, (program, t) -> {
481 final InputSpec inputSpec = program.inputSpec();
482
483 final OperationFactory oneFactory = OperationFactories
484 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 1.0d);
485
486 return new TreeNode<>(oneFactory.build(inputSpec));
487 });
488
489 @SuppressWarnings("unchecked")
490 final public static Rule POW_1 = ImmutableRule.of((t) -> {
491 if (isOperation(t, Functions.NAME_POW) == false) {
492 return false;
493 }
494
495 if (hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT) == false) {
496 return false;
497 }
498
499 final CoefficientOperation<Double> secondCoefficient = (CoefficientOperation<Double>) t.getChild(1).getData();
500
501 return isEqual(secondCoefficient.value(), 1);
502 }, (program, t) -> {
503
504 return t.getChild(0);
505 });
506
507 @SuppressWarnings("unchecked")
508 final public static Rule COS_OF_COEFFICIENT = ImmutableRule.of((t) -> {
509 if (isOperation(t, Functions.NAME_COS) == false) {
510 return false;
511 }
512
513 return hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT);
514 }, (program, t) -> {
515
516 final InputSpec inputSpec = program.inputSpec();
517
518 final CoefficientOperation<Double> cosCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
519
520 final double cosValue = Math.cos(cosCoefficient.value());
521
522 final OperationFactory cosValueOperationFactory = OperationFactories
523 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, cosValue);
524
525 return new TreeNode<>(cosValueOperationFactory.build(inputSpec));
526 });
527
528 @SuppressWarnings("unchecked")
529 final public static Rule SIN_OF_COEFFICIENT = ImmutableRule.of((t) -> {
530 if (isOperation(t, Functions.NAME_SIN) == false) {
531 return false;
532 }
533
534 return hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT);
535 }, (program, t) -> {
536
537 final InputSpec inputSpec = program.inputSpec();
538
539 final CoefficientOperation<Double> sinCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
540
541 final double sinValue = Math.sin(sinCoefficient.value());
542
543 final OperationFactory sinValueOperationFactory = OperationFactories
544 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, sinValue);
545
546 return new TreeNode<>(sinValueOperationFactory.build(inputSpec));
547 });
548
549 final public static Rule SUB_SAME_BRANCHES = ImmutableRule.of((t) -> {
550 if (isOperation(t, Functions.NAME_SUB) == false) {
551 return false;
552 }
553
554 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
555 }, (program, t) -> {
556
557 final InputSpec inputSpec = program.inputSpec();
558
559 final OperationFactory zeroFactory = OperationFactories
560 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 0.0d);
561
562 return new TreeNode<>(zeroFactory.build(inputSpec));
563 });
564
565 final public static Rule ADD_SAME_BRANCHES = ImmutableRule.of((t) -> {
566 if (isOperation(t, Functions.NAME_ADD) == false) {
567 return false;
568 }
569
570 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
571 }, (program, t) -> {
572
573 final InputSpec inputSpec = program.inputSpec();
574
575 final TreeNode<Operation<?>> baseAdd = new TreeNode<>(Functions.ADD.build(inputSpec));
576
577 final OperationFactory twoFactory = OperationFactories
578 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 2.0d);
579 baseAdd.addChild(new TreeNode<>(twoFactory.build(inputSpec)));
580
581 baseAdd.addChild(t.getChild(0));
582
583 return baseAdd;
584 });
585
586 final public static Rule DIV_SAME_BRANCHES = ImmutableRule.of((t) -> {
587 if (isOperation(t, Functions.NAME_DIV) == false) {
588 return false;
589 }
590
591 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
592 }, (program, t) -> {
593
594 final InputSpec inputSpec = program.inputSpec();
595
596 final OperationFactory oneFactory = OperationFactories
597 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 1.0d);
598
599 return new TreeNode<>(oneFactory.build(inputSpec));
600 });
601
602 @SuppressWarnings("unchecked")
603 final public static Rule EXP_OF_COEFFICIENT = ImmutableRule.of((t) -> {
604 if (isOperation(t, Functions.NAME_EXP) == false) {
605 return false;
606 }
607
608 return hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT);
609 }, (program, t) -> {
610
611 final InputSpec inputSpec = program.inputSpec();
612
613 final CoefficientOperation<Double> expCoefficient = (CoefficientOperation<Double>) t.getChild(0).getData();
614
615 final double expValue = Math.exp(expCoefficient.value());
616
617 final OperationFactory expValueOperationFactory = OperationFactories
618 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, expValue);
619
620 return new TreeNode<>(expValueOperationFactory.build(inputSpec));
621 });
622
623 @SuppressWarnings("unchecked")
624 final public static Rule POW_TWO_COEFFICIENTS = ImmutableRule.of(
625 (t) -> isOperation(t, Functions.NAME_POW) && hasChildOperation(t, 0, Terminals.TYPE_COEFFICIENT)
626 && hasChildOperation(t, 1, Terminals.TYPE_COEFFICIENT),
627 (program, t) -> {
628
629 final InputSpec inputSpec = program.inputSpec();
630
631 final CoefficientOperation<Double> firstCoefficient = getChildAs(t, 0, CoefficientOperation.class);
632 final Double firstValue = firstCoefficient.value();
633
634 final CoefficientOperation<Double> secondCoefficient = getChildAs(t, 1, CoefficientOperation.class);
635 final Double secondValue = secondCoefficient.value();
636
637 final OperationFactory coefficientFactory = OperationFactories
638 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, Math.pow(firstValue, secondValue));
639
640 final Operation<?> newOperation = coefficientFactory.build(inputSpec);
641
642 return new TreeNode<>(newOperation);
643 });
644
645
646
647
648 final public static Rule MUL_SAME_BRANCHES = ImmutableRule.of((t) -> {
649 if (isOperation(t, Functions.NAME_MUL) == false) {
650 return false;
651 }
652
653 return TreeNodeUtils.areSame(t.getChild(0), t.getChild(1));
654 }, (program, t) -> {
655
656 final InputSpec inputSpec = program.inputSpec();
657
658 final TreeNode<Operation<?>> powNode = new TreeNode<>(Functions.POW.build(inputSpec));
659
660 powNode.addChild(t.getChild(0));
661 powNode.addChild(
662 new TreeNode<>(
663 OperationFactories.ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, 2.0d).build(inputSpec)));
664
665 return powNode;
666 });
667
668 final public static Rule COS_PI = ImmutableRule.of((t) -> {
669 if (isOperation(t, Functions.NAME_COS) == false) {
670 return false;
671 }
672
673 return hasChildOperation(t, 0, Terminals.NAME_PI);
674 }, (program, t) -> {
675
676 final InputSpec inputSpec = program.inputSpec();
677
678 final OperationFactory minusOneFactory = OperationFactories
679 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, -1.0d);
680
681 return new TreeNode<>(minusOneFactory.build(inputSpec));
682 });
683
684 final public static Rule SIN_PI = ImmutableRule.of((t) -> {
685 if (isOperation(t, Functions.NAME_SIN) == false) {
686 return false;
687 }
688
689 return hasChildOperation(t, 0, Terminals.NAME_PI);
690 }, (program, t) -> {
691
692 final InputSpec inputSpec = program.inputSpec();
693
694 final OperationFactory zeroFactory = OperationFactories
695 .ofCoefficient(Terminals.TYPE_COEFFICIENT, Double.class, -0.0d);
696
697 return new TreeNode<>(zeroFactory.build(inputSpec));
698 });
699
700 final public static List<Rule> SIMPLIFY_RULES = Arrays.asList(
701 MUL_SAME_BRANCHES,
702 ADD_TWO_COEFFCIENTS,
703 MUL_TWO_COEFFICIENTS,
704 SUB_TWO_COEFFICIENTS,
705 SUB_INPUT_FROM_SAME_INPUT,
706 SUB_ZERO_FROM_INPUT,
707 DIV_TWO_COEFFICIENT_FINITE,
708 ADD_INPUT_TO_SAME_INPUT,
709 MULTIPLY_INPUT_WITH_SAME_INPUT,
710 MUL_1_WITH_ANYTHING,
711 MUL_ANYTHING_WITH_1,
712 MUL_0_WITH_ANYTHING,
713 MUL_ANYTHING_WITH_0,
714 POW_0,
715 POW_1,
716 COS_OF_COEFFICIENT,
717 SIN_OF_COEFFICIENT,
718 SUB_SAME_BRANCHES,
719 ADD_SAME_BRANCHES,
720 DIV_SAME_BRANCHES,
721 EXP_OF_COEFFICIENT,
722 POW_TWO_COEFFICIENTS,
723 ADD_0_WITH_ANYTHING,
724 ADD_ANYTHING_WITH_0,
725 COS_PI,
726 SIN_PI);
727
728 }