using System; using System.IO; using System.Collections.Generic; using System.Linq; /// <summary> /// /// </summary> public abstract class LogicFunction { // public readonly ICollection<char[]> Terms = new LinkedList<char[]>(); // public abstract bool Calculate(bool[] X); // public virtual bool Calculate(char[] X) { return Calculate(X.Select(p => p != '0').ToArray()); } } /// <summary> /// /// </summary> public class Dnf : LogicFunction { public override bool Calculate(bool[] X) { bool bResult = false; foreach (char[] term in Terms) { bool TermVal = true; for (int i = 0; i < term.Length; i++) { if (term[i] == '*') 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 (char[] term in Terms) { bool TermVal = false; for (int i = 0; i < term.Length; i++) { if (term[i] == '*') continue; TermVal |= (term[i] != '0' ? X[i] : !X[i]); } bResult &= TermVal; } return bResult; } } /// <summary> /// ---- /// </summary> public class Quine_McCluskey { private readonly Dnf _result = new Dnf(); public Dnf Result { get { return _result; } } // public void Start(IEnumerable<char[]> TermInput) { LogicFuncMinimize(TermInput, _result.Terms); } // public void Start(string sFileName) { Start(LoadDsnfFromFile(sFileName)); } // private static void LogicFuncMinimize(IEnumerable<char[]> X1, ICollection<char[]> OutR) { Dictionary<int, LinkedList<TreeNodeEnd>> OutTemp = new Dictionary<int, LinkedList<TreeNodeEnd>>(); if (X1.First().Length <= 40) { Dictionary<UInt64, TreeNodeEnd> X1Tree = new Dictionary<UInt64, TreeNodeEnd>(); DeleteDublicatingTerms(X1, X1Tree); int iLevelCounter = 0; // while (X1Tree.Count != 0) { Dictionary<UInt64, TreeNodeEnd> X2Tree = new Dictionary<UInt64, TreeNodeEnd>(); Skleivanie(X1Tree, X2Tree, OutTemp, iLevelCounter++); X1Tree = X2Tree; GC.Collect(); // !!! } } else { TreeFuncTerm X1Tree = new TreeFuncTerm(); DeleteDublicatingTerms(X1, X1Tree); int iLevelCounter = 0; // while (X1Tree.Count != 0) { TreeFuncTerm X2Tree = new TreeFuncTerm(); Skleivanie(X1Tree, X2Tree, OutTemp, iLevelCounter++); X1Tree = X2Tree; GC.Collect(); // !!! } } HashSet<TreeNodeEnd> OutRes = new HashSet<TreeNodeEnd>(); ReduceRedundancyTerms(OutTemp, OutRes); OutR.Clear(); foreach (TreeNodeEnd term in OutRes) OutR.Add(term.Term); } // private static ICollection<char[]> LoadDsnfFromFile(string sFullFileName) { ICollection<char[]> DSNF = new LinkedList<char[]>(); // using (StreamReader InFile = new StreamReader(sFullFileName)) { string sLine = ""; while ((sLine = InFile.ReadLine()) != null) { DSNF.Add(sLine.ToArray()); } } return DSNF; } // // private static void DeleteDublicatingTerms(IEnumerable<char[]> InX1, Dictionary<UInt64, TreeNodeEnd> OutX2Tree) { OutX2Tree.Clear(); TreeNodeEnd pCurrNode = null; foreach (char[] x1 in InX1) { UInt64 iCode = GetTermCode(x1); if (OutX2Tree.ContainsKey(iCode)) continue; pCurrNode = new TreeNodeEnd(x1, null, null, pCurrNode, OutX2Tree.Count); OutX2Tree.Add(iCode, pCurrNode); } } // // private static void DeleteDublicatingTerms(IEnumerable<char[]> InX1, TreeFuncTerm OutX2Tree) { OutX2Tree.Clear(); foreach (char[] x1 in InX1) { OutX2Tree.AddTerm(x1, null, null); } } // private static void Skleivanie(TreeFuncTerm X1Tree, TreeFuncTerm X2Tree, Dictionary<int, LinkedList<TreeNodeEnd>> OutResult, int iLevel) { LinkedList<TreeNodeEnd> OutR = new LinkedList<TreeNodeEnd>(); OutResult.Add(iLevel, OutR); Dictionary<int, TreeNodeEnd> FindTerms = new Dictionary<int, TreeNodeEnd>(); TreeNodeEnd x1 = X1Tree.Last; while (x1 != null) { X1Tree.SearchDiff1(x1, FindTerms); if (FindTerms.Count == 0) { // , OutR.AddLast(x1); } else { foreach (KeyValuePair<int, TreeNodeEnd> kvp in FindTerms) { //, if (x1.Number < kvp.Value.Number) continue; // char cSymbSav = x1.Term[kvp.Key]; x1.Term[kvp.Key] = '*'; // X2Tree.AddTerm(x1.Term, x1, kvp.Value); x1.Term[kvp.Key] = cSymbSav; } } x1 = x1.Prev; } } // private static UInt64 GetTermCode(char[] pTerm) { UInt64 iMultip = 1, iCode = 0; for (int i = 0; i < pTerm.Length; i++) { switch (pTerm[i]) { case '0': break; case '1': iCode += iMultip; break; case '*': iCode += (iMultip + iMultip); break; } iMultip *= 3; } return iCode; } // private static void Skleivanie(Dictionary<UInt64, TreeNodeEnd> X1Tree, Dictionary<UInt64, TreeNodeEnd> X2Tree, Dictionary<int, LinkedList<TreeNodeEnd>> OutResult, int iLevel) { LinkedList<TreeNodeEnd> OutR = new LinkedList<TreeNodeEnd>(); OutResult.Add(iLevel, OutR); foreach (KeyValuePair<UInt64, TreeNodeEnd> x1 in X1Tree) { bool bIsSkleiv = false; UInt64 iMultip = 1; for (int iPos = 0; iPos < x1.Value.Term.Length; iPos++) { char cSymbSav = x1.Value.Term[iPos]; if (cSymbSav != '*') { UInt64 iCode; if (cSymbSav == '0') iCode = x1.Key + iMultip; else //_if (cSymbSav == '1') iCode = x1.Key - iMultip; TreeNodeEnd pSkleivNode = null; X1Tree.TryGetValue(iCode, out pSkleivNode); if (pSkleivNode != null) { bIsSkleiv = true; //, if (x1.Value.Number > pSkleivNode.Number) { // if (cSymbSav == '0') iCode = x1.Key + iMultip + iMultip; else //_if (cSymbSav == '1') iCode = x1.Key + iMultip; x1.Value.Term[iPos] = '*'; // if (!X2Tree.ContainsKey(iCode)) X2Tree.Add(iCode, new TreeNodeEnd(x1.Value.Term, x1.Value, pSkleivNode, null, X2Tree.Count)); x1.Value.Term[iPos] = cSymbSav; } } } iMultip *= 3; } if (!bIsSkleiv) { // , OutR.AddLast(x1.Value); } } } // . private static void ReduceRedundancyTerms(Dictionary<int, LinkedList<TreeNodeEnd>> X, HashSet<TreeNodeEnd> ResultNumbers) { // ResultNumbers.Clear(); // - HashSet<TreeNodeEnd> pNumbersForAdd = new HashSet<TreeNodeEnd>(); Dictionary<TreeNodeEnd, uint> Numbers2Terms = new Dictionary<TreeNodeEnd, uint>(); Dictionary<TreeNodeEnd, HashSet<TreeNodeEnd>> Terms2Numbers = new Dictionary<TreeNodeEnd, HashSet<TreeNodeEnd>>(); // foreach (int iLevel in X.Keys.OrderByDescending(p => p).AsQueryable()) { foreach (TreeNodeEnd term in X[iLevel]) { HashSet<TreeNodeEnd> TermNumberCont = new HashSet<TreeNodeEnd>(); HashSet<TreeNodeEnd> ListNumbers = new HashSet<TreeNodeEnd>(); ListNumbers.Add(term); while (ListNumbers.Count > 0) { TreeNodeEnd pCurrNode = ListNumbers.First(); ListNumbers.Remove(pCurrNode); if (pCurrNode.Parent1 != null && pCurrNode.Parent2 != null) { ListNumbers.Add(pCurrNode.Parent1); ListNumbers.Add(pCurrNode.Parent2); } else { if (!Numbers2Terms.ContainsKey(pCurrNode)) Numbers2Terms.Add(pCurrNode, 0); Numbers2Terms[pCurrNode]++; // TermNumberCont.Add(pCurrNode); } } //int iIntersectNumbers = pNumbersForAdd.Intersect(TermNumberCont).Count(); //if (iIntersectNumbers < TermNumberCont.Count) { pNumbersForAdd.UnionWith(TermNumberCont); Terms2Numbers.Add(term, TermNumberCont); } } } // - pNumbersForAdd = new HashSet<TreeNodeEnd>(pNumbersForAdd.OrderBy(p => Numbers2Terms[p])); // Dictionary<TreeNodeEnd, HashSet<TreeNodeEnd>> SelectedTerms = new Dictionary<TreeNodeEnd, HashSet<TreeNodeEnd>>(); // while (pNumbersForAdd.Count > 0) { // TreeNodeEnd pSrcTerm = pNumbersForAdd.First(); // , TreeNodeEnd BestTerm = null; int iBestTermNumbersCount = 0; foreach (KeyValuePair<TreeNodeEnd, HashSet<TreeNodeEnd>> CurrTerm in Terms2Numbers) { if (!CurrTerm.Value.Contains(pSrcTerm)) continue; int iCurrTermNumbersCount = CurrTerm.Value.Intersect(pNumbersForAdd).Count(); if ((BestTerm == null) || (iBestTermNumbersCount < iCurrTermNumbersCount)) { BestTerm = CurrTerm.Key; iBestTermNumbersCount = iCurrTermNumbersCount; } } ResultNumbers.Add(BestTerm); HashSet<TreeNodeEnd> pBestTermSrcNodes = Terms2Numbers[BestTerm]; Terms2Numbers.Remove(BestTerm); SelectedTerms.Add(BestTerm, pBestTermSrcNodes); pNumbersForAdd.RemoveWhere(p => pBestTermSrcNodes.Contains(p)); } // Terms2Numbers = SelectedTerms; // TreeNodeEnd termForDelete = null; do { termForDelete = null; int iTermForDeleteUsedNumbCount = 0; foreach (KeyValuePair<TreeNodeEnd, HashSet<TreeNodeEnd>> term1 in SelectedTerms) { int iUsedNumbCounter = 0; foreach (TreeNodeEnd numb in term1.Value) { bool bFind = false; foreach (KeyValuePair<TreeNodeEnd, HashSet<TreeNodeEnd>> term2 in SelectedTerms) { if (term1.Key == term2.Key) continue; if (bFind = term2.Value.Contains(numb)) break; } if (bFind) iUsedNumbCounter++; } if ((iUsedNumbCounter == term1.Value.Count) && ((termForDelete == null) || (iUsedNumbCounter <= iTermForDeleteUsedNumbCount))) { termForDelete = term1.Key; iTermForDeleteUsedNumbCount = iUsedNumbCounter; } } if (termForDelete != null) { ResultNumbers.Remove(termForDelete); SelectedTerms.Remove(termForDelete); } } while (termForDelete != null); } } /// <summary> /// /// </summary> public class TreeFuncTerm { // private readonly TreeNodeMiddle rootNode = new TreeNodeMiddle(); // private TreeNodeEnd _lastTreeNode = null; public TreeNodeEnd Last { get { return _lastTreeNode; } } // private int _count = 0; public int Count { get { return _count; } } // public TreeFuncTerm() { Clear(); } // public void Clear() { rootNode.Clear(); _count = 0; _lastTreeNode = null; } // public void AddTerm(char[] term, TreeNodeEnd pParent1, TreeNodeEnd pParent2) { TreeNodeMiddle pCurrNode = rootNode; for (int j = 0; j < term.Length; j++) { TreeNodeBase item = pCurrNode.GetChild(term[j]); if (item == null) { if (j + 1 < term.Length) { item = new TreeNodeMiddle(); } else { item = new TreeNodeEnd(term, pParent1, pParent2, _lastTreeNode, _count); _lastTreeNode = (TreeNodeEnd)item; _count++; } pCurrNode.AddChild(item, term[j]); } if (item is TreeNodeMiddle) pCurrNode = (TreeNodeMiddle)item; } } // public void SearchDiff1(TreeNodeEnd x1, Dictionary<int, TreeNodeEnd> result) { result.Clear(); TreeNodeMiddle pCurrNode = rootNode; Dictionary<int, TreeNodeMiddle> OneDiffNodesList = new Dictionary<int, TreeNodeMiddle>(); for (int iPos = 0; iPos < x1.Term.Length; iPos++) { char cSymbol = x1.Term[iPos]; if (pCurrNode != null) { if (cSymbol != '*') { TreeNodeBase item = pCurrNode.GetChild(cSymbol == '0' ? '1' : '0'); if (item != null) { if (item is TreeNodeMiddle) { OneDiffNodesList.Add(iPos, (TreeNodeMiddle)item); } else //if (item is TreeNodeEnd) { // result.Add(iPos, (TreeNodeEnd)item); } } } TreeNodeBase pNextNode = pCurrNode.GetChild(cSymbol); if ((pNextNode != null) && (pNextNode is TreeNodeMiddle)) { pCurrNode = (TreeNodeMiddle)pNextNode; } } // , , // for (int iKey = 0; iKey < iPos; iKey++) { if (!OneDiffNodesList.ContainsKey(iKey)) continue; TreeNodeMiddle pValue = OneDiffNodesList[iKey]; TreeNodeBase item = pValue.GetChild(cSymbol); if (item == null) { OneDiffNodesList.Remove(iKey); } else if (item is TreeNodeMiddle) { OneDiffNodesList[iKey] = (TreeNodeMiddle)item; } else //if (item is TreeNodeEnd) { // result.Add(iKey, (TreeNodeEnd)item); } } } } } /// <summary> /// /// </summary> public interface TreeNodeBase { // void Clear(); } /// <summary> /// /// </summary> public class TreeNodeEnd : TreeNodeBase { //, private char[] _term; public char[] Term { get { return _term; } } // private TreeNodeEnd _prev; public TreeNodeEnd Prev { get { return _prev; } } // private TreeNodeEnd _parent1; public TreeNodeEnd Parent1 { get { return _parent1; } } // private TreeNodeEnd _parent2; public TreeNodeEnd Parent2 { get { return _parent2; } } // , public readonly int Number; // public TreeNodeEnd(char[] pTermRef, TreeNodeEnd pParent1, TreeNodeEnd pParent2, TreeNodeEnd pPrevTreeNode, int iNumber) { pTermRef.CopyTo(_term = new char[pTermRef.Length], 0); _parent1 = pParent1; _parent2 = pParent2; _prev = pPrevTreeNode; Number = iNumber; } // public void Clear() { _term = null; _parent1 = null; _parent2 = null; _prev = null; } } /// <summary> /// /// </summary> public class TreeNodeMiddle : TreeNodeBase { // private TreeNodeBase Childs0; private TreeNodeBase Childs1; private TreeNodeBase Childs2; // public void Clear() { if ((Childs0 != null) && (Childs0 is TreeNodeMiddle)) ((TreeNodeMiddle)Childs0).Clear(); if ((Childs1 != null) && (Childs1 is TreeNodeMiddle)) ((TreeNodeMiddle)Childs1).Clear(); if ((Childs2 != null) && (Childs2 is TreeNodeMiddle)) ((TreeNodeMiddle)Childs2).Clear(); Childs0 = Childs1 = Childs2 = null; } // public TreeNodeBase GetChild(char cSymbol) { switch (cSymbol) { case '0': return Childs0; case '1': return Childs1; case '*': return Childs2; } return null; } // public void AddChild(TreeNodeBase newChild, char cSymbol) { switch (cSymbol) { case '0': Childs0 = newChild; break; case '1': Childs1 = newChild; break; case '*': Childs2 = newChild; break; } } }
public static void TestQuineMcCluskeyRandom(string sFileName, int iVariableAmount) { int iTotalCombines = 1 << iVariableAmount; ICollection<KeyValuePair<string, bool>> FuncResult = new List<KeyValuePair<string, bool>>(iTotalCombines); File.Delete(sFileName); Random rnd = new Random(); int iLogicFuncMask = 0; while (iLogicFuncMask == 0) iLogicFuncMask = rnd.Next(iTotalCombines); for (int iCounter = 0; iCounter < iTotalCombines; iCounter++) { int iCurValue = iCounter; string sLine = ""; for (int i = 0; i < iVariableAmount; i++) { sLine += (iCurValue % 2).ToString(); iCurValue /= 2; } bool bFuncValue = (iCounter & iLogicFuncMask) > 0; if (bFuncValue) { File.AppendAllText(sFileName, sLine + Environment.NewLine); } FuncResult.Add(new KeyValuePair<string, bool>(sLine, bFuncValue)); } // DateTime DtStart = DateTime.Now; Console.WriteLine(" - " + DtStart.ToLongTimeString()); Quine_McCluskey Logic = new Quine_McCluskey(); Logic.Start(sFileName); DateTime DtEnd = DateTime.Now; TimeSpan Elapsed = DtEnd - DtStart; Console.WriteLine(" - " + DtEnd.ToLongTimeString()); Console.WriteLine(" - " + String.Format("{0:00}:{1:00}:{2:00}", Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds)); // int iErrorsCounter = 0; foreach (KeyValuePair<string, bool> kvp in FuncResult) { if (Logic.Result.Calculate(kvp.Key.ToArray()) != kvp.Value) iErrorsCounter++; } Console.WriteLine("- = " + Logic.Result.Terms.Count); Console.WriteLine("- = " + iErrorsCounter); Console.ReadLine(); }
public static void TestQuineMcCluskeyFile(string sFileName, int iVariableAmount) { int iTotalCombines = 1 << iVariableAmount; ICollection<KeyValuePair<string, bool>> FuncResult = new List<KeyValuePair<string, bool>>(iTotalCombines); string sFileContent = File.ReadAllText(sFileName); for (int iCounter = 0; iCounter < iTotalCombines; iCounter++) { int iCurValue = iCounter; string sLine = ""; for (int i = 0; i < iVariableAmount; i++) { sLine += (iCurValue % 2).ToString(); iCurValue /= 2; } bool bFuncValue = sFileContent.Contains(sLine + Environment.NewLine); FuncResult.Add(new KeyValuePair<string, bool>(sLine, bFuncValue)); } // DateTime DtStart = DateTime.Now; Console.WriteLine(" - " + DtStart.ToLongTimeString()); Quine_McCluskey Logic = new Quine_McCluskey(); Logic.Start(sFileName); DateTime DtEnd = DateTime.Now; TimeSpan Elapsed = DtEnd - DtStart; Console.WriteLine(" - " + DtEnd.ToLongTimeString()); Console.WriteLine(" - " + String.Format("{0:00}:{1:00}:{2:00}", Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds)); // int iErrorsCounter = 0; foreach (KeyValuePair<string, bool> kvp in FuncResult) { if (Logic.Result.Calculate(kvp.Key.ToArray()) != kvp.Value) iErrorsCounter++; } Console.WriteLine("- = " + Logic.Result.Terms.Count); Console.WriteLine("- = " + iErrorsCounter); Console.ReadLine(); }
X2Tree.Add(iCode, new TreeNodeEnd(x1.Value.Term, x1.Value, pSkleivNode, null, X2Tree.Count)); X2Tree.AddTerm(x1.Term, x1, kvp.Value);
Source: https://habr.com/ru/post/328506/
All Articles