Реализация минимизации логических функций методом Квайна-Мак'Класки при неполном входном наборе
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();
}
}
}