001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 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.util.Objects.requireNonNull; 023 024import java.util.Objects; 025import java.util.Optional; 026import java.util.function.Function; 027import java.util.stream.Stream; 028 029import io.jenetics.ext.util.Tree; 030import 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 */ 039public 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 * {@snippet lang="java": 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 * } 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 return switch (value) { 187 case "true", "1" -> Optional.of(true); 188 case "false", "0" -> Optional.of(false); 189 default -> Optional.empty(); 190 }; 191 } 192 193 private static Optional<Op<Boolean>> toOp(final String string) { 194 return Stream.of(values()) 195 .filter(op -> Objects.equals(op._name, string)) 196 .map(op -> (Op<Boolean>)op) 197 .findFirst(); 198 } 199 200}