1 /** N-State (Fuzzy Logic). 2 3 Generalization of `bool` to three or more states. 4 5 See_Also: https://en.wikipedia.org/wiki/Three-state_logic 6 See_Also: https://en.wikipedia.org/wiki/Four-valued_logic 7 See_Also: https://en.wikipedia.org/wiki/Many-valued_logic 8 See_Also: https://en.wikipedia.org/wiki/Three-valued_logic 9 See_Also: https://forum.dlang.org/post/l4gnrc$2glg$1@digitalmars.com 10 */ 11 module nxt.nstate; 12 13 /** Fuzzy logic State. 14 */ 15 struct Fuzzy 16 { 17 @safe pure nothrow @nogc: 18 19 enum defaultCode = 0; 20 21 enum no = make(defaultCode); // probability: 0 22 enum yes = make(1); // probability: 1 23 enum likely = make(2); // probability: > 1/2 24 enum unlikely = make(3); // probability: < 1/2 25 enum unknown = make(4); // probability: any 26 27 this(bool b) 28 { 29 _v = b ? yes._v : no._v; 30 } 31 32 void opAssign(bool b) 33 { 34 _v = b ? yes._v : no._v; 35 } 36 37 Fuzzy opUnary(string s)() if (s == "~") 38 { 39 final switch (_v) 40 { 41 case no._v: return yes; 42 case yes._v: return no; 43 case likely._v: return unlikely; 44 case unlikely._v: return likely; 45 } 46 } 47 48 Fuzzy opBinary(string s)(Fuzzy rhs) if (s == "|") 49 { 50 import std.algorithm.comparion : among; 51 if (_v.among!(yes._v, no._v) && rhs._v.among!(yes._v, no._v)) 52 { 53 return _v | rhs._v; 54 } 55 else if (_v == yes._v || rhs._v == yes._v) 56 { 57 return yes; 58 } 59 else if (_v == no._v) 60 { 61 return rhs._v; 62 } 63 else if (rhs._v == no._v) 64 { 65 return _v; 66 } 67 else if (_v == rhs._v) // both likely or unlikely or unknown 68 { 69 return _v; 70 } 71 else 72 { 73 return unknown; 74 } 75 } 76 77 // Fuzzy opBinary(string s)(Fuzzy rhs) if (s == "&") 78 // { 79 // return make(_v & rhs._v); 80 // } 81 82 // Fuzzy opBinary(string s)(Fuzzy rhs) if (s == "^") 83 // { 84 // auto v = _v + rhs._v; 85 // return v >= 4 ? unknown : make(!!v); 86 // } 87 88 private: 89 ubyte _v = defaultCode; 90 static Fuzzy make(ubyte b) 91 { 92 Fuzzy r = void; 93 r._v = b; 94 return r; 95 } 96 } 97 98 @safe pure nothrow @nogc unittest 99 { 100 alias T = Fuzzy; 101 T a; 102 assert(a == T.no); 103 104 a = true; 105 assert(a == T.yes); 106 107 a = T.likely; 108 assert(a == T.likely); 109 110 a = T.unlikely; 111 assert(a == T.unlikely); 112 113 with (T) 114 { 115 assert(~no == yes); 116 assert(no == ~yes); 117 assert(~unlikely == likely); 118 assert(unlikely == ~likely); 119 } 120 } 121 122 /** State being either `yes`, `no` or `unknown`. 123 */ 124 struct Tristate 125 { 126 @safe pure nothrow @nogc: 127 128 enum defaultCode = 0; 129 130 enum no = make(defaultCode); 131 enum yes = make(2); 132 enum unknown = make(6); 133 134 this(bool b) 135 { 136 _v = b ? yes._v : no._v; 137 } 138 139 void opAssign(bool b) 140 { 141 _v = b ? yes._v : no._v; 142 } 143 144 Tristate opUnary(string s)() if (s == "~") 145 { 146 return make((193 >> _v & 3) << 1); 147 } 148 149 Tristate opBinary(string s)(Tristate rhs) if (s == "|") 150 { 151 return make((12756 >> (_v + rhs._v) & 3) << 1); 152 } 153 154 Tristate opBinary(string s)(Tristate rhs) if (s == "&") 155 { 156 return make((13072 >> (_v + rhs._v) & 3) << 1); 157 } 158 159 Tristate opBinary(string s)(Tristate rhs) if (s == "^") 160 { 161 return make((13252 >> (_v + rhs._v) & 3) << 1); 162 } 163 164 private: 165 ubyte _v = defaultCode; 166 static Tristate make(ubyte b) 167 { 168 Tristate r = void; 169 r._v = b; 170 return r; 171 } 172 } 173 174 @safe pure nothrow @nogc unittest 175 { 176 alias T = Tristate; 177 T a; 178 assert(a == T.no); 179 static assert(!is(typeof({ if (a) {} }))); 180 assert(!is(typeof({ auto b = T(3); }))); 181 182 a = true; 183 assert(a == T.yes); 184 185 a = false; 186 assert(a == T.no); 187 188 a = T.unknown; 189 T b; 190 191 b = a; 192 assert(b == a); 193 194 auto c = a | b; 195 assert(c == T.unknown); 196 assert((a & b) == T.unknown); 197 198 a = true; 199 assert(~a == T.no); 200 201 a = true; 202 b = false; 203 assert((a ^ b) == T.yes); 204 205 with (T) 206 { 207 // not 208 assert(~no == yes); 209 assert(~yes == no); 210 assert(~unknown == unknown); 211 212 // or 213 assert((no | no) == no); 214 assert((no | yes) == yes); 215 assert((yes | no) == yes); 216 assert((yes | yes) == yes); 217 assert((no | unknown) == unknown); 218 assert((yes | unknown) == yes); 219 assert((unknown | no) == unknown); 220 assert((unknown | yes) == yes); 221 assert((unknown | unknown) == unknown); 222 223 // and 224 assert((no & no) == no); 225 assert((no & yes) == no); 226 assert((yes & no) == no); 227 assert((yes & yes) == yes); 228 assert((no & unknown) == no); 229 assert((unknown & no) == no); 230 assert((unknown & unknown) == unknown); 231 assert((yes & unknown) == unknown); 232 assert((unknown & yes) == unknown); 233 234 // exclusive or 235 assert((yes ^ yes) == no); 236 assert((no ^ no) == no); 237 assert((no ^ yes) == yes); 238 assert((yes ^ no) == yes); 239 assert((no ^ unknown) == unknown); 240 assert((yes ^ unknown) == unknown); 241 assert((unknown ^ no) == unknown); 242 assert((unknown ^ yes) == unknown); 243 assert((unknown ^ unknown) == unknown); 244 } 245 } 246 247 /** Tristate: Three-state logic. 248 */ 249 struct TristateCond 250 { 251 @safe pure nothrow @nogc: 252 253 enum defaultCode = 0; 254 255 enum no = make(defaultCode); 256 enum yes = make(1); 257 enum unknown = make(4); 258 259 this(bool b) 260 { 261 _v = b ? yes._v : no._v; 262 } 263 264 void opAssign(bool b) 265 { 266 _v = b ? yes._v : no._v; 267 } 268 269 TristateCond opUnary(string s)() if (s == "~") 270 { 271 return this == unknown ? this : make(!_v); 272 } 273 274 TristateCond opBinary(string s)(TristateCond rhs) if (s == "|") 275 { 276 // | yields 0, 1, 4, 5 277 auto v = _v | rhs._v; 278 return v == 4 ? unknown : make(v & 1); 279 } 280 281 TristateCond opBinary(string s)(TristateCond rhs) if (s == "&") 282 { 283 // & yields 0, 1, 4 284 return make(_v & rhs._v); 285 } 286 287 TristateCond opBinary(string s)(TristateCond rhs) if (s == "^") 288 { 289 // + yields 0, 1, 2, 4, 5, 8 290 auto v = _v + rhs._v; 291 return v >= 4 ? unknown : make(!!v); 292 } 293 294 private: 295 ubyte _v = defaultCode; 296 static TristateCond make(ubyte b) 297 { 298 TristateCond r = void; 299 r._v = b; 300 return r; 301 } 302 } 303 304 @safe pure nothrow @nogc unittest 305 { 306 TristateCond a; 307 assert(a == TristateCond.no); 308 static assert(!is(typeof({ if (a) {} }))); 309 assert(!is(typeof({ auto b = TristateCond(3); }))); 310 a = true; 311 assert(a == TristateCond.yes); 312 a = false; 313 assert(a == TristateCond.no); 314 a = TristateCond.unknown; 315 TristateCond b; 316 b = a; 317 assert(b == a); 318 auto c = a | b; 319 assert(c == TristateCond.unknown); 320 assert((a & b) == TristateCond.unknown); 321 a = true; 322 assert(~a == TristateCond.no); 323 a = true; 324 b = false; 325 assert((a ^ b) == TristateCond.yes); 326 }