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) && 52 rhs._v.among!(yes._v, no._v)) 53 return _v | rhs._v; 54 else if (_v == yes._v || 55 rhs._v == yes._v) 56 return yes; 57 else if (_v == no._v) 58 return rhs._v; 59 else if (rhs._v == no._v) 60 return _v; 61 else if (_v == rhs._v) // both likely or unlikely or unknown 62 return _v; 63 else 64 return unknown; 65 } 66 67 // Fuzzy opBinary(string s)(Fuzzy rhs) if (s == "&") 68 // { 69 // return make(_v & rhs._v); 70 // } 71 72 // Fuzzy opBinary(string s)(Fuzzy rhs) if (s == "^") 73 // { 74 // auto v = _v + rhs._v; 75 // return v >= 4 ? unknown : make(!!v); 76 // } 77 78 private: 79 ubyte _v = defaultCode; 80 static Fuzzy make(ubyte b) 81 { 82 Fuzzy r = void; 83 r._v = b; 84 return r; 85 } 86 } 87 88 @safe pure nothrow @nogc unittest 89 { 90 alias T = Fuzzy; 91 T a; 92 assert(a == T.no); 93 94 a = true; 95 assert(a == T.yes); 96 97 a = T.likely; 98 assert(a == T.likely); 99 100 a = T.unlikely; 101 assert(a == T.unlikely); 102 103 with (T) 104 { 105 assert(~no == yes); 106 assert(no == ~yes); 107 assert(~unlikely == likely); 108 assert(unlikely == ~likely); 109 } 110 } 111 112 /** State being either `yes`, `no` or `unknown`. 113 */ 114 struct Tristate 115 { 116 @safe pure nothrow @nogc: 117 118 enum defaultCode = 0; 119 120 enum no = make(defaultCode); 121 enum yes = make(2); 122 enum unknown = make(6); 123 124 this(bool b) 125 { 126 _v = b ? yes._v : no._v; 127 } 128 129 void opAssign(bool b) 130 { 131 _v = b ? yes._v : no._v; 132 } 133 134 Tristate opUnary(string s)() if (s == "~") => make((193 >> _v & 3) << 1); 135 Tristate opBinary(string s)(Tristate rhs) if (s == "|") => make((12756 >> (_v + rhs._v) & 3) << 1); 136 Tristate opBinary(string s)(Tristate rhs) if (s == "&") => make((13072 >> (_v + rhs._v) & 3) << 1); 137 Tristate opBinary(string s)(Tristate rhs) if (s == "^") => make((13252 >> (_v + rhs._v) & 3) << 1); 138 139 private: 140 ubyte _v = defaultCode; 141 static Tristate make(ubyte b) 142 { 143 Tristate r = void; 144 r._v = b; 145 return r; 146 } 147 } 148 149 @safe pure nothrow @nogc unittest 150 { 151 alias T = Tristate; 152 T a; 153 assert(a == T.no); 154 static assert(!is(typeof({ if (a) {} }))); 155 assert(!is(typeof({ auto b = T(3); }))); 156 157 a = true; 158 assert(a == T.yes); 159 160 a = false; 161 assert(a == T.no); 162 163 a = T.unknown; 164 T b; 165 166 b = a; 167 assert(b == a); 168 169 auto c = a | b; 170 assert(c == T.unknown); 171 assert((a & b) == T.unknown); 172 173 a = true; 174 assert(~a == T.no); 175 176 a = true; 177 b = false; 178 assert((a ^ b) == T.yes); 179 180 with (T) 181 { 182 // not 183 assert(~no == yes); 184 assert(~yes == no); 185 assert(~unknown == unknown); 186 187 // or 188 assert((no | no) == no); 189 assert((no | yes) == yes); 190 assert((yes | no) == yes); 191 assert((yes | yes) == yes); 192 assert((no | unknown) == unknown); 193 assert((yes | unknown) == yes); 194 assert((unknown | no) == unknown); 195 assert((unknown | yes) == yes); 196 assert((unknown | unknown) == unknown); 197 198 // and 199 assert((no & no) == no); 200 assert((no & yes) == no); 201 assert((yes & no) == no); 202 assert((yes & yes) == yes); 203 assert((no & unknown) == no); 204 assert((unknown & no) == no); 205 assert((unknown & unknown) == unknown); 206 assert((yes & unknown) == unknown); 207 assert((unknown & yes) == unknown); 208 209 // exclusive or 210 assert((yes ^ yes) == no); 211 assert((no ^ no) == no); 212 assert((no ^ yes) == yes); 213 assert((yes ^ no) == yes); 214 assert((no ^ unknown) == unknown); 215 assert((yes ^ unknown) == unknown); 216 assert((unknown ^ no) == unknown); 217 assert((unknown ^ yes) == unknown); 218 assert((unknown ^ unknown) == unknown); 219 } 220 } 221 222 /** Tristate: Three-state logic. 223 */ 224 struct TristateCond 225 { 226 @safe pure nothrow @nogc: 227 228 enum defaultCode = 0; 229 230 enum no = make(defaultCode); 231 enum yes = make(1); 232 enum unknown = make(4); 233 234 this(bool b) 235 { 236 _v = b ? yes._v : no._v; 237 } 238 239 void opAssign(bool b) 240 { 241 _v = b ? yes._v : no._v; 242 } 243 244 TristateCond opUnary(string s)() if (s == "~") 245 => this == unknown ? this : make(!_v); 246 247 TristateCond opBinary(string s)(TristateCond rhs) if (s == "|") 248 { 249 // | yields 0, 1, 4, 5 250 auto v = _v | rhs._v; 251 return v == 4 ? unknown : make(v & 1); 252 } 253 254 TristateCond opBinary(string s)(TristateCond rhs) if (s == "&") 255 => make(_v & rhs._v); // & yields 0, 1, 4 256 257 TristateCond opBinary(string s)(TristateCond rhs) if (s == "^") 258 { 259 // + yields 0, 1, 2, 4, 5, 8 260 auto v = _v + rhs._v; 261 return v >= 4 ? unknown : make(!!v); 262 } 263 264 private: 265 ubyte _v = defaultCode; 266 static TristateCond make(ubyte b) 267 { 268 TristateCond r = void; 269 r._v = b; 270 return r; 271 } 272 } 273 274 @safe pure nothrow @nogc unittest 275 { 276 TristateCond a; 277 assert(a == TristateCond.no); 278 static assert(!is(typeof({ if (a) {} }))); 279 assert(!is(typeof({ auto b = TristateCond(3); }))); 280 a = true; 281 assert(a == TristateCond.yes); 282 a = false; 283 assert(a == TristateCond.no); 284 a = TristateCond.unknown; 285 TristateCond b; 286 b = a; 287 assert(b == a); 288 auto c = a | b; 289 assert(c == TristateCond.unknown); 290 assert((a & b) == TristateCond.unknown); 291 a = true; 292 assert(~a == TristateCond.no); 293 a = true; 294 b = false; 295 assert((a ^ b) == TristateCond.yes); 296 }