BoolOp.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.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             defaultreturn 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 }