Реализация минимизации логических функций методом Квайна-Мак'Класки при неполном входном наборе

d719e0fb0b8428be4f0144d45f7b6ccf.svg
using System;
using System.Collections.Generic;
using System.Linq;

/// 
/// Базовый класс для логических функций
/// 
public abstract class LogicFunction
{
//Символ склееной позиции
public const byte cStarSymb = 2;

//Дизъюнкции или конъюнкции функции
public readonly ICollection Terms = new LinkedList();
//Вычисление значения функции
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());
}
}

/// 
/// Дизъюнктивная нормальная форма
/// 
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;
}
}

/// 
/// Конъюнктивная нормальная форма
/// 
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;
}
}

/// 
/// Дерево термов
/// 
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;
}
}

/// 
/// Базовый интерфейс узла дерева термов
/// 
public interface TreeNodeBase
{
//Очистка выделенных ресурсов
void Clear();
}

/// 
/// Конечный узел дерева термов
/// 
public class TreeNodeEnd : TreeNodeBase
{
//Очистка выделенных ресурсов
public void Clear() { }
}

/// 
/// Промежуточный узел дерева термов
/// 
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;
  }
}
}

/// 
/// Минимизация логической функции методом Квайна---Мак-Класки
/// 
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 NegTerms,
  Dictionary> OutResult, TreeFuncTerm NegativTree, int iLevel)
{
  LinkedList OutR = new LinkedList();
  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 X1Tree, SortedSet X2Tree, LinkedList NegTerms,
  Dictionary> OutResult, SortedSet NegativTree, int iLevel,
  int iTermLength)
{
  LinkedList OutR = new LinkedList();
  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 InX1, SortedSet 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 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 InpTerms, LinkedList NegTerms, Dictionary> OutputTerms, ICollection ResultTerms)
{
  //Подготовка результирующего контейнера
  ResultTerms.Clear();
  //Контейнер первичных входных термов, образовавшие текущие отобранные выходные термы
  HashSet pNumbersForAdd = new HashSet();
  //Контейнер для соответствия первичных входных терм к тому списку выходных, которые их покрывают
  Dictionary> Numbers2Terms = new Dictionary>();
  //Контейнер для соответствия конечного терма к списку первичных термов, которые его образовали
  Dictionary> Terms2Numbers = new Dictionary>();
  //Формирование распределения по уровню
  foreach (int iLevel in OutputTerms.Keys.OrderByDescending(p => p).AsEnumerable())
  {
        //Сбор статистики об покрытии выходными термами входных
        foreach (byte[] term in OutputTerms[iLevel])
        {
          //Контейнер входных термов, которые покрывает данный выходной терм term
          HashSet InTermsCont = new HashSet();
          //Цикл по всем входным термам
          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 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());
                  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 PositivTerms, IEnumerable NegativTerms, ICollection OutR)
{
  int iTotalLevels = (PositivTerms.Count() > 0 ? PositivTerms.First().Length : (NegativTerms != null && NegativTerms.Count() > 0 ? NegativTerms.First().Length : 0));
  Dictionary> SkleivTerms = new Dictionary>(iTotalLevels);
  LinkedList InpTerms = new LinkedList();
  LinkedList NegTerms = new LinkedList();

  if (iTotalLevels < 40)
  {
        SortedSet X1PositivTree = new SortedSet();

        DeleteDublicatingTerms(PositivTerms, X1PositivTree);

        SortedSet X1NegativTree = null;
        if (NegativTerms != null)
        {
          X1NegativTree = new SortedSet();
          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 X2Tree = new SortedSet();
          Skleivanie(X1PositivTree, X2Tree, NegTerms, SkleivTerms, X1NegativTree, iLevelCounter, iTotalLevels);

          if ((X1NegativTree != null) && (X1NegativTree.Count != 0))
          {
                SortedSet X2NegativTree = new SortedSet();
                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 TermsInput)
{
  LogicFuncMinimize(TermsInput, null, _result.Terms);
}

//Запуск метода
public void Start(IEnumerable TermsInput, IEnumerable NegativTerms)
{
  LogicFuncMinimize(TermsInput, NegativTerms, _result.Terms);
}

//Запуск метода
public void Start(IEnumerable TermsInput)
{
  Start(TermsInput.Select(t => t.Select(p => (byte)(p == '0' ? 0 : 1)).ToArray()));
}

//Запуск метода
public void Start(IEnumerable TermsInput, IEnumerable 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();
  }
}
}


© Habrahabr.ru