001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 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 */ 020package io.jenetics.prog.op; 021 022import static java.lang.String.format; 023import static java.util.Objects.requireNonNull; 024 025import java.lang.reflect.Array; 026import java.util.Optional; 027import java.util.stream.Stream; 028 029import io.jenetics.ext.rewriting.TreeRewriter; 030import io.jenetics.ext.util.Tree; 031import io.jenetics.ext.util.TreeNode; 032 033/** 034 * This class rewrites constant expressions to its single value. 035 * <p> 036 * The following example shows 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 */ 050public 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 } else { 103 return 0; 104 } 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 subtrees (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 subtrees (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}