Example #1
0
        //-1 - greater, 1 - smaller, 0 - error(equal)
        public int CompareTo(object obj)
        {
            Litemset litemset = (Litemset)obj;

            if (items.Count > litemset.items.Count)
            {
                return(1);
            }
            else if (items.Count < litemset.items.Count)
            {
                return(-1);
            }
            else
            {
                for (int i = 0; i < items.Count; i++)
                {
                    if (items[i].CompareTo(litemset.items[i]) == 0)                     // equal
                    {
                        continue;
                    }
                    else
                    {
                        return(items[i].CompareTo(litemset.items[i]));
                    }
                }
                return(0);
            }
        }
Example #2
0
        /// <summary>
        /// Выполняет параллельную версию алгоритма Apriori.
        /// </summary>
        /// <param name="minimalSupport"></param>
        /// <param name="progressOutput">если это правда, информация о прогрессе отправляется на стандартный вывод</param>
        /// <returns>Список L-элементов с поддержкой> = minimumSupport</returns>
        public List <ILitemset> RunParallelApriori(double minimalSupport, bool progressOutput)
        {
            if (Platforms.InitializeAll().Length == 0)
            {
                return(RunApriori(minimalSupport, progressOutput));
            }

            if (minimalSupport > 1 || minimalSupport <= 0)
            {
                return(null);
            }

            if (customerList == null)
            {
                return(null);
            }

            if (this.customersCount == 0)
            {
                return(new List <ILitemset>());
            }

            int minSupport = (int)Math.Ceiling((double)this.customersCount * minimalSupport);

            Stopwatch watch = null;

            if (progressOutput)
            {
                watch = new Stopwatch();
                watch.Start();
            }

            #region conversion of input to int[]

            int itemsCountInt        = 0;
            int transactionsCountInt = 0;
            int customersCountInt    = 0;

            foreach (ICustomer c in customerList)
            {
                ++customersCountInt;
                foreach (ITransaction t in c.GetTransactions())
                {
                    ++transactionsCountInt;
                    foreach (IItem item in t.GetItems())
                    {
                        ++itemsCountInt;
                    }
                }
            }

            uint itemsCountUInt        = (uint)itemsCountInt;
            uint transactionsCountUInt = (uint)transactionsCountInt;
            uint customersCountUInt    = (uint)customersCountInt;

            int[] items               = new int[itemsCountInt];
            int[] itemsTransactions   = new int[itemsCountInt];
            int[] itemsCustomers      = new int[itemsCountInt];
            int[] transactionsStarts  = new int[transactionsCountInt];
            int[] transactionsLengths = new int[transactionsCountInt];
            int[] customersStarts     = new int[customersCountInt]; // с точки зрения транзакций!
            int[] customersLengths    = new int[customersCountInt]; // с точки зрения транзакций!
            {
                int currItem        = 0;
                int currTransaction = 0;
                int currCustomer    = 0;

                int currTransactionLenth = 0;
                int currCustomerLength   = 0;
                foreach (ICustomer c in customerList)
                {
                    currCustomerLength            = 0;
                    customersStarts[currCustomer] = currTransaction;
                    foreach (ITransaction t in c.GetTransactions())
                    {
                        currTransactionLenth = 0;
                        transactionsStarts[currTransaction] = currItem;
                        foreach (IItem item in t.GetItems())
                        {
                            items[currItem]             = item.GetId();
                            itemsTransactions[currItem] = currTransaction;
                            itemsCustomers[currItem]    = currCustomer;
                            ++currItem;
                            ++currTransactionLenth;
                        }
                        ++currCustomerLength;
                        transactionsLengths[currTransaction] = currTransactionLenth;
                        ++currTransaction;
                    }
                    customersLengths[currCustomer] = currCustomerLength;
                    ++currCustomer;
                }
            }

            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("преобразованный вход @ {0} мс", watch.ElapsedMilliseconds);
                watch.Start();
            }

            //Abstract.Diagnostics = true;

            uint localSize = 32;

            InitOpenCL(progressOutput);

            CommandQueue queue = new CommandQueue(device, context);

            #region input buffers allocation and initialization

            Buffer <int> itemsBuf = new Buffer <int>(context, queue, items);

            Buffer <int> transactionsStartsBuf = new Buffer <int>(context, queue, transactionsStarts);

            Buffer <int> customersStartsBuf = new Buffer <int>(context, queue, customersStarts);

            int[]        itemsCount    = new int[] { itemsCountInt };
            Buffer <int> itemsCountBuf = new Buffer <int>(context, queue, itemsCount);

            int[]        transactionsCount    = new int[] { transactionsCountInt };
            Buffer <int> transactionsCountBuf = new Buffer <int>(context, queue, transactionsCount);

            int[]        customersCount    = new int[] { customersCountInt };
            Buffer <int> customersCountBuf = new Buffer <int>(context, queue, customersCount);

            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("буферы, написанные @ {0} мс", watch.ElapsedMilliseconds);
                watch.Start();
            }

            InitOpenCLPrograms(false, progressOutput);

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("программы построены @ {0} мс", watch.ElapsedMilliseconds);
                watch.Start();
            }

            #region empty buffers allocation and initialization

            Buffer <int> Zero = new Buffer <int>(context, queue, new int[] { 0 });
            Zero.Write(false);
            Buffer <int> One = new Buffer <int>(context, queue, new int[] { 1 });
            One.Write(false);

            Buffer <int> tempItemsBuf = new Buffer <int>(context, queue, itemsCountUInt);
            itemsBuf.Copy(0, itemsCountUInt, tempItemsBuf, 0);

            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("Initialized OpenCL in {0}ms.", watch.ElapsedMilliseconds);
                watch.Restart();
            }

            // time: n*log^2(n)
            #region finding empty id

            int[] tempValue = new int[] { -1 };

            kernelMax.SetArgument(0, tempItemsBuf);
            kernelMax.SetArguments(null, itemsCountInt, 0, itemsCountInt);
            uint globalSize = itemsCountUInt;
            for (int scaling = 1; scaling < itemsCountInt; scaling *= (int)localSize)
            {
                kernelMax.SetArgument(4, scaling);
                globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                kernelMax.Launch1D(queue, globalSize, localSize);
                globalSize /= localSize;
            }

            //tempItemsBuf.Read(tempValue, 0, 1); // debug

            int          emptyId    = -1;
            Buffer <int> emptyIdBuf = new Buffer <int>(context, queue, 1);
            kernelIncrement.SetArgument(0, tempItemsBuf);
            kernelIncrement.SetArguments(null, 1, 0, 1);
            kernelIncrement.Launch1D(queue, 1, 1);

            tempItemsBuf.Copy(0, 1, emptyIdBuf, 0);

            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("empty id @ {0}ms", watch.ElapsedMilliseconds);
                watch.Start();
            }

            // time: 3n + n * ( 1.5n + log^2(n) ) == O(n^2)
            #region finding distinct item ids

            Buffer <int> itemsRemainingBuf = new Buffer <int>(context, queue, itemsCountUInt);
            itemsBuf.Copy(itemsRemainingBuf);
            itemsBuf.Copy(tempItemsBuf);

            int uniqueItemsCount = 0;

            int[]        uniqueItems    = new int[itemsCountInt];
            Buffer <int> uniqueItemsBuf = new Buffer <int>(context, queue, uniqueItems);

            kernelZero.SetArgument(0, uniqueItemsBuf);
            kernelZero.SetArguments(null, itemsCountInt, 0, itemsCountInt);
            kernelZero.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, itemsCountUInt), localSize);

            kernelMin.SetArgument(0, tempItemsBuf);
            kernelMin.SetArguments(null, itemsCountInt, 0, itemsCountInt);
            kernelSubstitute.SetArgument(0, itemsRemainingBuf);
            kernelSubstitute.SetArguments(null, itemsCountInt, 0, itemsCountInt);
            kernelSubstitute.SetArgument(4, emptyIdBuf);
            kernelSubstitute.SetArgument(5, tempItemsBuf);

            while (true)
            {
                globalSize = itemsCountUInt;
                for (int scaling = 1; scaling < itemsCountInt; scaling *= (int)localSize)
                {
                    kernelMin.SetArgument(4, scaling);
                    globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                    kernelMin.Launch1D(queue, globalSize, localSize);
                    globalSize /= localSize;
                }

                if (emptyId == -1)
                {
                    emptyIdBuf.Read();
                    emptyId = emptyIdBuf.Value;
                }
                tempItemsBuf.Read(tempValue, 0, 1);
                if (tempValue[0] == emptyId)
                {
                    break;                     // достигнут конец вычисления
                }
                uniqueItems[uniqueItemsCount] = tempValue[0];
                uniqueItemsCount += 1;
                uniqueItemsBuf.Write(false, 0, (uint)uniqueItemsCount);

                kernelSubstitute.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, itemsCountUInt), localSize);


                itemsRemainingBuf.Copy(0, itemsCountUInt, tempItemsBuf, 0);
            }

            uint uniqueItemsCountUInt = (uint)uniqueItemsCount;

            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("distinct items @ {0}ms", watch.ElapsedMilliseconds);
                watch.Start();
            }

            // time: 2n + n^2 * log^2(n) == O(n^2 * log^2(n))
            #region finding supports for items

            int  itemsSupportsCountInt  = itemsCountInt * uniqueItemsCount;
            uint itemsSupportsCountUInt = (uint)itemsSupportsCountInt;

            int[]        itemsSupportsCount    = new int[] { itemsSupportsCountInt };
            Buffer <int> itemsSupportsCountBuf = new Buffer <int>(context, queue, itemsSupportsCount);

            int[]        itemsSupports    = new int[itemsSupportsCountInt];
            Buffer <int> itemsSupportsBuf = new Buffer <int>(context, queue, itemsSupports);

            kernelZero.SetArgument(0, itemsSupportsBuf);
            kernelZero.SetArguments(null, itemsSupportsCountInt, null, itemsSupportsCountInt);
            kernelZero.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, itemsSupportsCountUInt), localSize);

            Buffer <int> uniqueItemBuf = new Buffer <int>(context, queue, 1);

            kernelCopyIfEqual.SetArgument(0, itemsBuf);
            kernelCopyIfEqual.SetArgument(4, itemsSupportsBuf);
            kernelCopyIfEqual.SetArguments(null, itemsCountInt, 0, itemsCountInt,
                                           null, itemsSupportsCountInt, null, itemsCountInt);
            kernelCopyIfEqual.SetArgument(8, uniqueItemBuf);

            int uniqueItemIndex = 0;
            for (int supportsOffset = 0; supportsOffset < itemsSupports.Length; supportsOffset += items.Length)
            {
                uniqueItemBuf.Value = uniqueItems[uniqueItemIndex];
                uniqueItemBuf.Write();
                kernelCopyIfEqual.SetArgument(6, supportsOffset);

                kernelCopyIfEqual.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, itemsCountUInt), localSize);


                ++uniqueItemIndex;
            }

            kernelSubstituteIfNotEqual.SetArgument(0, itemsSupportsBuf);
            kernelSubstituteIfNotEqual.SetArguments(null, itemsSupportsCountInt, 0, itemsSupportsCountInt);
            kernelSubstituteIfNotEqual.SetArgument(4, One);
            kernelSubstituteIfNotEqual.SetArgument(5, Zero);
            kernelSubstituteIfNotEqual.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, itemsSupportsCountUInt), localSize);


            #endregion

            // time: 2n + n^2 * log^2(n) == O(n^2 * log^2(n))
            #region finding supports for transactions

            int  transactionsSupportsCountInt  = transactionsCountInt * uniqueItemsCount;
            uint transactionsSupportsCountUInt = (uint)transactionsSupportsCountInt;

            int[]        transactionsSupportsCount    = new int[] { transactionsSupportsCountInt };
            Buffer <int> transactionsSupportsCountBuf = new Buffer <int>(context, queue, transactionsSupportsCount);

            int[]        transactionsSupports    = new int[transactionsSupportsCountInt];
            Buffer <int> transactionsSupportsBuf = new Buffer <int>(context, queue, transactionsSupports);

            kernelZero.SetArgument(0, transactionsSupportsBuf);
            kernelZero.SetArguments(null, transactionsSupportsCountInt, null, transactionsSupportsCountInt);
            kernelZero.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, transactionsSupportsCountUInt), localSize);

            Buffer <int> itemsSupportsBufCopy = new Buffer <int>(context, queue, itemsSupports);

            itemsSupportsBuf.Copy(0, itemsSupportsCountUInt, itemsSupportsBufCopy, 0);

            kernelSegmentedOr.SetArgument(0, itemsSupportsBufCopy);
            kernelSegmentedOr.SetArguments(null, itemsSupportsCountInt, null, null,
                                           null, itemsCountInt);


            for (int tn = 0; tn < transactionsCountInt; ++tn)
            {
                kernelSegmentedOr.SetArgument(2, transactionsStarts[tn]);
                kernelSegmentedOr.SetArgument(3, transactionsLengths[tn]);

                globalSize = (uint)transactionsLengths[tn];
                for (int scaling = 1; scaling < transactionsLengths[tn]; scaling *= (int)localSize)
                {
                    kernelSegmentedOr.SetArgument(4, scaling);
                    globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                    kernelSegmentedOr.Launch2D(queue, globalSize, localSize, uniqueItemsCountUInt, 1);
                    globalSize /= localSize;
                }

                int offset       = transactionsStarts[tn];
                int outputOffset = tn;
                for (int i = 0; i < uniqueItemsCount; ++i)
                {
                    itemsSupportsBufCopy.Copy((uint)offset, 1, transactionsSupportsBuf, (uint)outputOffset);


                    if (i == uniqueItemsCount - 1)
                    {
                        break;
                    }

                    offset       += itemsCountInt;
                    outputOffset += transactionsCountInt;
                }
            }


            #endregion

            // time: 2n + n^2 * log^2(n) == O(n^2 * log^2(n))
            #region finding supports for customers

            int  customersSupportsCountInt  = customersCountInt * uniqueItemsCount;
            uint customersSupportsCountUInt = (uint)customersSupportsCountInt;

            int[]        customersSupportsCount    = new int[] { customersSupportsCountInt };
            Buffer <int> customersSupportsCountBuf = new Buffer <int>(context, queue, customersSupportsCount);

            int[]        customersSupports    = new int[customersSupportsCountInt];
            Buffer <int> customersSupportsBuf = new Buffer <int>(context, queue, customersSupports);

            kernelZero.SetArgument(0, customersSupportsBuf);
            kernelZero.SetArguments(null, customersSupportsCountInt, null, customersSupportsCountInt);
            kernelZero.Launch1D(queue, Kernels.GetOptimalGlobalSize(localSize, customersSupportsCountUInt), localSize);

            Buffer <int> transactionsSupportsBufCopy = new Buffer <int>(context, queue, transactionsSupports);

            transactionsSupportsBuf.Copy(0, transactionsSupportsCountUInt, transactionsSupportsBufCopy, 0);

            kernelSegmentedOr.SetArgument(0, transactionsSupportsBufCopy);
            kernelSegmentedOr.SetArguments(null, transactionsSupportsCountInt, null, null,
                                           null, transactionsCountInt);


            for (int cn = 0; cn < customersCountInt; ++cn)
            {
                kernelSegmentedOr.SetArgument(2, customersStarts[cn]);
                kernelSegmentedOr.SetArgument(3, customersLengths[cn]);

                globalSize = (uint)customersLengths[cn];
                for (int scaling = 1; scaling < customersLengths[cn]; scaling *= (int)localSize)
                {
                    kernelSegmentedOr.SetArgument(4, scaling);
                    globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                    kernelSegmentedOr.Launch2D(queue, globalSize, localSize, uniqueItemsCountUInt, 1);
                    globalSize /= localSize;
                }


                int offset       = customersStarts[cn];
                int outputOffset = cn;
                for (int i = 0; i < uniqueItemsCount; ++i)
                {
                    transactionsSupportsBufCopy.Copy((uint)offset, 1, customersSupportsBuf, (uint)outputOffset);


                    if (i == uniqueItemsCount - 1)
                    {
                        break;
                    }

                    offset       += transactionsCountInt;
                    outputOffset += customersCountInt;
                }
            }

            #endregion

            // time: n + n * ( n*log^2(n) + n ) == O(n^2 * log^2(n))
            #region litemsets of size 1

            Buffer <int> customersSupportsBufCopy = new Buffer <int>(context, queue, customersSupports);

            customersSupportsBuf.Copy(0, customersSupportsCountUInt, customersSupportsBufCopy, 0);


            kernelSum.SetArgument(0, customersSupportsBufCopy);
            kernelSum.SetArguments(null, customersSupportsCountInt, null, customersCountInt);

            var litemsets          = new List <ILitemset>();
            var supportedLocations = new List <int>();

            for (int un = 0; un < uniqueItemsCount; ++un)
            {
                int offset = un * customersCountInt;
                kernelSum.SetArgument(2, offset);

                globalSize = customersCountUInt;
                for (int scaling = 1; scaling < customersCountInt; scaling *= (int)localSize)
                {
                    kernelSum.SetArgument(4, scaling);
                    globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                    kernelSum.Launch1D(queue, globalSize, localSize);
                    globalSize /= localSize;
                }


                customersSupportsBufCopy.Read(tempValue, (uint)offset, 1);

                int support = tempValue[0];

                if (support < 0 || support > customersCountInt)
                {
                    Zero.Read();
                    One.Read();
                    emptyIdBuf.Read();
                    itemsSupportsBuf.Read();
                    transactionsSupportsBufCopy.Read();
                    customersSupportsBufCopy.Read();
                    itemsSupportsBuf.Read();
                    transactionsSupportsBuf.Read();
                    customersSupportsBuf.Read();
                    throw new Exception(String.Format("support = {0} не имеет теоретических границ [0, {1}]!",
                                                      support, customersCountInt));
                }

                if (support < minSupport)
                {
                    continue;
                }

                litemsets.Add(new Litemset(support, uniqueItems[un]));
                supportedLocations.Add(un);
            }

            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("отдельные элементы @ {0} мс", watch.ElapsedMilliseconds);
                watch.Start();
            }

            // time: n*log^2(n) + n + n * ( 0.5n + n^2 + 0.5n * n^2 * log^2(n) + n*log^2(n) ) == O(n^4 * log^2(n))
            #region litemsets of size 2 and above

            bool moreCanBeFound = true;


            kernelMax.SetArgument(0, customersSupportsBufCopy);
            kernelMax.SetArguments(null, customersSupportsCountInt, null, customersSupportsCountInt);
            globalSize = customersSupportsCountUInt;
            for (int scaling = 1; scaling < customersSupportsCountInt; scaling *= (int)localSize)
            {
                kernelMax.SetArgument(4, scaling);
                globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                kernelMax.Launch1D(queue, globalSize, localSize);
                globalSize /= localSize;
            }

            bool[] newSupportedLocations = new bool[uniqueItemsCount];
            for (int i = 0; i < uniqueItemsCount; ++i)
            {
                newSupportedLocations[i] = false;
            }

            customersSupportsBufCopy.Read(tempValue, 0, 1);
            if (tempValue[0] < minSupport)
            {
                moreCanBeFound = false;
            }
            else if (supportedLocations.Count == 1)
            {
                moreCanBeFound = false;
            }

            if (moreCanBeFound)
            {
                int[] indices = new int[uniqueItemsCount];

                int[]        locations    = new int[uniqueItemsCount];
                Buffer <int> locationsBuf = new Buffer <int>(context, queue, locations);

                int          currLength    = 1;
                Buffer <int> currLengthBuf = new Buffer <int>(context, queue, 1);

                kernelMulitItemSupport.SetArgument(0, transactionsSupportsBufCopy);
                kernelMulitItemSupport.SetArguments(null, transactionsSupportsCountInt,
                                                    transactionsCountInt);
                kernelMulitItemSupport.SetArgument(3, locationsBuf);
                kernelMulitItemSupport.SetArgument(4, currLengthBuf);

                kernelOr.SetArgument(0, transactionsSupportsBufCopy);
                kernelOr.SetArguments(null, transactionsSupportsCountInt, null, null);

                while (moreCanBeFound)
                {
                    ++currLength;
                    currLengthBuf.Value = currLength;
                    currLengthBuf.Write(false);

                    uint litemsetOffset = (uint)litemsets.Count;

                    for (int i = 0; i < currLength; ++i)
                    {
                        indices[i] = i;
                    }
                    int currIndex = currLength - 1;


                    while (true)
                    {
                        #region initialization of int[] locations
                        for (int i = 0; i < currLength; ++i)
                        {
                            locations[i] = supportedLocations[indices[i]];
                        }
                        locationsBuf.Write(false, 0, (uint)currLength);
                        #endregion

                        #region copying of relevant parts of int[] transactionsSupports
                        for (int i = 0; i < currLength; ++i)
                        {
                            #region debugging
                            //if (currLength == 2
                            //	&& uniqueItems[supportedLocations[indices[0]]] == 2
                            //	&& uniqueItems[supportedLocations[indices[1]]] == 3)
                            //{
                            //	// debug only
                            //	queue.Finish();
                            //	transactionsSupportsBufCopy.Read();
                            //	//transactionsSupportsBuf.Read();
                            //}
                            #endregion

                            int offset = supportedLocations[indices[i]] * transactionsCountInt;
                            transactionsSupportsBuf.Copy((uint)offset, transactionsCountUInt,
                                                         transactionsSupportsBufCopy, (uint)offset);
                        }
                        #endregion



                        int stepNo = 1;
                        while (stepNo < currLength)
                        {
                            kernelMulitItemSupport.SetArgument(5, stepNo);
                            kernelMulitItemSupport.Launch2D(queue, transactionsCountUInt, 1, (uint)currLength, 1);
                            stepNo *= 2;
                            queue.Finish();
                        }


                        for (int cn = 0; cn < customersCountInt; ++cn)
                        {
                            kernelOr.SetArgument(2, supportedLocations[indices[0]] * transactionsCountInt + customersStarts[cn]);
                            kernelOr.SetArgument(3, customersLengths[cn]);

                            globalSize = (uint)customersLengths[cn];
                            for (int scaling = 1; scaling < customersLengths[cn]; scaling *= (int)localSize)
                            {
                                kernelOr.SetArgument(4, scaling);
                                globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                                kernelOr.Launch1D(queue, globalSize, localSize);
                                globalSize /= localSize;
                            }
                        }

                        kernelSum.SetArgument(0, transactionsSupportsBufCopy);
                        kernelSum.SetArguments(null, transactionsSupportsCountInt, null, transactionsCountInt);

                        int offset2 = supportedLocations[indices[0]] * transactionsCountInt;
                        kernelSum.SetArgument(2, offset2);

                        globalSize = transactionsCountUInt;
                        for (int scaling = 1; scaling < transactionsCountInt; scaling *= (int)localSize)
                        {
                            kernelSum.SetArgument(4, scaling);
                            globalSize = Kernels.GetOptimalGlobalSize(localSize, globalSize);
                            kernelSum.Launch1D(queue, globalSize, localSize);
                            globalSize /= localSize;
                        }

                        transactionsSupportsBufCopy.Read(tempValue, (uint)offset2, 1);

                        if (tempValue[0] > transactionsSupportsCountInt)
                        {
                            // это означает, что данные были повреждены из-за:
                            // a) некоторая ошибка памяти gpu,
                            // б) плохая синхронизация,
                            // c) или какая-то другая неизвестная вещь
                            // эта ситуация встречается редко, только с очень большими данными
                            // Неизвестная причина неизвестна
                            itemsSupportsBufCopy.Read();
                            transactionsSupportsBufCopy.Read();
                            customersSupportsBufCopy.Read();
                            itemsSupportsBuf.Read();
                            transactionsSupportsBuf.Read();
                            customersSupportsBuf.Read();
                            // эта ошибка является серьезной: она предотвращает продолжение алгоритма
                            throw new Exception(String.Format("{0} больше {1}, невозможно!\n {2}",
                                                              tempValue[0], transactionsSupportsCountInt, String.Join(",", transactionsSupports)));
                        }


                        if (tempValue[0] >= minSupport)
                        {
                            ILitemset l = new Litemset(new List <IItem>());
                            l.SetSupport(tempValue[0]);
                            for (int i = 0; i < currLength; ++i)
                            {
                                int index  = indices[i];
                                int spprtd = supportedLocations[index];
                                l.AddItem(new Item(uniqueItems[spprtd]));
                                newSupportedLocations[spprtd] = true;
                            }



                            litemsets.Add(l);
                        }

                        #region selecting new indices (from supportedLocations) to analyze
                        if ((currIndex == 0 && indices[currIndex] == supportedLocations.Count - currLength) ||
                            currLength == supportedLocations.Count)
                        {
                            break;
                        }
                        if (indices[currIndex] == supportedLocations.Count - currLength + currIndex)
                        {
                            ++indices[currIndex - 1];
                            if (indices[currIndex - 1] + 1 < indices[currIndex])
                            {
                                while (currIndex < currLength - 1)
                                {
                                    indices[currIndex] = indices[currIndex - 1] + 1;
                                    ++currIndex;
                                }
                                indices[currIndex] = indices[currIndex - 1] + 1;
                            }
                            else
                            {
                                --currIndex;
                            }
                            continue;
                        }
                        indices[currIndex] += 1;
                        #endregion
                    }

                    if (progressOutput)
                    {
                        Log.WriteLine("наконец, {0}, до настоящего времени найдено {1} l-itemsets", currLength, litemsets.Count);
                    }


                    if (litemsets.Count <= litemsetOffset || currLength >= uniqueItemsCount)
                    {
                        moreCanBeFound = false;
                        break;
                    }

                    supportedLocations.Clear();
                    for (int i = 0; i < uniqueItemsCount; ++i)
                    {
                        if (newSupportedLocations[i])
                        {
                            supportedLocations.Add(i);
                            newSupportedLocations[i] = false;
                        }
                    }

                    if (currLength >= supportedLocations.Count)
                    {
                        // слишком мало поддерживаемых отдельных элементов, чтобы сделать кандидата требуемой длины
                        moreCanBeFound = false;
                        break;
                    }
                }

                queue.Finish();

                currLengthBuf.Dispose();
                locationsBuf.Dispose();
            }
            #endregion

            if (progressOutput)
            {
                watch.Stop();
                Log.WriteLine("Сгенерировал все l-itemsets, нашел {0} в {1} мс.", litemsets.Count, watch.ElapsedMilliseconds);
            }

            queue.Finish();

            #region disposing of buffers

            // входные буферы
            itemsBuf.Dispose();
            transactionsStartsBuf.Dispose();
            customersStartsBuf.Dispose();
            itemsCountBuf.Dispose();
            transactionsCountBuf.Dispose();
            customersCountBuf.Dispose();

            // создание элементовПоддержка
            emptyIdBuf.Dispose();

            // хранение уникальных предметов
            uniqueItemBuf.Dispose();
            uniqueItemsBuf.Dispose();

            // поддерживает хранение
            itemsSupportsBuf.Dispose();
            itemsSupportsCountBuf.Dispose();
            itemsSupportsBufCopy.Dispose();
            transactionsSupportsBuf.Dispose();
            transactionsSupportsCountBuf.Dispose();
            transactionsSupportsBufCopy.Dispose();
            customersSupportsBuf.Dispose();
            customersSupportsCountBuf.Dispose();
            customersSupportsBufCopy.Dispose();

            // временная память
            tempItemsBuf.Dispose();
            itemsRemainingBuf.Dispose();

            // константы
            Zero.Dispose();
            One.Dispose();

            #endregion

            queue.Dispose();
            Kernels.Dispose();

            return(litemsets);
        }