001 /*
002 * Java Genetic Algorithm Library (jenetics-6.1.0).
003 * Copyright (c) 2007-2020 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 */
020 package io.jenetics.prog.op;
021
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024
025 import java.lang.reflect.Array;
026 import java.util.Optional;
027 import java.util.stream.Stream;
028
029 import io.jenetics.ext.rewriting.TreeRewriter;
030 import io.jenetics.ext.util.Tree;
031 import io.jenetics.ext.util.TreeNode;
032
033 /**
034 * This class rewrites constant expressions to its single value.
035 * <p>
036 * The following example show how to use the rewriter for a double operation
037 * tree:
038 * <pre>{@code
039 * final TreeNode<Op<Double>> tree = MathExpr.parseTree("1 + 2 + 3 + 4");
040 * ConstRewriter.ofType(Double.class).rewrite(tree);
041 * assert tree.getValue().equals(Const.of(10.0));
042 * }</pre>
043 *
044 * @param <T> the operation type the rewriter is working on
045 *
046 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
047 * @version 5.2
048 * @since 5.2
049 */
050 public final class ConstRewriter<T> implements TreeRewriter<Op<T>> {
051
052 /**
053 * Const rewriter for double operation trees.
054 */
055 public static final ConstRewriter<Double> DOUBLE = ofType(Double.class);
056
057 private final Class<T> _type;
058
059 @SuppressWarnings("unchecked")
060 private ConstRewriter(final Class<? extends T> type) {
061 _type = (Class<T>)requireNonNull(type);
062 }
063
064 /**
065 * Return the operation type this rewriter is working on.
066 *
067 * @return the operation type this rewriter is working on
068 */
069 public Class<T> type() {
070 return _type;
071 }
072
073 @Override
074 public int rewrite(final TreeNode<Op<T>> node, final int limit) {
075 requireNonNull(node);
076
077 int rewritten = 0;
078 int res;
079 Optional<TreeNode<Op<T>>> result;
080 do {
081 result = results(node).findFirst();
082
083 res = result.map(this::rewriting).orElse(0);
084 rewritten += res;
085 } while (result.isPresent() && rewritten < limit);
086
087 return rewritten;
088 }
089
090 private int rewriting(final TreeNode<Op<T>> node) {
091 if (matches(node)) {
092 final T[] args = newArray(node.childCount());
093 for (int i = 0, n = node.childCount(); i < n; ++i) {
094 args[i] = ((Val<T>)node.childAt(i).value()).value();
095 }
096
097 final T value = node.value().apply(args);
098 node.removeAllChildren();
099 node.value(Const.of(value));
100
101 return 1;
102 }
103
104 return 0;
105 }
106
107 @SuppressWarnings("unchecked")
108 private T[] newArray(final int length) {
109 return (T[])Array.newInstance(_type, length);
110 }
111
112 private static <T> Stream<TreeNode<Op<T>>>
113 results(final TreeNode<Op<T>> node) {
114 return node.stream()
115 .filter(ConstRewriter::matches);
116 }
117
118 private static boolean matches(final Tree<?, ?> node) {
119 return
120 !(node.value() instanceof Val) &&
121 !(node.value() instanceof Var) &&
122 node.childStream()
123 .allMatch(child -> child.value() instanceof Val);
124 }
125
126 @Override
127 public String toString() {
128 return format("ConstRewriter<%s>", _type.getSimpleName());
129 }
130
131 /**
132 * Create a new rewriter for constant operation sub-trees (expressions).
133 *
134 * @param type the type of the operation tree
135 * @param <T> the type of the operation tree
136 * @return a new rewriter for constant operation sub-trees (expressions)
137 * @throws NullPointerException if the given {@code type} is {@code null}
138 */
139 public static <T> ConstRewriter<T> ofType(final Class<? extends T> type) {
140 return new ConstRewriter<>(type);
141 }
142
143 }
|