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