MathExprFormatter.java
01 /*
02  * Java Genetic Algorithm Library (jenetics-7.1.1).
03  * Copyright (c) 2007-2022 Franz Wilhelmstötter
04  *
05  * Licensed under the Apache License, Version 2.0 (the "License");
06  * you may not use this file except in compliance with the License.
07  * You may obtain a copy of the License at
08  *
09  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Author:
18  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
19  */
20 package io.jenetics.prog.op;
21 
22 import java.util.Map;
23 
24 import io.jenetics.ext.util.Tree;
25 
26 /**
27  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
28  @version 4.3
29  @since 4.3
30  */
31 final class MathExprFormatter {
32     private MathExprFormatter() {}
33 
34     private static final Map<Op<Double>, String> INFIX_OPS = Map.of(
35         MathOp.ADD, " + ",
36         MathOp.SUB, " - ",
37         MathOp.MUL, "*",
38         MathOp.DIV, "/",
39         MathOp.MOD, "%",
40         MathOp.POW, "^"
41     );
42 
43     private static final Map<Op<Double>, Integer> PRECEDENCE = Map.of(
44         MathOp.ADD, 6,
45         MathOp.SUB, 6,
46         MathOp.MUL, 5,
47         MathOp.DIV, 5,
48         MathOp.MOD, 5,
49         MathOp.POW, 4
50     );
51 
52     static String format(final Tree<? extends Op<Double>, ?> tree) {
53         final StringBuilder out = new StringBuilder();
54         format(tree, out);
55         return out.toString();
56     }
57 
58     private static void format(
59         final Tree<? extends Op<Double>, ?> tree,
60         final StringBuilder out
61     ) {
62         final Op<Double> op = tree.value();
63         if (INFIX_OPS.containsKey(op)) {
64             infix(tree, out);
65         else {
66             out.append(op);
67             if (!tree.isLeaf()) {
68                 out.append("(");
69                 format(tree.childAt(0), out);
70                 for (int i = 1; i < tree.childCount(); ++i) {
71                     out.append(", ");
72                     format(tree.childAt(i), out);
73                 }
74                 out.append(")");
75             }
76         }
77     }
78 
79     private static void infix(
80         final Tree<? extends Op<Double>, ?> tree,
81         final StringBuilder out
82     ) {
83         assert tree.childCount() == 2;
84 
85         final int precedence = PRECEDENCE.getOrDefault(tree.value()100);
86         final int parentPrecedence = tree.parent()
87             .map(p -> PRECEDENCE.getOrDefault(p.value()100))
88             .orElse(100);
89 
90         final boolean brackets = !tree.isRoot() && precedence >= parentPrecedence;
91 
92         if (bracketsout.append("(");
93         format(tree.childAt(0), out);
94         out.append(INFIX_OPS.get(tree.value()));
95         format(tree.childAt(1), out);
96         if (bracketsout.append(")");
97     }
98 
99 }