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