ConstRewriter.java
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 }