001 /*
002 * Java Genetic Algorithm Library (jenetics-6.0.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 = node.childStream()
093 .map(child -> ((Val<T>)child.value()).value())
094 .toArray(this::newArray);
095
096 final T value = node.value().apply(args);
097 node.removeAllChildren();
098 node.value(Const.of(value));
099
100 return 1;
101 }
102
103 return 0;
104 }
105
106 @SuppressWarnings("unchecked")
107 private T[] newArray(final int length) {
108 return (T[])Array.newInstance(_type, length);
109 }
110
111 private static <T> Stream<TreeNode<Op<T>>>
112 results(final TreeNode<Op<T>> node) {
113 return node.stream()
114 .filter(ConstRewriter::matches);
115 }
116
117 private static boolean matches(final Tree<?, ?> node) {
118 return
119 !(node.value() instanceof Val) &&
120 !(node.value() instanceof Var) &&
121 node.childStream()
122 .allMatch(child -> child.value() instanceof Val);
123 }
124
125 @Override
126 public String toString() {
127 return format("ConstRewriter<%s>", _type.getSimpleName());
128 }
129
130 /**
131 * Create a new rewriter for constant operation sub-trees (expressions).
132 *
133 * @param type the type of the operation tree
134 * @param <T> the type of the operation tree
135 * @return a new rewriter for constant operation sub-trees (expressions)
136 * @throws NullPointerException if the given {@code type} is {@code null}
137 */
138 public static <T> ConstRewriter<T> ofType(final Class<? extends T> type) {
139 return new ConstRewriter<>(type);
140 }
141
142 }
|