@@ -0,0 +1,1145 @@
1+using System;
2+using System.Collections.Generic;
3+using System.Linq;
4+
5+namespace SolveAvdoshin
6+{
7+ public static class BooleanFunctions
8+ {
9+ static readonly string[] AvdoshinNames = {
10+ "ОБЩИЙ",
11+ "NOR",
12+ "NAND",
13+ "0, IMP",
14+ "1, COIMP",
15+ "IMP, COIMP",
16+ "XOR, IMP",
17+ "EQV, COIMP",
18+ "NOT, IMP",
19+ "NOT, COIMP",
20+ "NOT, OR",
21+ "NOT, AND",
22+ "0, EQV, AND",
23+ "1, XOR, OR",
24+ "0, EQV, OR",
25+ "1, XOR, AND",
26+ "XOR, EQV, OR",
27+ "EQV, XOR, AND",
28+ };
29+
30+ static readonly BooleanOperation[][] AvdoshinBases = {
31+ new BooleanOperation[] {
32+ BooleanOperation.Zero,
33+ BooleanOperation.One,
34+ BooleanOperation.NotA,
35+ BooleanOperation.NotB,
36+ BooleanOperation.NOR,
37+ BooleanOperation.CoImp,
38+ BooleanOperation.BCoImp,
39+ BooleanOperation.Xor,
40+ BooleanOperation.NAND,
41+ BooleanOperation.And,
42+ BooleanOperation.Eq,
43+ BooleanOperation.B,
44+ BooleanOperation.BImp,
45+ BooleanOperation.A,
46+ BooleanOperation.Imp,
47+ BooleanOperation.Or,
48+ },
49+ new BooleanOperation[] { BooleanOperation.NOR, },
50+ new BooleanOperation[] { BooleanOperation.NAND, },
51+ new BooleanOperation[] { BooleanOperation.Imp, },
52+ new BooleanOperation[] { BooleanOperation.CoImp, },
53+ new BooleanOperation[] { BooleanOperation.Imp, BooleanOperation.CoImp, },
54+ new BooleanOperation[] { BooleanOperation.Xor, BooleanOperation.Imp, },
55+ new BooleanOperation[] { BooleanOperation.Eq, BooleanOperation.CoImp, },
56+ new BooleanOperation[] { BooleanOperation.NotA, BooleanOperation.Imp, },
57+ new BooleanOperation[] { BooleanOperation.NotA, BooleanOperation.CoImp, },
58+ new BooleanOperation[] { BooleanOperation.NotA, BooleanOperation.Or, },
59+ new BooleanOperation[] { BooleanOperation.NotA, BooleanOperation.And, },
60+ new BooleanOperation[] { BooleanOperation.Eq, BooleanOperation.And, },
61+ new BooleanOperation[] { BooleanOperation.Xor, BooleanOperation.Or, },
62+ new BooleanOperation[] { BooleanOperation.Eq, BooleanOperation.Or, },
63+ new BooleanOperation[] { BooleanOperation.Xor, BooleanOperation.And, },
64+ new BooleanOperation[] { BooleanOperation.Xor, BooleanOperation.Eq, BooleanOperation.Or, },
65+ new BooleanOperation[] { BooleanOperation.Eq, BooleanOperation.Xor, BooleanOperation.And, },
66+ };
67+
68+ static readonly BooleanVariable[][] AvdoshinVars = {
69+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
70+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
71+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
72+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, BooleanVariable.Zero, },
73+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, BooleanVariable.One, },
74+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
75+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
76+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
77+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
78+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
79+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
80+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
81+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, BooleanVariable.Zero, },
82+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, BooleanVariable.One, },
83+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, BooleanVariable.Zero, },
84+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, BooleanVariable.One, },
85+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
86+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
87+ };
88+
89+ public static void PrintMinimaInAvdoshinBases(int n, bool minOps, bool showBlocks)
90+ {
91+ Console.WriteLine("\nМинимальные представления f_" + n + " в базисах (для рисования в винлогике):");
92+
93+ Console.WriteLine(" ☻ Базис Выражение");
94+ Console.WriteLine();
95+
96+ for(int i = 0; i < AvdoshinBases.Length; i++) {
97+ Console.Write("{0} — {1}", i.ToString("D2"), AvdoshinNames[i].PadRight(18));
98+
99+ try {
100+ var ex = BooleanExpression.FindMininalExpressionInBasis(n, AvdoshinBases[i], AvdoshinVars[i],
101+ mode: minOps ? BooleanExpression.ExpressionSearchMode.CountOps :
102+ BooleanExpression.ExpressionSearchMode.CountBlocks);
103+
104+ Console.WriteLine(ex.ToString());
105+
106+ if(showBlocks) {
107+ if(ex.CountOps() == ex.CountBlocks()) {
108+ Console.WriteLine("\tСколько операций, столько и блоков");
109+ }
110+ else {
111+ foreach(string s in new HashSet<string>(ex.GetSetOfAllBlockStrings()).OrderByDescending(x => x.Length).Skip(1)) {
112+ if(s != ex.ToString()) {
113+ Console.WriteLine("\t" + s);
114+ }
115+ }
116+
117+ Console.WriteLine("\tИтого: операций: {0}, блоков: {1}", ex.CountOps(), ex.CountBlocks());
118+ }
119+ }
120+ }
121+ catch(CouldntFindExpressionException) {
122+ Console.WriteLine("не нашлось");
123+ }
124+ }
125+ }
126+
127+ static readonly BooleanVariable[][] VarLists = new BooleanVariable[][] {
128+ new BooleanVariable[] { BooleanVariable.A, },
129+ new BooleanVariable[] { BooleanVariable.B, },
130+ new BooleanVariable[] { BooleanVariable.C, },
131+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, },
132+ new BooleanVariable[] { BooleanVariable.B, BooleanVariable.C, },
133+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.C, },
134+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
135+ };
136+
137+ static readonly string[] DerivStrings = new string[] {
138+ "F'_A",
139+ "F'_B",
140+ "F'_C",
141+ "F''_AB",
142+ "F''_BC",
143+ "F''_AC",
144+ "F'''_ABC",
145+ };
146+
147+ static readonly string[] DirDerivStrings = new string[] {
148+ "F'_A",
149+ "F'_B",
150+ "F'_C",
151+ "F'_(A,B)",
152+ "F'_(B,C)",
153+ "F'_(A,C)",
154+ "F'_(A,B,C)",
155+ };
156+
157+ static void PrintJustTruthTable(BooleanFunction f)
158+ {
159+ Console.WriteLine((new BooleanFunction(0x0F)).ToString("A"));
160+ Console.WriteLine((new BooleanFunction(0x33)).ToString("B"));
161+ Console.WriteLine((new BooleanFunction(0x55)).ToString("C"));
162+
163+ Console.WriteLine(f.ToString("F"));
164+ }
165+
166+ public static void PrintDerivatives(int n)
167+ {
168+ BooleanFunction f = new BooleanFunction((byte)n);
169+
170+ PrintJustTruthTable(f);
171+
172+ for(int i = 0; i < 7; i++) {
173+ Console.WriteLine(f.Deriv(VarLists[i]).ToString(DerivStrings[i]));
174+ }
175+
176+ Console.WriteLine();
177+ }
178+
179+ public static void Print2DirectionalDerivatives(int n)
180+ {
181+ BooleanFunction f = new BooleanFunction((byte)n);
182+
183+ PrintJustTruthTable(f);
184+
185+ for(int i = 3; i <= 5; i++) {
186+ Console.WriteLine(f.DirectionalDeriv(VarLists[i]).ToString(DirDerivStrings[i]));
187+ }
188+
189+ Console.WriteLine();
190+ }
191+
192+ public static void Print3DirectionalDerivative(int n)
193+ {
194+ BooleanFunction f = new BooleanFunction((byte)n);
195+
196+ PrintJustTruthTable(f);
197+
198+ Console.WriteLine(f.DirectionalDeriv(VarLists[6]).ToString(DirDerivStrings[6]));
199+
200+ Console.WriteLine();
201+ }
202+
203+ public static void PrintExpressionsForDerivatives(int n)
204+ {
205+ BooleanFunction f = new BooleanFunction((byte)n);
206+
207+ for(int i = 0; i < 7; i++) {
208+ Console.WriteLine(DerivStrings[i] + " = " + BooleanExpression.FindMininalExpressionInBasis(
209+ f.Deriv(VarLists[i]).Eval(), AvdoshinBases[0], AvdoshinVars[0]).ToString());
210+ }
211+
212+ Console.WriteLine();
213+ }
214+
215+ public static void PrintExpressionsFor2DirDerivatives(int n)
216+ {
217+ BooleanFunction f = new BooleanFunction((byte)n);
218+
219+ for(int i = 3; i <= 5; i++) {
220+ Console.WriteLine(DirDerivStrings[i] + " = " + BooleanExpression.FindMininalExpressionInBasis(
221+ f.DirectionalDeriv(VarLists[i]).Eval(), AvdoshinBases[0], AvdoshinVars[0]).ToString());
222+ }
223+
224+ Console.WriteLine();
225+ }
226+
227+ public static void PrintExpressionFor3DirDerivative(int n)
228+ {
229+ BooleanFunction f = new BooleanFunction((byte)n);
230+
231+ Console.WriteLine(DirDerivStrings[6] + " = " + BooleanExpression.FindMininalExpressionInBasis(
232+ f.DirectionalDeriv(VarLists[6]).Eval(), AvdoshinBases[0], AvdoshinVars[0]).ToString());
233+
234+ Console.WriteLine();
235+ }
236+
237+ static readonly string[] ReprStrings = new string[] {
238+ "(0,0,0)",
239+ "(0,0,1)",
240+ "(0,1,0)",
241+ "(0,1,1)",
242+ "(1,0,0)",
243+ "(1,0,1)",
244+ "(1,1,0)",
245+ "(1,1,1)",
246+ };
247+
248+ public static void PrintMaclauren1XorAnd(int n)
249+ {
250+ BooleanFunction f = new BooleanFunction((byte)n);
251+
252+ Console.WriteLine("F(A,B,C) = " + f.GetTailorStringXor(0));
253+
254+ Console.WriteLine();
255+ }
256+
257+ public static void PrintTailor1XorAnd(int n)
258+ {
259+ BooleanFunction f = new BooleanFunction((byte)n);
260+
261+ for(int i = 0; i < 8; i++) {
262+ Console.WriteLine(ReprStrings[i] + ": F(A,B,C) = " + f.GetTailorStringXor(i));
263+ }
264+
265+ Console.WriteLine();
266+ }
267+
268+ public static void PrintMaclauren0EqOr(int n)
269+ {
270+ BooleanFunction f = new BooleanFunction((byte)n);
271+
272+ Console.WriteLine("F(A,B,C) = " + f.GetTailorStringEq(7));
273+
274+ Console.WriteLine();
275+ }
276+
277+ public static void PrintTailor0EqOr(int n)
278+ {
279+ BooleanFunction f = new BooleanFunction((byte)n);
280+
281+ for(int i = 0; i < 8; i++) {
282+ Console.WriteLine(ReprStrings[i] + ": F(A,B,C) = " + f.GetTailorStringEq(i));
283+ }
284+
285+ Console.WriteLine();
286+ }
287+
288+ public static void PrintClosedClasses(int n)
289+ {
290+ BooleanFunction f = new BooleanFunction((byte)n);
291+
292+ PostClosedClasses.CheckConservationZero(f, true);
293+
294+ PostClosedClasses.CheckConservationOne(f, true);
295+
296+ PostClosedClasses.CheckSelfDuality(f, true);
297+
298+ PostClosedClasses.CheckMonotony(f, true);
299+
300+ PostClosedClasses.CheckLinearity(f, true);
301+
302+ Console.WriteLine();
303+ }
304+
305+ // Закомменченные функции не рассматриваются в силу избыточности
306+ static readonly Tuple<BooleanOperation, bool[]>[] BinariesAndClasses = {
307+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.NotA, new bool[5] { false, false, true, false, true, }),
308+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.Zero, new bool[5] { true, false, false, true, true, }),
309+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.One, new bool[5] { false, true, false, true, true, }),
310+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.And, new bool[5] { true, true, false, true, false, }),
311+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.CoImp, new bool[5] { true, false, false, false, false, }),
312+// new Tuple<BooleanOperation, bool[]>(BooleanOperation.A, new bool[5] { ),
313+// new Tuple<BooleanOperation, bool[]>(BooleanOperation.BCoImp, new bool[5] { } ),
314+// new Tuple<BooleanOperation, bool[]>(BooleanOperation.B, new bool[5] { } ),
315+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.Xor, new bool[5] { true, false, false, false, true, }),
316+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.Or, new bool[5] { true, true, false, true, false, }),
317+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.NOR, new bool[5] { false, false, false, false, false, }),
318+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.Eq, new bool[5] { false, true, false, false, true, }),
319+// new Tuple<BooleanOperation, bool[]>(BooleanOperation.NotB, new bool[5] { } ),
320+// new Tuple<BooleanOperation, bool[]>(BooleanOperation.BImp, new bool[5] { } ),
321+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.Imp, new bool[5] { false, true, false, false, false, }),
322+ new Tuple<BooleanOperation, bool[]>(BooleanOperation.NAND, new bool[5] { false, false, false, false, false, }),
323+ };
324+
325+ public static void PrintRepresentBinariesInF(int n, bool noLookBack)
326+ {
327+ bool[] functionClasses = PostClosedClasses.GetFunctionClasses(new BooleanFunction((byte)n));
328+
329+ var availableExpressions = new List<BooleanExpression> {
330+ new VarExpression(BooleanVariable.A),
331+ new VarExpression(BooleanVariable.B),
332+ };
333+
334+ foreach(var t in BinariesAndClasses) {
335+ bool representable = true;
336+
337+ for(int i = 0; i < 5; i++) {
338+ if(functionClasses[i] && !t.Item2[i]) {
339+ representable = false;
340+ break;
341+ }
342+ }
343+
344+ if(!representable)
345+ continue;
346+
347+ try {
348+ var targetExpression = new OpExpression(t.Item1, BooleanVariable.A, BooleanVariable.B);
349+
350+ Console.WriteLine(targetExpression.ToString() + " = " +
351+ TertiaryOpExpression.FindMininalExpressionForBinary(targetExpression,
352+ new BooleanFunction((byte)n), availableExpressions));
353+
354+ if(!noLookBack)
355+ availableExpressions.Add(targetExpression);
356+ }
357+ catch(CouldntFindExpressionException) {
358+
359+ }
360+ }
361+ }
362+ }
363+
364+ class TertiaryOpExpression : BooleanExpression
365+ {
366+ BooleanFunction F;
367+ BooleanExpression First, Second, Third;
368+
369+ public TertiaryOpExpression(BooleanFunction f, BooleanExpression first, BooleanExpression second, BooleanExpression third)
370+ {
371+ F = f;
372+ First = first;
373+ Second = second;
374+ Third = third;
375+ }
376+
377+ public override bool Equals(object obj)
378+ {
379+ return base.Equals(obj);
380+ }
381+
382+ public override int GetHashCode()
383+ {
384+ return base.GetHashCode();
385+ }
386+
387+ public override string ToString()
388+ {
389+ return String.Format("F({0},{1},{2})", First.ToString(), Second.ToString(), Third.ToString());
390+ }
391+
392+ public override int CountOps()
393+ {
394+ return 1 + First.CountOps() + Second.CountOps() + Third.CountOps();
395+ }
396+
397+ public override BooleanExpression Clone()
398+ {
399+ return new TertiaryOpExpression(F, First, Second, Third);
400+ }
401+
402+ public override byte Eval()
403+ {
404+ int res = 0;
405+
406+ for(int i = 0; i < 8; i++) {
407+ res *= 2;
408+ res += F.EvalAt(First.EvalAt(i) * 4 + Second.EvalAt(i) * 2 + Third.EvalAt(i));
409+ }
410+
411+ return (byte)res;
412+ }
413+
414+ public override IEnumerable<string> GetSetOfAllBlockStrings()
415+ {
416+ throw new NotImplementedException();
417+ }
418+
419+ static public IEnumerable<TertiaryOpExpression> CombineTertiary(BooleanFunction f,
420+ BooleanExpression firstExpression, BooleanExpression anotherExpression, BooleanExpression thirdExpression)
421+ {
422+ yield return new TertiaryOpExpression(f, firstExpression.Clone(), anotherExpression.Clone(),
423+ thirdExpression.Clone());
424+ yield return new TertiaryOpExpression(f, firstExpression.Clone(), thirdExpression.Clone(),
425+ anotherExpression.Clone());
426+ yield return new TertiaryOpExpression(f, anotherExpression.Clone(), firstExpression.Clone(),
427+ thirdExpression.Clone());
428+ yield return new TertiaryOpExpression(f, thirdExpression.Clone(), firstExpression.Clone(),
429+ anotherExpression.Clone());
430+ yield return new TertiaryOpExpression(f, anotherExpression.Clone(), thirdExpression.Clone(),
431+ firstExpression.Clone());
432+ yield return new TertiaryOpExpression(f, thirdExpression.Clone(), anotherExpression.Clone(),
433+ firstExpression.Clone());
434+ }
435+
436+ public static BooleanExpression FindMininalExpressionForBinary(BooleanExpression targetBinary, BooleanFunction f,
437+ List<BooleanExpression> availableExpressions)
438+ {
439+ var queue = new ImprovisedPriorityQueue<BooleanExpression>(20);
440+ var knownTruthTables = new HashSet<byte>();
441+ var knownExpressions = new HashSet<BooleanExpression>();
442+
443+ foreach(var expression in availableExpressions) {
444+ queue.TryEnqueue(expression, 1);
445+ }
446+
447+ while(queue.Count != 0) {
448+ var curExperession = queue.Dequeue();
449+
450+ byte truthTable = curExperession.Eval();
451+
452+ if(knownTruthTables.Contains(truthTable)) {
453+ continue;
454+ }
455+
456+ if((curExperession.Eval() & 0xAA) == (targetBinary.Eval() & 0xAA)) {
457+ return curExperession;
458+ }
459+
460+ knownExpressions.Add(curExperession);
461+ knownTruthTables.Add(truthTable);
462+
463+ foreach(var anotherExpression in knownExpressions) {
464+ foreach(var thirdExpression in knownExpressions) {
465+ foreach(var neighbourExpression in CombineTertiary(f, curExperession, anotherExpression, thirdExpression)) {
466+ queue.TryEnqueue(neighbourExpression, neighbourExpression.CountOps());
467+ }
468+ }
469+ }
470+ }
471+
472+ throw new CouldntFindExpressionException();
473+ }
474+ }
475+
476+ static class PostClosedClasses
477+ {
478+ public static bool[] GetFunctionClasses(BooleanFunction f)
479+ {
480+ return new bool[] { CheckConservationZero(f), CheckConservationOne(f), CheckSelfDuality(f), CheckMonotony(f), CheckLinearity(f), };
481+ }
482+
483+ public static bool CheckConservationZero(BooleanFunction f, bool verbose = false)
484+ {
485+ if(f.EvalAt(0) == 0) {
486+ if(verbose)
487+ Console.WriteLine("F ∈ T_0, т.к. F(0,0,0) = 0");
488+
489+ return true;
490+ }
491+ else {
492+ if(verbose)
493+ Console.WriteLine("F ∉ T_0, т.к. F(0,0,0) = 1");
494+
495+ return false;
496+ }
497+ }
498+
499+ public static bool CheckConservationOne(BooleanFunction f, bool verbose = false)
500+ {
501+ if(f.EvalAt(7) == 1) {
502+ if(verbose)
503+ Console.WriteLine("F ∈ T_1, т.к. F(1,1,1) = 1");
504+
505+ return true;
506+ }
507+ else {
508+ if(verbose)
509+ Console.WriteLine("F ∉ T_1, т.к. F(1,1,1) = 0");
510+
511+ return false;
512+ }
513+ }
514+
515+ static string PointAsString(int a)
516+ {
517+ return ((a >> 2) & 1) + "," + ((a >> 1) & 1) + "," + (a & 1);
518+ }
519+
520+ public static bool CheckSelfDuality(BooleanFunction f, bool verbose = false)
521+ {
522+ for(int i = 0; i < 8; i++) {
523+ if(f.EvalAt(i) == f.EvalAt(7 - i)) {
524+ if(verbose)
525+ Console.WriteLine("F ∉ T_*, т.к. F({0}) = F({1}) = {2}", PointAsString(i), PointAsString(7 - i), f.EvalAt(i));
526+
527+ return false;
528+ }
529+ }
530+
531+ if(verbose)
532+ Console.WriteLine("F ∈ T_*, т.к. я на всех наборах проверял, честно!");
533+
534+ return true;
535+ }
536+
537+ static bool AreAdjacent(int a, int b)
538+ {
539+ bool res = false;
540+
541+ for(int i = 0; i < 3; i++) {
542+ if(((a >> i) & 1) != ((b >> i) & 1)) {
543+ if(!res)
544+ res = true;
545+ else {
546+ res = false;
547+ break;
548+ }
549+ }
550+ }
551+
552+ return res;
553+ }
554+
555+ static bool IsLessThan(int a, int b)
556+ {
557+ int onesA = 0, onesB = 0;
558+
559+ for(int i = 0; i < 3; i++) {
560+ onesA += (a >> i) & 1;
561+ onesB += (b >> i) & 1;
562+ }
563+
564+ return onesA < onesB;
565+ }
566+
567+ public static bool CheckMonotony(BooleanFunction f, bool verbose = false)
568+ {
569+ for(int i = 0; i < 8; i++) {
570+ for(int j = 0; j < 8; j++) {
571+ if(!AreAdjacent(i, j) || !IsLessThan(i, j))
572+ continue;
573+
574+ if(f.EvalAt(i) > f.EvalAt(j)) {
575+ if(verbose)
576+ Console.WriteLine("F ∉ T_<=, т.к. F({0}) > F({1})", PointAsString(i), PointAsString(j));
577+
578+ return false;
579+ }
580+ }
581+ }
582+
583+ if(verbose)
584+ Console.WriteLine("F ∈ T_<=, т.к. я на всех наборах проверял, честно!");
585+
586+ return true;
587+ }
588+
589+ public static bool CheckLinearity(BooleanFunction f, bool verbose = false)
590+ {
591+ string zhegalkinRep = f.GetTailorStringXor(0);
592+
593+ foreach(string s in new string[] { "AB", "BC", "AC", "ABC", }) {
594+ if(zhegalkinRep.Contains(s)) {
595+ if(verbose)
596+ Console.WriteLine("F ∉ T_L, т.к. F(A,B,C) = " + zhegalkinRep);
597+
598+ return false;
599+ }
600+ }
601+
602+ if(verbose)
603+ Console.WriteLine("F ∈ T_L, т.к. F(A,B,C) = " + zhegalkinRep);
604+
605+ return true;
606+ }
607+ }
608+
609+ class BooleanFunction
610+ {
611+ byte TruthTable;
612+
613+ public BooleanFunction(byte n)
614+ {
615+ TruthTable = n;
616+ }
617+
618+ public byte Eval()
619+ {
620+ return TruthTable;
621+ }
622+
623+ public int EvalAt(int n)
624+ {
625+ return (TruthTable >> (7 - n)) & 1;
626+ }
627+
628+ public new string ToString()
629+ {
630+ return ToString("F");
631+ }
632+
633+ public string ToString(string caption)
634+ {
635+ int n = TruthTable;
636+ char[] digits = new char[8];
637+
638+ for(int i = 0; i < 8; i++) {
639+ digits[i] += (n % 2).ToString()[0];
640+ n /= 2;
641+ }
642+
643+ Array.Reverse(digits);
644+
645+ return caption.PadRight(10) + " " + String.Join(" ", digits);
646+ }
647+
648+ static readonly BooleanVariable[][] VarLists = new BooleanVariable[][] {
649+ new BooleanVariable[] { },
650+ new BooleanVariable[] { BooleanVariable.A, },
651+ new BooleanVariable[] { BooleanVariable.B, },
652+ new BooleanVariable[] { BooleanVariable.C, },
653+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, },
654+ new BooleanVariable[] { BooleanVariable.B, BooleanVariable.C, },
655+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.C, },
656+ new BooleanVariable[] { BooleanVariable.A, BooleanVariable.B, BooleanVariable.C, },
657+ };
658+
659+ static readonly string[][] StringLists = new string[][] {
660+ new string[] { },
661+ new string[] { "A", },
662+ new string[] { "B", },
663+ new string[] { "C", },
664+ new string[] { "A", "B", },
665+ new string[] { "B", "C", },
666+ new string[] { "A", "C", },
667+ new string[] { "A", "B", "C", },
668+ };
669+
670+ bool VariablePresentAt(int point, string variable)
671+ {
672+ switch(variable) {
673+ case "A":
674+ return ((point >> 2) & 1) == 1;
675+ case "B":
676+ return ((point >> 1) & 1) == 1;
677+ case "C":
678+ return (point & 1) == 1;
679+ default:
680+ throw new ArgumentException("VariablePresentAt only works for BooleanVariables A, B and C");
681+ }
682+ }
683+
684+ public string GetTailorStringXor(int point)
685+ {
686+ List<string> outerTerms = new List<string>();
687+
688+ if(((Eval() >> (7 - point)) & 1) == 1)
689+ outerTerms.Add("1");
690+
691+ for(int i = 1; i < 8; i++) { // terms
692+ if(((Deriv(VarLists[i]).Eval() >> (7 - point)) & 1) == 1) {
693+ List<string> factors = new List<string>();
694+
695+ foreach(var variable in StringLists[i]) {
696+ if(VariablePresentAt(point, variable))
697+ factors.Add("(" + variable + " ⊕ 1)");
698+ else
699+ factors.Add(variable);
700+ }
701+
702+ outerTerms.Add(String.Join("", factors));
703+ }
704+ }
705+
706+ return String.Join(" ⊕ ", outerTerms);
707+ }
708+
709+ public string GetTailorStringEq(int point)
710+ {
711+ List<string> outerTerms = new List<string>();
712+
713+ if(((Eval() >> (7 - point)) & 1) == 0)
714+ outerTerms.Add("0");
715+
716+ for(int i = 1; i < 8; i++) { // terms
717+ if(((Deriv(VarLists[i]).Eval() >> (7 - point)) & 1) == 1) {
718+ List<string> factors = new List<string>();
719+
720+ foreach(var variable in StringLists[i]) {
721+ if(!VariablePresentAt(point, variable))
722+ factors.Add("(" + variable + " ≡ 0)");
723+ else
724+ factors.Add(variable);
725+ }
726+
727+ if(factors.Count == 1)
728+ outerTerms.Add(String.Join(" + ", factors));
729+ else
730+ outerTerms.Add("(" + String.Join(" + ", factors) + ")");
731+ }
732+ }
733+
734+ return String.Join(" ≡ ", outerTerms);
735+ }
736+
737+ public BooleanFunction DirectionalDeriv(params BooleanVariable[] variables)
738+ {
739+ Dictionary<BooleanVariable, bool> values;
740+
741+ int res = 0;
742+
743+ for(int i = 0; i < 8; i++) {
744+ res *= 2;
745+
746+ values = new Dictionary<BooleanVariable, bool> { { BooleanVariable.A, i / 4 == 1 },
747+ { BooleanVariable.B, i / 2 % 2 == 1 },
748+ { BooleanVariable.C, i % 2 == 1 },
749+ };
750+
751+ BooleanFunction leftOp = this;
752+ BooleanFunction rightOp = this;
753+
754+ foreach(var variable in variables) {
755+ leftOp = leftOp.FixVar(variable, values[variable] ? 1 : 0);
756+ rightOp = rightOp.FixVar(variable, values[variable] ? 0 : 1);
757+ }
758+
759+ res += leftOp.EvalAt(i) ^ rightOp.EvalAt(i);
760+ }
761+
762+ return new BooleanFunction((byte)res);
763+ }
764+
765+ public BooleanFunction Deriv(params BooleanVariable[] variables)
766+ {
767+ BooleanFunction res = this;
768+
769+ foreach(var variable in variables) {
770+ res = new BooleanFunction((byte)(res.FixVar(variable, 0).Eval() ^ res.FixVar(variable, 1).Eval()));
771+ }
772+
773+ return res;
774+ }
775+
776+ BooleanFunction FixVar(BooleanVariable variable, int value)
777+ {
778+ int res = 0;
779+
780+ switch(variable) {
781+ case BooleanVariable.A:
782+ res = FixA(value);
783+ break;
784+ case BooleanVariable.B:
785+ res = FixB(value);
786+ break;
787+ case BooleanVariable.C:
788+ res = FixC(value);
789+ break;
790+ default:
791+ throw new ArgumentException("The variable argument for FixVar should be A, B or C");
792+ }
793+
794+ return new BooleanFunction((byte)res);
795+ }
796+
797+ byte FixA(int value)
798+ {
799+ int res = 0;
800+
801+ if(value == 0) {
802+ res = TruthTable >> 4;
803+ res += (TruthTable >> 4) * 16;
804+ }
805+ else if(value == 1) {
806+ res = TruthTable & 15;
807+ res += (TruthTable & 15) * 16;
808+ }
809+ else {
810+ throw new ArgumentException("Value for Fix[Variable] should be either 0 or 1");
811+ }
812+
813+ return (byte)res;
814+ }
815+
816+ byte FixB(int value)
817+ {
818+ int res = 0;
819+
820+ if(value == 0) {
821+ res += (TruthTable >> 2) & 3;
822+ res += ((TruthTable >> 2) & 3) * 4;
823+ res += ((TruthTable >> 6) & 3) * 16;
824+ res += ((TruthTable >> 6) & 3) * 64;
825+ }
826+ else if(value == 1) {
827+ res += TruthTable & 3;
828+ res += (TruthTable & 3) * 4;
829+ res += ((TruthTable >> 4) & 3) * 16;
830+ res += ((TruthTable >> 4) & 3) * 64;
831+ }
832+ else {
833+ throw new ArgumentException("Value for Fix[Variable] should be either 0 or 1");
834+ }
835+
836+ return (byte)res;
837+ }
838+
839+ byte FixC(int value)
840+ {
841+ int res = 0;
842+
843+ if(value == 0) {
844+ res += (TruthTable >> 1) & 1;
845+ res += ((TruthTable >> 1) & 1) * 2;
846+ res += ((TruthTable >> 3) & 1) * 4;
847+ res += ((TruthTable >> 3) & 1) * 8;
848+ res += ((TruthTable >> 5) & 1) * 16;
849+ res += ((TruthTable >> 5) & 1) * 32;
850+ res += ((TruthTable >> 7) & 1) * 64;
851+ res += ((TruthTable >> 7) & 1) * 128;
852+ }
853+ else if(value == 1) {
854+ res += TruthTable & 1;
855+ res += (TruthTable & 1) * 2;
856+ res += ((TruthTable >> 2) & 1) * 4;
857+ res += ((TruthTable >> 2) & 1) * 8;
858+ res += ((TruthTable >> 4) & 1) * 16;
859+ res += ((TruthTable >> 4) & 1) * 32;
860+ res += ((TruthTable >> 6) & 1) * 64;
861+ res += ((TruthTable >> 6) & 1) * 128;
862+ }
863+ else {
864+ throw new ArgumentException("Value for Fix[Variable] should be either 0 or 1");
865+ }
866+
867+ return (byte)res;
868+ }
869+ }
870+
871+ class CouldntFindExpressionException : Exception
872+ {
873+
874+ }
875+
876+ enum BooleanOperation { Zero, NOR, CoImp, NotA, BCoImp, NotB, Xor, NAND, And, Eq, B, BImp, A, Imp, Or, One };
877+ enum BooleanVariable { A, B, C, Zero, One, };
878+
879+ abstract class BooleanExpression
880+ {
881+ public static readonly string[] OpSymbols = new string[] { "0", "↓", "=/>", "(!A)", "</=", "(!B)", "⨁", "|", "&", "≡", "(B)", "<=", "(A)", "=>", "+", "1", };
882+
883+ abstract public byte Eval();
884+ abstract override public string ToString();
885+ abstract public BooleanExpression Clone();
886+ abstract public int CountOps();
887+
888+ public int EvalAt(int i)
889+ {
890+ return (Eval() >> (7 - i)) & 1;
891+ }
892+
893+ public override int GetHashCode()
894+ {
895+ return ToString().GetHashCode();
896+ }
897+
898+ public bool Equals(BooleanExpression obj)
899+ {
900+ return ToString() == obj.ToString();
901+ }
902+
903+ public abstract IEnumerable<string> GetSetOfAllBlockStrings();
904+
905+ public int CountBlocks()
906+ {
907+ var allBlocks = new HashSet<string>();
908+
909+ foreach(string s in GetSetOfAllBlockStrings()) {
910+ allBlocks.Add(s);
911+ }
912+
913+ return allBlocks.Count;
914+ }
915+
916+ public IEnumerable<BooleanExpression> CombineWith(BooleanExpression anotherExpression,
917+ BooleanOperation[] ops)
918+ {
919+ foreach(var op in ops) {
920+ yield return new OpExpression(op, Clone(), anotherExpression.Clone());
921+ yield return new OpExpression(op, anotherExpression.Clone(), Clone());
922+ }
923+ }
924+
925+ public static string PrintOperation(BooleanOperation op)
926+ {
927+ return OpSymbols[(int)op];
928+ }
929+
930+ public enum ExpressionSearchMode { CountOps, CountBlocks, };
931+ public static BooleanExpression FindMininalExpressionInBasis(int n, BooleanOperation[] ops,
932+ BooleanVariable[] vars, ExpressionSearchMode mode = ExpressionSearchMode.CountOps)
933+ {
934+ var queue = new ImprovisedPriorityQueue<BooleanExpression>(20);
935+ var knownTruthTables = new HashSet<byte>();
936+ var knownExpressions = new HashSet<BooleanExpression>();
937+
938+ foreach(var variable in vars) {
939+ queue.TryEnqueue(new VarExpression(variable), 1);
940+ }
941+
942+ while(queue.Count != 0) {
943+ var curExperession = queue.Dequeue();
944+
945+ byte truthTable = curExperession.Eval();
946+
947+ if(knownTruthTables.Contains(truthTable)) {
948+ continue;
949+ }
950+
951+ if(curExperession.Eval() == n) {
952+ return curExperession;
953+ }
954+
955+ knownExpressions.Add(curExperession);
956+ knownTruthTables.Add(truthTable);
957+
958+ foreach(var anotherExpression in knownExpressions) {
959+ foreach(var neighbourExpression in curExperession.CombineWith(anotherExpression, ops)) {
960+ queue.TryEnqueue(neighbourExpression, mode == ExpressionSearchMode.CountBlocks
961+ ? neighbourExpression.CountBlocks() : neighbourExpression.CountOps());
962+ }
963+ }
964+ }
965+
966+ throw new CouldntFindExpressionException();
967+ }
968+ }
969+
970+ class OpExpression : BooleanExpression
971+ {
972+ BooleanOperation Op;
973+ BooleanExpression Left, Right;
974+
975+ public OpExpression(BooleanOperation op, BooleanExpression left, BooleanExpression right)
976+ {
977+ Op = op;
978+ Left = left;
979+ Right = right;
980+ }
981+
982+ public OpExpression(BooleanOperation op, BooleanVariable left, BooleanVariable right)
983+ {
984+ Op = op;
985+ Left = new VarExpression(left);
986+ Right = new VarExpression(right);
987+ }
988+
989+ public override BooleanExpression Clone()
990+ {
991+ return new OpExpression(Op, Left.Clone(), Right.Clone());
992+ }
993+
994+ public override int CountOps()
995+ {
996+ return Left.CountOps() + Right.CountOps() + 1;
997+ }
998+
999+ public override IEnumerable<string> GetSetOfAllBlockStrings()
1000+ {
1001+ yield return ToString();
1002+
1003+ foreach(string s in Left.GetSetOfAllBlockStrings()) {
1004+ yield return s;
1005+ }
1006+
1007+ foreach(string s in Right.GetSetOfAllBlockStrings()) {
1008+ yield return s;
1009+ }
1010+ }
1011+
1012+ public override byte Eval()
1013+ {
1014+ byte aVal = Left.Eval();
1015+ byte bVal = Right.Eval();
1016+
1017+ int res;
1018+
1019+ switch(Op) {
1020+ case BooleanOperation.Zero:
1021+ res = 0x00;
1022+ break;
1023+ case BooleanOperation.NOR:
1024+ res = ~(aVal | bVal);
1025+ break;
1026+ case BooleanOperation.CoImp:
1027+ res = aVal & ~bVal;
1028+ break;
1029+ case BooleanOperation.NotA:
1030+ res = ~aVal;
1031+ break;
1032+ case BooleanOperation.BCoImp:
1033+ res = ~aVal & bVal;
1034+ break;
1035+ case BooleanOperation.NotB:
1036+ res = ~bVal;
1037+ break;
1038+ case BooleanOperation.Xor:
1039+ res = aVal ^ bVal;
1040+ break;
1041+ case BooleanOperation.NAND:
1042+ res = ~(aVal & bVal);
1043+ break;
1044+ case BooleanOperation.And:
1045+ res = aVal & bVal;
1046+ break;
1047+ case BooleanOperation.Eq:
1048+ res = aVal ^ (~bVal);
1049+ break;
1050+ case BooleanOperation.B:
1051+ res = bVal;
1052+ break;
1053+ case BooleanOperation.BImp:
1054+ res = aVal | ~bVal;
1055+ break;
1056+ case BooleanOperation.A:
1057+ res = aVal;
1058+ break;
1059+ case BooleanOperation.Imp:
1060+ res = ~aVal | bVal;
1061+ break;
1062+ case BooleanOperation.Or:
1063+ res = aVal | bVal;
1064+ break;
1065+ case BooleanOperation.One:
1066+ res = 0xFF;
1067+ break;
1068+ default:
1069+ throw new ArgumentException();
1070+ }
1071+
1072+ return (byte)res;
1073+ }
1074+
1075+ public override string ToString()
1076+ {
1077+ switch(Op) {
1078+ case BooleanOperation.A:
1079+ return Left.ToString();
1080+ case BooleanOperation.B:
1081+ return Right.ToString();
1082+ case BooleanOperation.One:
1083+ case BooleanOperation.Zero:
1084+ return PrintOperation(Op);
1085+ case BooleanOperation.NotA:
1086+ return "!" + Left.ToString();
1087+ case BooleanOperation.NotB:
1088+ return "!" + Right.ToString();
1089+ default:
1090+ return "(" + Left.ToString() + " " + PrintOperation(Op) + " " + Right.ToString() + ")";
1091+ }
1092+ }
1093+ }
1094+
1095+ class VarExpression : BooleanExpression
1096+ {
1097+ static readonly string[] VarSymbols = new string[] { "A", "B", "C", "0", "1", };
1098+
1099+ BooleanVariable Var;
1100+
1101+ public VarExpression(BooleanVariable var, bool not = false)
1102+ {
1103+ Var = var;
1104+ }
1105+
1106+ public override BooleanExpression Clone()
1107+ {
1108+ return new VarExpression(Var);
1109+ }
1110+
1111+ public override int CountOps()
1112+ {
1113+ return 0;
1114+ }
1115+
1116+ public override IEnumerable<string> GetSetOfAllBlockStrings()
1117+ {
1118+ yield break;
1119+ }
1120+
1121+ public override byte Eval()
1122+ {
1123+ switch(Var) {
1124+ case BooleanVariable.A:
1125+ return 0x0F;
1126+ case BooleanVariable.B:
1127+ return 0x33;
1128+ case BooleanVariable.C:
1129+ return 0x55;
1130+ case BooleanVariable.Zero:
1131+ return 0x00;
1132+ case BooleanVariable.One:
1133+ return 0xFF;
1134+ default:
1135+ throw new Exception("Nigga wat?");
1136+ }
1137+ }
1138+
1139+ public override string ToString()
1140+ {
1141+ return VarSymbols[(int)Var];
1142+ }
1143+ }
1144+}
1145+