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.util.Objects.requireNonNull;
023
024 import java.util.Objects;
025 import java.util.Optional;
026 import java.util.function.Function;
027 import java.util.stream.Stream;
028
029 import io.jenetics.ext.util.Tree;
030 import io.jenetics.ext.util.TreeNode;
031
032 /**
033 * This class contains basic and secondary boolean operations.
034 *
035 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
036 * @version 5.0
037 * @since 5.0
038 */
039 public enum BoolOp implements Op<Boolean> {
040
041 /**
042 * Conjunction. <em>This operation has arity 2.</em>
043 */
044 AND("and", 2, v -> v[0] && v[1]),
045
046 /**
047 * Disjunction. <em>This operation has arity 2.</em>
048 */
049 OR("or", 2, v -> v[0] || v[1]),
050
051 /**
052 * Negation. <em>This operation has arity 1.</em>
053 */
054 NOT("not", 1, v -> !v[0]),
055
056 /**
057 * Implication. <em>This operation has arity 2.</em>
058 */
059 IMP("imp", 2, v -> !v[0] || v[1]),
060
061 /**
062 * Exclusive or. <em>This operation has arity 2.</em>
063 */
064 XOR("xor", 2, v -> (v[0] || v[1]) && !(v[0] && v[1])),
065
066 /**
067 * Equivalence. <em>This operation has arity 2.</em>
068 */
069 EQU("equ", 2, v -> (v[0] && v[1]) || (!v[0] && !v[1]));
070
071 /**
072 * Represents the constant {@code true}.
073 */
074 public static final Const<Boolean> TRUE = Const.of("true", true);
075
076 /**
077 * Represents the constant {@code true}.
078 */
079 public static final Const<Boolean> FALSE = Const.of("false", false);
080
081
082 private final String _name;
083 private final int _arity;
084 private final Function<Boolean[], Boolean> _function;
085
086 BoolOp(
087 final String name,
088 final int arity,
089 final Function<Boolean[], Boolean> function
090 ) {
091 assert name != null;
092 assert arity >= 0;
093 assert function != null;
094
095 _name = name;
096 _function = function;
097 _arity = arity;
098 }
099
100 @Override
101 public int arity() {
102 return _arity;
103 }
104
105 @Override
106 public Boolean apply(final Boolean[] args) {
107 return _function.apply(args);
108 }
109
110 /**
111 * Evaluates the operation with the given arguments.
112 *
113 * @see #apply(Boolean[])
114 *
115 * @param args the operation arguments
116 * @return the evaluated operation
117 */
118 public boolean eval(final boolean... args) {
119 final Boolean[] v = new Boolean[args.length];
120 for (int i = 0; i < args.length; ++i) {
121 v[i] = args[i];
122 }
123
124 return apply(v);
125 }
126
127 @Override
128 public String toString() {
129 return _name;
130 }
131
132
133 /**
134 * Converts the string representation of an operation to the operation
135 * object. It is used for converting the string representation of a tree to
136 * an operation tree. If you use it that way, you should not forget to
137 * re-index the tree variables.
138 *
139 * <pre>{@code
140 * final TreeNode<Op<Boolean>> tree = TreeNode.parse(
141 * "and(or(x,y),not(y))",
142 * BoolOp::toBoolOp
143 * );
144 *
145 * assert Program.eval(tree, false, false) == false;
146 * Var.reindex(tree);
147 * assert Program.eval(tree, false, false) == true;
148 * }</pre>
149 *
150 * @since 5.0
151 *
152 * @see Var#reindex(TreeNode)
153 * @see Program#eval(Tree, Object[])
154 *
155 * @param string the string representation of an operation which should be
156 * converted
157 * @return the operation, converted from the given string
158 * @throws IllegalArgumentException if the given {@code value} doesn't
159 * represent a mathematical expression
160 * @throws NullPointerException if the given string {@code value} is
161 * {@code null}
162 */
163 public static Op<Boolean> toBoolOp(final String string) {
164 requireNonNull(string);
165
166 final Op<Boolean> result;
167 final Optional<Const<Boolean>> cop = toConst(string);
168 if (cop.isPresent()) {
169 result = cop.orElseThrow(AssertionError::new);
170 } else {
171 final Optional<Op<Boolean>> mop = toOp(string);
172 result = mop.isPresent()
173 ? mop.orElseThrow(AssertionError::new)
174 : Var.parse(string);
175 }
176
177 return result;
178 }
179
180 static Optional<Const<Boolean>> toConst(final String string) {
181 return tryParseBoolean(string)
182 .map(Const::of);
183 }
184
185 private static Optional<Boolean> tryParseBoolean(final String value) {
186 switch (value) {
187 case "true":
188 case "1": return Optional.of(true);
189 case "false":
190 case "0": return Optional.of(false);
191 default: return Optional.empty();
192 }
193 }
194
195 private static Optional<Op<Boolean>> toOp(final String string) {
196 return Stream.of(values())
197 .filter(op -> Objects.equals(op._name, string))
198 .map(op -> (Op<Boolean>)op)
199 .findFirst();
200 }
201
202 }
|