using System; using System.Collections.Generic; using System.Linq; /// <summary> /// /// </summary> public abstract class LogicFunction { // public const byte cStarSymb = 2; // public readonly ICollection<byte[]> Terms = new LinkedList<byte[]>(); // public abstract bool Calculate(bool[] X); // public virtual bool Calculate(char[] X) { return Calculate(X.Select(p => p != '0').ToArray()); } // public virtual bool Calculate(byte[] X) { return Calculate(X.Select(p => p != 0).ToArray()); } } /// <summary> /// /// </summary> public class Dnf : LogicFunction { public static bool Calculate(byte[] X, byte[] term) { bool bResult = true; for (int i = 0; i < term.Length; i++) { if ((term[i] == cStarSymb) || (term[i] == X[i])) continue; bResult = false; break; } return bResult; } public override bool Calculate(bool[] X) { bool bResult = false; foreach (byte[] term in Terms) { bool TermVal = true; for (int i = 0; i < term.Length; i++) { if (term[i] == cStarSymb) continue; TermVal &= (term[i] != 0 ? X[i] : !X[i]); } bResult |= TermVal; } return bResult; } } /// <summary> /// /// </summary> public class Knf : LogicFunction { public override bool Calculate(bool[] X) { bool bResult = true; foreach (byte[] term in Terms) { bool TermVal = false; for (int i = 0; i < term.Length; i++) { if (term[i] == cStarSymb) continue; TermVal |= (term[i] != 0 ? X[i] : !X[i]); } bResult &= TermVal; } return bResult; } } /// <summary> /// /// </summary> public class TreeFuncTerm { // private readonly TreeNodeMiddle rootNode = new TreeNodeMiddle(); // () private int _rang = 0; public int Rang { get { return _rang; } } // private int enumerationPos = 0; private TreeNodeMiddle[] enumerationBuf; //, private byte[] enumerationTerm; public byte[] EnumerationTerm { get { return enumerationTerm; } } // private UInt32 _count = 0; public UInt32 Count { get { return _count; } } // public TreeFuncTerm() { Clear(); } // public void Clear() { _count = 0; _rang = 0; enumerationPos = 0; enumerationBuf = null; enumerationTerm = null; rootNode.Clear(); } // public TreeNodeEnd EnumerationInit() { enumerationPos = 0; enumerationTerm = new byte[_rang]; enumerationTerm[0] = 0; enumerationBuf = new TreeNodeMiddle[_rang]; enumerationBuf[0] = rootNode; // return EnumerationNextNode(); } // public TreeNodeEnd EnumerationNextNode() { int iIsNext = (enumerationPos > 0 ? 1 : 0); TreeNodeEnd pRetTreeNode = null; while ((pRetTreeNode == null) && (enumerationPos >= 0)) { TreeNodeBase[] pCurrNodes = enumerationBuf[enumerationPos].Childs; TreeNodeBase pNextNode = null; int i = enumerationTerm[enumerationPos] + iIsNext; for (; i < 3; i++) if ((pNextNode = pCurrNodes[i]) != null) break; if (pNextNode == null) { // enumerationPos--; iIsNext = 1; } else { enumerationTerm[enumerationPos] = (byte)i; if (pNextNode is TreeNodeMiddle) { // enumerationPos++; enumerationBuf[enumerationPos] = (TreeNodeMiddle)pNextNode; enumerationTerm[enumerationPos] = 0; iIsNext = 0; } else //if (pNextNode is TreeNodeEnd) { // pRetTreeNode = (TreeNodeEnd)pNextNode; } } } return pRetTreeNode; } // public TreeNodeEnd AddTerm(byte[] term) { _rang = Math.Max(_rang, term.Length); TreeNodeBase pCurrNode = rootNode; for (int j = 0; j < term.Length; j++) { TreeNodeBase item = ((TreeNodeMiddle)pCurrNode).Childs[term[j]]; if (item == null) { if (j + 1 < term.Length) { item = new TreeNodeMiddle(); } else { item = new TreeNodeEnd(); _count++; } ((TreeNodeMiddle)pCurrNode).Childs[term[j]] = item; } pCurrNode = item; } return (TreeNodeEnd)pCurrNode; } // public TreeNodeEnd Remove(byte[] term) { TreeNodeEnd pRemovedNode = null; TreeNodeMiddle pCurrNode = rootNode; foreach (byte cSymb in term) { TreeNodeBase pNextNode = pCurrNode.Childs[cSymb]; if (pNextNode == null) break; if (pNextNode is TreeNodeMiddle) { pCurrNode = (TreeNodeMiddle)pNextNode; } else { // pRemovedNode = (TreeNodeEnd)pNextNode; // pCurrNode.Childs[cSymb] = null; // - _count--; // - break; } } return pRemovedNode; } // public TreeNodeEnd IsContains(byte[] term) { TreeNodeBase pCurrNode = rootNode; foreach (byte cSymb in term) { pCurrNode = ((TreeNodeMiddle)pCurrNode).Childs[cSymb]; if (pCurrNode == null) break; } return ((pCurrNode != null) && (pCurrNode is TreeNodeEnd) ? (TreeNodeEnd)pCurrNode : null); } // public int SearchDiff1(byte[] term, TreeNodeBase[] pOneDiffNodesList) { int iOneDiffNodesListCount = 0; TreeNodeBase pCurrNode = rootNode; for (int iPos = 0; iPos < term.Length; iPos++) { pOneDiffNodesList[iPos] = null; byte cSymbol = term[iPos]; if (pCurrNode != null) { if (cSymbol != LogicFunction.cStarSymb) { TreeNodeBase item = ((TreeNodeMiddle)pCurrNode).Childs[1 - cSymbol]; if (item != null) { // pOneDiffNodesList[iPos] = item; iOneDiffNodesListCount++; } } pCurrNode = ((TreeNodeMiddle)pCurrNode).Childs[cSymbol]; } else if (iOneDiffNodesListCount == 0) { // for (int i = iPos + 1; i < term.Length; i++) pOneDiffNodesList[i] = null; break; } // , , // for (int iKey = 0; iKey < iPos; iKey++) { TreeNodeBase item = pOneDiffNodesList[iKey]; if (item == null) continue; item = ((TreeNodeMiddle)item).Childs[cSymbol]; if (item == null) { // pOneDiffNodesList[iKey] = null; iOneDiffNodesListCount--; } else { pOneDiffNodesList[iKey] = item; } } } return iOneDiffNodesListCount; } } /// <summary> /// /// </summary> public interface TreeNodeBase { // void Clear(); } /// <summary> /// /// </summary> public class TreeNodeEnd : TreeNodeBase { // public void Clear() { } } /// <summary> /// /// </summary> public class TreeNodeMiddle : TreeNodeBase { // public readonly TreeNodeBase[] Childs = new TreeNodeBase[3]; // public void Clear() { for (int i = 0; i < 3; i++) { if ((Childs[i] != null) && (Childs[i] is TreeNodeMiddle)) ((TreeNodeMiddle)Childs[i]).Clear(); Childs[i] = null; } } } /// <summary> /// ---- /// </summary> public class Quine_McCluskey { private readonly Dnf _result = new Dnf(); public Dnf Result { get { return _result; } } // private static void Skleivanie(TreeFuncTerm X1Tree, TreeFuncTerm X2Tree, LinkedList<byte[]> NegTerms, Dictionary<int, LinkedList<byte[]>> OutResult, TreeFuncTerm NegativTree, int iLevel) { LinkedList<byte[]> OutR = new LinkedList<byte[]>(); if (OutResult != null) OutResult.Add(iLevel, OutR); bool IsVirtSkleivOn = ((NegativTree != null) && (NegativTree.Count != 0)); TreeNodeEnd x1 = X1Tree.EnumerationInit(); TreeNodeBase[] FindTerms = new TreeNodeBase[x1 != null ? X1Tree.Rang : 1]; TreeNodeBase[] FindNegTerms = new TreeNodeBase[x1 != null ? X1Tree.Rang : 1]; TreeNodeBase[] FindVirtTerms = new TreeNodeBase[x1 != null ? X1Tree.Rang : 1]; while (x1 != null) { bool bIsSkleiv = false; byte[] pCurrTerm = X1Tree.EnumerationTerm; X1Tree.SearchDiff1(pCurrTerm, FindTerms); if (IsVirtSkleivOn) NegativTree.SearchDiff1(pCurrTerm, FindNegTerms); for (int iPos = 0; iPos < pCurrTerm.Length; iPos++) { byte cSymbSav = pCurrTerm[iPos]; if (cSymbSav == LogicFunction.cStarSymb) continue; // // , NegativTree if (FindTerms[iPos] != null) { bIsSkleiv = true; if (cSymbSav == 0) { pCurrTerm[iPos] = LogicFunction.cStarSymb; // X2Tree.AddTerm(pCurrTerm); pCurrTerm[iPos] = cSymbSav; } } else if (IsVirtSkleivOn && (FindNegTerms[iPos] == null)) { pCurrTerm[iPos] = LogicFunction.cStarSymb; // bool bIsNotCanAdd = false; foreach (byte[] NegTerm in NegTerms) { if (bIsNotCanAdd = Dnf.Calculate(NegTerm, pCurrTerm)) break; } if (!bIsNotCanAdd) { bIsSkleiv = true; X2Tree.AddTerm(pCurrTerm); } pCurrTerm[iPos] = cSymbSav; } } // , if (!bIsSkleiv) OutR.AddLast(pCurrTerm.ToArray()); // x1 = X1Tree.EnumerationNextNode(); } } // private static UInt64 GetTermCode(byte[] pTerm) { UInt64 iMultip = 1, iCode = 0; for (int i = 0; i < pTerm.Length; i++) { iCode += (iMultip * pTerm[i]); iMultip *= 3; } return iCode; } // private static byte[] GetTermByCode(UInt64 iCode, int iTermLength) { byte[] pTerm = new byte[iTermLength]; int iCounter = 0; while (iCode != 0) { pTerm[iCounter++] = (byte)(iCode % 3); iCode /= 3; } return pTerm; } // private static void Skleivanie(SortedSet<UInt64> X1Tree, SortedSet<UInt64> X2Tree, LinkedList<byte[]> NegTerms, Dictionary<int, LinkedList<byte[]>> OutResult, SortedSet<UInt64> NegativTree, int iLevel, int iTermLength) { LinkedList<byte[]> OutR = new LinkedList<byte[]>(); if (OutResult != null) OutResult.Add(iLevel, OutR); bool IsVirtSkleivOn = ((NegativTree != null) && (NegativTree.Count != 0)); foreach (UInt64 x1 in X1Tree) { byte[] pCurrTerm = (IsVirtSkleivOn ? GetTermByCode(x1, iTermLength) : null); bool bIsSkleiv = false; UInt64 iMultip = 1; for (int iPos = 0; iPos < iTermLength; iPos++) { byte cSymbSav = (pCurrTerm != null ? pCurrTerm[iPos] : (byte)((x1 / iMultip) % 3)); if (cSymbSav != LogicFunction.cStarSymb) { UInt64 iCode = (cSymbSav == 0 ? x1 + iMultip : x1 - iMultip); // // , NegativTree if (X1Tree.Contains(iCode)) { bIsSkleiv = true; if (cSymbSav == 0) { X2Tree.Add(x1 + (byte)(LogicFunction.cStarSymb - cSymbSav) * iMultip); } } else if (IsVirtSkleivOn && !NegativTree.Contains(iCode)) { bool bIsNotCanAdd = false; pCurrTerm[iPos] = LogicFunction.cStarSymb; // foreach (byte[] NegTerm in NegTerms) { if (bIsNotCanAdd = Dnf.Calculate(NegTerm, pCurrTerm)) break; } pCurrTerm[iPos] = cSymbSav; if (!bIsNotCanAdd) { bIsSkleiv = true; X2Tree.Add(x1 + (byte)(LogicFunction.cStarSymb - cSymbSav) * iMultip); } } } iMultip *= 3; } // , if (!bIsSkleiv) OutR.AddLast(pCurrTerm != null ? pCurrTerm : GetTermByCode(x1, iTermLength)); } } // // private static void DeleteDublicatingTerms(IEnumerable<byte[]> InX1, SortedSet<UInt64> OutX2Tree) { OutX2Tree.Clear(); foreach (byte[] x1 in InX1) { UInt64 iCode = GetTermCode(x1); if (OutX2Tree.Contains(iCode)) continue; OutX2Tree.Add(iCode); } } // // private static void DeleteDublicatingTerms(IEnumerable<byte[]> InX1, TreeFuncTerm OutX2Tree) { OutX2Tree.Clear(); foreach (byte[] x1 in InX1) OutX2Tree.AddTerm(x1); } // private static bool IsEqualTerms(byte[] pTermC, byte[] pTermB) { if ((pTermC == null) || (pTermB == null) || (pTermC.Length != pTermB.Length)) return false; bool bIsEqual = false; int iLength = Math.Min(pTermC.Length, pTermB.Length); for ( int i = 0; i < iLength; i++) { if (!(bIsEqual = (pTermB[i] == pTermC[i]))) break; } return bIsEqual; } // . private static void ReduceRedundancyTerms(LinkedList<byte[]> InpTerms, LinkedList<byte[]> NegTerms, Dictionary<int, LinkedList<byte[]>> OutputTerms, ICollection<byte[]> ResultTerms) { // ResultTerms.Clear(); // , HashSet<byte[]> pNumbersForAdd = new HashSet<byte[]>(); // , Dictionary<byte[], HashSet<byte[]>> Numbers2Terms = new Dictionary<byte[], HashSet<byte[]>>(); // , Dictionary<byte[], HashSet<byte[]>> Terms2Numbers = new Dictionary<byte[], HashSet<byte[]>>(); // foreach (int iLevel in OutputTerms.Keys.OrderByDescending(p => p).AsEnumerable()) { // foreach (byte[] term in OutputTerms[iLevel]) { // , term HashSet<byte[]> InTermsCont = new HashSet<byte[]>(); // foreach (byte[] InpTerm in InpTerms) { if (Dnf.Calculate(InpTerm, term)) InTermsCont.Add(InpTerm); } // ( ) if (NegTerms != null) { foreach (byte[] NegTerm in NegTerms) { if (!Dnf.Calculate(NegTerm, term)) InTermsCont.Add(NegTerm); } } Terms2Numbers.Add(term, InTermsCont); } // , int iTerms2NumbersCountPrev = 0; foreach (byte[] term in OutputTerms[iLevel].OrderByDescending(p => Terms2Numbers[p].Count)) { // , term HashSet<byte[]> InTermsCont = Terms2Numbers[term]; int iIntersectNumbers = pNumbersForAdd.Intersect(InTermsCont).Count(); if ((iIntersectNumbers < InTermsCont.Count) || (iTerms2NumbersCountPrev == InTermsCont.Count)) { pNumbersForAdd.UnionWith(InTermsCont); iTerms2NumbersCountPrev = InTermsCont.Count; foreach (byte[] pSrcNode in InTermsCont) { if (!Numbers2Terms.ContainsKey(pSrcNode)) Numbers2Terms.Add(pSrcNode, new HashSet<byte[]>()); Numbers2Terms[pSrcNode].Add(term); } } } } // , - while (pNumbersForAdd.Count > 0) { byte[] term = Numbers2Terms[pNumbersForAdd.OrderBy(p => Numbers2Terms[p].Count).First()].OrderByDescending(q => pNumbersForAdd.Intersect(Terms2Numbers[q]).Count()).First(); ResultTerms.Add(term); pNumbersForAdd.ExceptWith(Terms2Numbers[term]); } } // public static void LogicFuncMinimize(IEnumerable<byte[]> PositivTerms, IEnumerable<byte[]> NegativTerms, ICollection<byte[]> OutR) { int iTotalLevels = (PositivTerms.Count() > 0 ? PositivTerms.First().Length : (NegativTerms != null && NegativTerms.Count() > 0 ? NegativTerms.First().Length : 0)); Dictionary<int, LinkedList<byte[]>> SkleivTerms = new Dictionary<int, LinkedList<byte[]>>(iTotalLevels); LinkedList<byte[]> InpTerms = new LinkedList<byte[]>(); LinkedList<byte[]> NegTerms = new LinkedList<byte[]>(); if (iTotalLevels < 40) { SortedSet<UInt64> X1PositivTree = new SortedSet<UInt64>(); DeleteDublicatingTerms(PositivTerms, X1PositivTree); SortedSet<UInt64> X1NegativTree = null; if (NegativTerms != null) { X1NegativTree = new SortedSet<UInt64>(); DeleteDublicatingTerms(NegativTerms, X1NegativTree); // UInt64[] pNumbList = X1PositivTree.Intersect(X1NegativTree).ToArray(); foreach(UInt64 iNumb in pNumbList) { // - X1 NegativTerms int iPos_Count = PositivTerms.Count(p => GetTermCode(p) == iNumb); int iNeg_Count = NegativTerms.Count(p => GetTermCode(p) == iNumb); if (iPos_Count > iNeg_Count) { X1NegativTree.Remove(iNumb); } else if (iPos_Count < iNeg_Count) { X1PositivTree.Remove(iNumb); } else //if (iPos_Count == iNeg_Count) { X1PositivTree.Remove(iNumb); X1NegativTree.Remove(iNumb); } } // foreach (UInt64 code in X1NegativTree) { NegTerms.AddLast(GetTermByCode(code, iTotalLevels)); } } // foreach (UInt64 code in X1PositivTree) { InpTerms.AddLast(GetTermByCode(code, iTotalLevels)); } int iLevelCounter = 0; // while ((X1PositivTree.Count != 0) && (iLevelCounter < iTotalLevels)) { SortedSet<UInt64> X2Tree = new SortedSet<UInt64>(); Skleivanie(X1PositivTree, X2Tree, NegTerms, SkleivTerms, X1NegativTree, iLevelCounter, iTotalLevels); if ((X1NegativTree != null) && (X1NegativTree.Count != 0)) { SortedSet<UInt64> X2NegativTree = new SortedSet<UInt64>(); Skleivanie(X1NegativTree, X2NegativTree, InpTerms, null, X1PositivTree, iLevelCounter, iTotalLevels); // X1NegativTree.Clear(); X1NegativTree = X2NegativTree; } // X1PositivTree.Clear(); X1PositivTree = X2Tree; iLevelCounter++; GC.Collect(); } } else { TreeFuncTerm X1PositivTree = new TreeFuncTerm(); DeleteDublicatingTerms(PositivTerms, X1PositivTree); TreeFuncTerm X1NegativTree = null; if (NegativTerms != null) { X1NegativTree = new TreeFuncTerm(); DeleteDublicatingTerms(NegativTerms, X1NegativTree); // TreeNodeEnd x1 = X1PositivTree.EnumerationInit(); while (x1 != null) { if (X1NegativTree.IsContains(X1PositivTree.EnumerationTerm) != null) { // - PositivTerms NegativTerms int iPos_Count = PositivTerms.Count(p => IsEqualTerms(p, X1PositivTree.EnumerationTerm)); int iNeg_Count = NegativTerms.Count(p => IsEqualTerms(p, X1PositivTree.EnumerationTerm)); if (iPos_Count > iNeg_Count) { X1NegativTree.Remove(X1PositivTree.EnumerationTerm); } else if (iPos_Count < iNeg_Count) { X1PositivTree.Remove(X1PositivTree.EnumerationTerm); } else //if (iPos_Count == iNeg_Count) { X1PositivTree.Remove(X1PositivTree.EnumerationTerm); X1NegativTree.Remove(X1PositivTree.EnumerationTerm); } } x1 = X1PositivTree.EnumerationNextNode(); } // x1 = X1NegativTree.EnumerationInit(); while (x1 != null) { NegTerms.AddLast(X1NegativTree.EnumerationTerm.ToArray()); x1 = X1NegativTree.EnumerationNextNode(); } } // TreeNodeEnd X1Term = X1PositivTree.EnumerationInit(); while (X1Term != null) { InpTerms.AddLast(X1PositivTree.EnumerationTerm.ToArray()); X1Term = X1PositivTree.EnumerationNextNode(); } int iLevelCounter = 0; // while ((X1PositivTree.Count != 0) && (iLevelCounter < iTotalLevels)) { TreeFuncTerm X2Tree = new TreeFuncTerm(); Skleivanie(X1PositivTree, X2Tree, NegTerms, SkleivTerms, X1NegativTree, iLevelCounter); if ((X1NegativTree != null) && (X1NegativTree.Count != 0)) { TreeFuncTerm X2NegativTree = new TreeFuncTerm(); Skleivanie(X1NegativTree, X2NegativTree, InpTerms, null, X1PositivTree, iLevelCounter); // X1NegativTree.Clear(); X1NegativTree = X2NegativTree; } // X1PositivTree.Clear(); X1PositivTree = X2Tree; iLevelCounter++; GC.Collect(); } } // ReduceRedundancyTerms(InpTerms, NegTerms, SkleivTerms, OutR); } // public void Start(IEnumerable<byte[]> TermsInput) { LogicFuncMinimize(TermsInput, null, _result.Terms); } // public void Start(IEnumerable<byte[]> TermsInput, IEnumerable<byte[]> NegativTerms) { LogicFuncMinimize(TermsInput, NegativTerms, _result.Terms); } // public void Start(IEnumerable<char[]> TermsInput) { Start(TermsInput.Select(t => t.Select(p => (byte)(p == '0' ? 0 : 1)).ToArray())); } // public void Start(IEnumerable<char[]> TermsInput, IEnumerable<char[]> NegativTerms) { Start(TermsInput.Select(t => t.Select(p => (byte)(p == '0' ? 0 : 1)).ToArray()), NegativTerms.Select(t => t.Select(p => (byte)(p == '0' ? 0 : 1)).ToArray())); } public void PrintResult() { Console.WriteLine("--------Otvet-------"); char[] pTermSymbs = new char[] { '0', '1', '*' }; foreach (byte[] Term in _result.Terms) { for (int j = 0; j < Term.Length; j++) { Console.Write(pTermSymbs[Term[j]].ToString() + " "); } Console.WriteLine(); } } }
public static void TestQuineMcCluskeyRandomPart(int iVariableAmount, double dPart=1) { if (dPart < 0) throw new ArgumentException(" dPart 0 1"); if (dPart > 1) dPart = 1; // ulong iTotalCombines = (ulong)1 << iVariableAmount; LinkedList<byte[]> pTrueCol = new LinkedList<byte[]>(); LinkedList<byte[]> pFalseCol = new LinkedList<byte[]>(); HashSet<ulong> pUsedTerms = new HashSet<ulong>(); Random rnd = new Random(); byte[] buf = new byte[8]; while (pUsedTerms.LongCount() < (iTotalCombines * dPart)) { rnd.NextBytes(buf); ulong iCurValue = (ulong)BitConverter.ToInt64(buf, 0) % iTotalCombines; if (pUsedTerms.Contains(iCurValue)) { // - do { iCurValue = ++iCurValue % iTotalCombines; } while (pUsedTerms.Contains(iCurValue)); } pUsedTerms.Add(iCurValue); byte[] sLine = new byte[iVariableAmount]; for (int i = 0; i < iVariableAmount; i++) { sLine[i] += (byte)(iCurValue % 2); iCurValue >>= 1; } if (rnd.Next(2) != 0) { pTrueCol.AddLast(sLine); } else { pFalseCol.AddLast(sLine); } } // DateTime DtStart = DateTime.Now; Console.WriteLine(" - " + DtStart.ToLongTimeString()); Quine_McCluskey Logic = new Quine_McCluskey(); Logic.Start(pTrueCol, pFalseCol); DateTime DtEnd = DateTime.Now; Logic.PrintResult(); Console.WriteLine(" - " + DtStart.ToLongTimeString()); Console.WriteLine(" - " + DtEnd.ToLongTimeString()); TimeSpan Elapsed = DtEnd - DtStart; Console.WriteLine(" - " + String.Format("{0:00}:{1:00}:{2:00}", Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds)); // int iErrorsCounter = 0; foreach (byte[] kvp in pTrueCol) { if (Logic.Result.Calculate(kvp) != true) iErrorsCounter++; } foreach (byte[] kvp in pFalseCol) { if (Logic.Result.Calculate(kvp) != false) iErrorsCounter++; } Console.WriteLine("- = " + pUsedTerms.Count); Console.WriteLine("- = " + Logic.Result.Terms.Count); Console.WriteLine("- = " + iErrorsCounter); Console.ReadLine(); }
Source: https://habr.com/ru/post/424517/
All Articles