From da8c2f1ecdea147d6c0b37c501799060feadd60f Mon Sep 17 00:00:00 2001 From: MithunThangaraj Date: Tue, 14 Jul 2026 15:23:11 +0000 Subject: [PATCH 1/5] added cuFFIMiner --- PAMI/fuzzyFrequentPattern/cuda/__init__.py | 0 PAMI/fuzzyFrequentPattern/cuda/abstract.py | 167 +++++++ PAMI/fuzzyFrequentPattern/cuda/cuFFIMiner.py | 441 +++++++++++++++++++ 3 files changed, 608 insertions(+) create mode 100644 PAMI/fuzzyFrequentPattern/cuda/__init__.py create mode 100644 PAMI/fuzzyFrequentPattern/cuda/abstract.py create mode 100644 PAMI/fuzzyFrequentPattern/cuda/cuFFIMiner.py diff --git a/PAMI/fuzzyFrequentPattern/cuda/__init__.py b/PAMI/fuzzyFrequentPattern/cuda/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/PAMI/fuzzyFrequentPattern/cuda/abstract.py b/PAMI/fuzzyFrequentPattern/cuda/abstract.py new file mode 100644 index 000000000..5913f5d78 --- /dev/null +++ b/PAMI/fuzzyFrequentPattern/cuda/abstract.py @@ -0,0 +1,167 @@ +# Copyright (C) 2021 Rage Uday Kiran +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from abc import ABC as _ABC, abstractmethod as _abstractmethod +import time as _time +import math as _math +import csv as _csv +import pandas as _pd +from collections import defaultdict as _defaultdict +from itertools import combinations as _c +import os as _os +import os.path as _ospath +import psutil as _psutil +import sys as _sys +import validators as _validators +import cupy as _cp +import numpy as _np +from urllib.request import urlopen as _urlopen + + +class _fuzzyFrequentPatterns(_ABC): + """ + :Description: This abstract base class defines the variables and methods that every fuzzy frequent pattern mining algorithm must + employ in PAMI + + :Attributes: + + iFile : str + Input file name or path of the input file + minSup: int or float or str + The user can specify minSup either in count or proportion of database size. + If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. + Otherwise, it will be treated as float. + Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float + sep : str + This variable is used to distinguish items from one another in a transaction. The default seperator is tab space or \t. + However, the users can override their default separator. + startTime:float + To record the start time of the algorithm + endTime:float + To record the completion time of the algorithm + finalPatterns: dict + Storing the complete set of patterns in a dictionary variable + oFile : str + Name of the output file to store complete set of fuzzy frequent patterns + memoryUSS : float + To store the total amount of USS memory consumed by the program + memoryRSS : float + To store the total amount of RSS memory consumed by the program + + :Methods: + + mine() + Mining process will start from here + getPatterns() + Complete set of patterns will be retrieved with this function + save(oFile) + Complete set of fuzzy frequent patterns will be loaded in to a output file + getPatternsAsDataFrame() + Complete set of fuzzy frequent patterns will be loaded in to data frame + getMemoryUSS() + Total amount of USS memory consumed by the program will be retrieved from this function + getMemoryRSS() + Total amount of RSS memory consumed by the program will be retrieved from this function + getRuntime() + Total amount of runtime taken by the program will be retrieved from this function + """ + + def __init__(self, iFile, minSup, sep = '\t'): + """ + :param iFile: Input file name or path of the input file + :type iFile: str + :param minSup: The user can specify minSup either in count or proportion of database size. + If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. + Otherwise, it will be treated as float. + Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float + :type minSup: int or float or str + :param sep: separator used in user specified input file + :type sep: str + """ + + self._iFile = iFile + self._minSup = minSup + self._sep = sep + self._finalPatterns = {} + self._startTime = float() + self._endTime = float() + self._memoryRSS = float() + self._memoryUSS = float() + self._oFile = " " + + @_abstractmethod + def startMine(self): + """ + Code for the mining process will start from this function + """ + + pass + + @_abstractmethod + def getPatterns(self): + """ + Complete set of fuzzy frequent patterns generated will be retrieved from this function + """ + + pass + + @_abstractmethod + def save(self, oFile): + """ + Complete set of fuzzy frequent patterns will be saved in to an output file from this function + :param oFile: Name of the output file + :type oFile: csvfile + """ + + pass + + @_abstractmethod + def getPatternsAsDataFrame(self): + """ + Complete set of fuzzy frequent patterns will be loaded in to data frame from this function + """ + + pass + + @_abstractmethod + def getMemoryUSS(self): + """ + Total amount of USS memory consumed by the program will be retrieved from this function + """ + + pass + + @_abstractmethod + def getMemoryRSS(self): + """ + Total amount of RSS memory consumed by the program will be retrieved from this function + """ + pass + + @_abstractmethod + def getRuntime(self): + """ + Total amount of runtime taken by the program will be retrieved from this function + """ + + pass + + @_abstractmethod + def printResults(self): + """ + To print results of the execution. + """ + + pass diff --git a/PAMI/fuzzyFrequentPattern/cuda/cuFFIMiner.py b/PAMI/fuzzyFrequentPattern/cuda/cuFFIMiner.py new file mode 100644 index 000000000..ca1cf576e --- /dev/null +++ b/PAMI/fuzzyFrequentPattern/cuda/cuFFIMiner.py @@ -0,0 +1,441 @@ +# cuFFIMiner is a fundamental algorithm to discover fuzzy frequent patterns in a quantitative transactional database using CUDA. This program employs the downward closure property to reduce the search space effectively. This algorithm employs breadth-first search technique to find the complete set of fuzzy frequent patterns in a quantitative transactional database. +# +# +# **Importing this algorithm into a python program** +# ---------------------------------------------------- +# +# import PAMI.fuzzyFrequentPattern.cuda.cuFFIMiner as alg +# +# obj = alg.cuFFIMiner(iFile, minSup) +# +# obj.mine() +# +# fuzzyFrequentPatterns = obj.getPatterns() +# +# print("Total number of Fuzzy Frequent Patterns:", len(fuzzyFrequentPatterns)) +# +# obj.save(oFile) +# +# Df = obj.getPatternInDataFrame() +# +# memUSS = obj.getMemoryUSS() +# +# print("Total Memory in USS:", memUSS) +# +# memRSS = obj.getMemoryRSS() +# +# print("Total Memory in RSS", memRSS) +# +# run = obj.getRuntime() +# +# print("Total ExecutionTime in seconds:", run) +# + + + + +__copyright__ = """ +Copyright (C) 2021 Rage Uday Kiran + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +""" + +from deprecated import deprecated +from PAMI.fuzzyFrequentPattern.cuda import abstract as _ab +# import abstract as _ab + +class cuFFIMiner(_ab._fuzzyFrequentPatterns): + """ + :Description: cuFFIMiner is a fundamental algorithm to discover fuzzy frequent patterns using Cuda in a quantitative transactional database. This program employs the downward closure property to reduce the search space effectively. This algorithm employs breadth-first search technique to find the complete set of fuzzy frequent patterns in a quantitative transactional database. + + :Reference: Lin, Chun-Wei & Li, Ting & Fournier Viger, Philippe & Hong, Tzung-Pei. (2015). + A fast Algorithm for mining fuzzy frequent itemsets. Journal of Intelligent & Fuzzy Systems. 29. + 2373-2379. 10.3233/IFS-151936. + https://www.researchgate.net/publication/286510908_A_fast_Algorithm_for_mining_fuzzy_frequent_itemSets + + :param iFile: str : + Name of the Input file to mine complete set of fuzzy frequent patterns + :param oFile: str : + Name of the output file to store complete set of fuzzy frequent patterns + :param minSup: int : + The user can specify minSup either in count or proportion of database size. If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. Otherwise, it will be treated as float. + :param sep: str : + This variable is used to distinguish items from one another in a transaction. The default seperator is tab space. However, the users can override their default separator. + + :Attributes: + + startTime : float + To record the start time of the mining process + + endTime : float + To record the completion time of the mining process + + finalPatterns : dict + Storing the complete set of patterns in a dictionary variable + + memoryUSS : float + To store the total amount of USS memory consumed by the program + + memoryRSS : float + To store the total amount of RSS memory consumed by the program + + Database : list + To store the transactions of a database in list + + + + **Methods to execute code on terminal** + ---------------------------------------------------- + + .. code-block:: console + + Format: + + (.venv) $ python3 cuFFIMiner.py + + Example Usage: + + (.venv) $ python3 cuFFIMiner.py sampleDB.txt patterns.txt 10.0 + + .. note:: minSup will be considered in percentage of database transactions + + + **Importing this algorithm into a python program** + ---------------------------------------------------- + + .. code-block:: python + + import PAMI.fuzzyFrequentPattern.cuda.cuFFIMiner as alg + + obj = alg.cuFFIMiner(iFile, minSup) + + obj.mine() + + fuzzyFrequentPatterns = obj.getPatterns() + + print("Total number of Fuzzy Frequent Patterns:", len(fuzzyFrequentPatterns)) + + obj.save(oFile) + + Df = obj.getPatternInDataFrame() + + memUSS = obj.getMemoryUSS() + + print("Total Memory in USS:", memUSS) + + memRSS = obj.getMemoryRSS() + + print("Total Memory in RSS", memRSS) + + run = obj.getRuntime() + + print("Total ExecutionTime in seconds:", run) + + + **Credits:** + ------------- + + The complete program was written by Mithun Thangaraj under the supervision of Professor Rage Uday Kiran. + + """ + + _minSup = float() + _startTime = float() + _endTime = float() + _finalPatterns = {} + _iFile = " " + _oFile = " " + _sep = "\t" + _memoryUSS = float() + _memoryRSS = float() + _transactions = [] + _fuzzyValues = [] + _dbLen = 0 + + _supportKernel = _ab._cp.RawKernel(r''' + + extern "C" __global__ + + void supportKernel(const float *matrix, const unsigned int *pairsA, const unsigned int *pairsB, + float *supports, unsigned int numElements, unsigned int numPairs) + { + __shared__ float partial[256]; + unsigned int p = blockIdx.x; + if (p >= numPairs) return; + const float *a = matrix + (unsigned long long)pairsA[p] * numElements; + const float *b = matrix + (unsigned long long)pairsB[p] * numElements; + float s = 0.0f; + for (unsigned int t = threadIdx.x; t < numElements; t += blockDim.x) + { + float va = a[t]; + float vb = b[t]; + s += va < vb ? va : vb; + } + partial[threadIdx.x] = s; + __syncthreads(); + for (unsigned int stride = blockDim.x / 2; stride > 0; stride >>= 1) + { + if (threadIdx.x < stride) + partial[threadIdx.x] += partial[threadIdx.x + stride]; + __syncthreads(); + } + if (threadIdx.x == 0) + supports[p] = partial[0]; + } + + ''', 'supportKernel') + + def _creatingItemSets(self): + """ + Storing the complete transactions of the database/input file in a database variable + """ + self._transactions, self._fuzzyValues = [], [] + if isinstance(self._iFile, _ab._pd.DataFrame): + if self._iFile.empty: + print("its empty..") + i = self._iFile.columns.values.tolist() + if 'Transactions' in i: + self._transactions = self._iFile['Transactions'].tolist() + if 'fuzzyValues' in i: + self._fuzzyValues = self._iFile['fuzzyValues'].tolist() + if isinstance(self._iFile, str): + if _ab._validators.url(self._iFile): + data = _ab._urlopen(self._iFile) + for line in data: + line = line.decode("utf-8") + line = line.split("\n")[0] + parts = line.split(":") + parts[0] = parts[0].strip() + parts[1] = parts[1].strip() + items = parts[0].split(self._sep) + quantities = parts[1].split(self._sep) + self._transactions.append([x for x in items if x]) + self._fuzzyValues.append([float(x) for x in quantities if x]) + else: + try: + with open(self._iFile, 'r', encoding='utf-8') as f: + for line in f: + line = line.split("\n")[0] + parts = line.split(":") + parts[0] = parts[0].strip() + parts[1] = parts[1].strip() + items = parts[0].split(self._sep) + quantities = parts[1].split(self._sep) + self._transactions.append([x for x in items if x]) + self._fuzzyValues.append([float(x) for x in quantities if x]) + except IOError: + print("File Not Found") + quit() + + def _convert(self, value): + """ + + To convert the user specified minSup value + + :param value: user specified minSup value + + :type value: int or float or str + + :return: converted type + + """ + if type(value) is int: + value = int(value) + if type(value) is float: + value = (self._dbLen * value) + if type(value) is str: + if '.' in value: + value = float(value) + value = (self._dbLen * value) + else: + value = int(value) + return value + + def arraysAndItems(self): + ArraysAndItems = {} + + for i in range(self._dbLen): + for item, fuzzyValue in zip(self._transactions[i], self._fuzzyValues[i]): + j = tuple([item]) + if j not in ArraysAndItems: + ArraysAndItems[j] = _ab._np.zeros(self._dbLen, dtype=_ab._np.float32) + ArraysAndItems[j][i] = fuzzyValue + + newArraysAndItems = {} + + for k, v in ArraysAndItems.items(): + support = float(v.sum()) + if support >= self._minSup: + self._finalPatterns[k] = support + newArraysAndItems[k] = _ab._cp.array(v) + + return newArraysAndItems + + @deprecated("It is recommended to use 'mine()' instead of 'startMine()' for mining process. Starting from January 2025, 'startMine()' will be completely terminated.") + def startMine(self): + """ + Fuzzy frequent pattern mining process will start from here + """ + self.mine() + + def mine(self): + """ + Fuzzy frequent pattern mining process will start from here + """ + _ab._cp.cuda.Device(0).use() + self._startTime = _ab._time.time() + self._creatingItemSets() + self._dbLen = len(self._transactions) + self._minSup = self._convert(self._minSup) + + ArraysAndItems = self.arraysAndItems() + + while len(ArraysAndItems) > 0: + # print("Total number of ArraysAndItems:", len(ArraysAndItems)) + newArraysAndItems = {} + keys = list(ArraysAndItems.keys()) + + pairsA, pairsB, unions = [], [], [] + seen = set() + for i in range(len(ArraysAndItems)): + # print(i, "/", len(ArraysAndItems), end="\r") + iList = list(keys[i]) + for j in range(i + 1, len(ArraysAndItems)): + jList = list(keys[j]) + union = tuple(sorted(set(iList + jList))) + if union in self._finalPatterns or union in seen: + continue + seen.add(union) + pairsA.append(i) + pairsB.append(j) + unions.append(union) + + if len(pairsA) > 0: + numPairs = len(pairsA) + matrix = _ab._cp.stack(list(ArraysAndItems.values())) + pairsA = _ab._np.asarray(pairsA, dtype=_ab._np.uint32) + pairsB = _ab._np.asarray(pairsB, dtype=_ab._np.uint32) + supports = _ab._cp.zeros(numPairs, dtype=_ab._cp.float32) + self._supportKernel((numPairs,), (256,), + (matrix, _ab._cp.array(pairsA), _ab._cp.array(pairsB), supports, + _ab._np.uint32(self._dbLen), _ab._np.uint32(numPairs))) + supports = supports.get() + + survivors = _ab._np.where(supports >= self._minSup)[0] + if len(survivors) > 0: + survA = _ab._cp.array(pairsA[survivors]) + survB = _ab._cp.array(pairsB[survivors]) + newMatrix = _ab._cp.minimum(matrix[survA], matrix[survB]) + for row, idx in enumerate(survivors): + union = unions[idx] + self._finalPatterns[union] = float(supports[idx]) + newArraysAndItems[union] = newMatrix[row] + + ArraysAndItems = newArraysAndItems + # print() + + self._endTime = _ab._time.time() + process = _ab._psutil.Process(_ab._os.getpid()) + self._memoryUSS = float() + self._memoryRSS = float() + self._memoryUSS = process.memory_full_info().uss + self._memoryRSS = process.memory_info().rss + print("Fuzzy frequent patterns were generated successfully using cuFFIMiner algorithm ") + + def getMemoryUSS(self): + """ + Total amount of USS memory consumed by the mining process will be retrieved from this function + :return: returning USS memory consumed by the mining process + :rtype: float + """ + + return self._memoryUSS + + def getMemoryRSS(self): + """ + Total amount of RSS memory consumed by the mining process will be retrieved from this function + :return: returning RSS memory consumed by the mining process + :rtype: float + """ + + return self._memoryRSS + + def getRuntime(self): + """ + Calculating the total amount of runtime taken by the mining process + :return: returning total amount of runtime taken by the mining process + :rtype: float + """ + + return self._endTime - self._startTime + + def getPatternsAsDataFrame(self): + """ + Storing final fuzzy frequent patterns in a dataframe + :return: returning fuzzy frequent patterns in a dataframe + :rtype: pd.DataFrame + """ + + dataFrame = {} + data = [] + for a, b in self._finalPatterns.items(): + data.append([" ".join(a), b]) + dataFrame = _ab._pd.DataFrame(data, columns=['Patterns', 'Support']) + # dataFrame = dataFrame.replace(r'\r+|\n+|\t+',' ', regex=True) + return dataFrame + + def save(self, outFile): + """ + Complete set of fuzzy frequent patterns will be loaded in to an output file + :param outFile: name of the output file + :type outFile: csvfile + """ + self._oFile = outFile + writer = open(self._oFile, 'w+') + for x, y in self._finalPatterns.items(): + s1 = "\t".join(x) + ":" + str(y) + writer.write("%s \n" % s1) + + def getPatterns(self): + """ + Function to send the set of fuzzy frequent patterns after completion of the mining process + :return: returning fuzzy frequent patterns + :rtype: dict + """ + return self._finalPatterns + + def printResults(self): + """ + This function is used to print results + """ + print("Total number of Fuzzy Frequent Patterns:", len(self.getPatterns())) + print("Total Memory in USS:", self.getMemoryUSS()) + print("Total Memory in RSS", self.getMemoryRSS()) + print("Total ExecutionTime in s:", self.getRuntime()) + +if __name__ == "__main__": + _ap = str() + if len(_ab._sys.argv) == 4 or len(_ab._sys.argv) == 5: + if len(_ab._sys.argv) == 5: + _ap = cuFFIMiner(_ab._sys.argv[1], _ab._sys.argv[3], _ab._sys.argv[4]) + if len(_ab._sys.argv) == 4: + _ap = cuFFIMiner(_ab._sys.argv[1], _ab._sys.argv[3]) + _ap.mine() + print("Total number of Fuzzy Frequent Patterns:", len(_ap.getPatterns())) + _ap.save(_ab._sys.argv[2]) + print("Total Memory in USS:", _ap.getMemoryUSS()) + print("Total Memory in RSS", _ap.getMemoryRSS()) + print("Total ExecutionTime in s:", _ap.getRuntime()) + else: + print("Error! The number of input parameters do not match the total number of parameters provided") From 025623408678c5991c2a226746e54ce8391e84c3 Mon Sep 17 00:00:00 2001 From: MithunThangaraj Date: Tue, 14 Jul 2026 15:24:30 +0000 Subject: [PATCH 2/5] added cuF3PMiner --- .../cuda/__init__.py | 0 .../cuda/abstract.py | 167 +++++++ .../cuda/cuF3PMiner.py | 439 ++++++++++++++++++ 3 files changed, 606 insertions(+) create mode 100644 PAMI/fuzzyPartialPeriodicPatterns/cuda/__init__.py create mode 100644 PAMI/fuzzyPartialPeriodicPatterns/cuda/abstract.py create mode 100644 PAMI/fuzzyPartialPeriodicPatterns/cuda/cuF3PMiner.py diff --git a/PAMI/fuzzyPartialPeriodicPatterns/cuda/__init__.py b/PAMI/fuzzyPartialPeriodicPatterns/cuda/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/PAMI/fuzzyPartialPeriodicPatterns/cuda/abstract.py b/PAMI/fuzzyPartialPeriodicPatterns/cuda/abstract.py new file mode 100644 index 000000000..2bb2862fb --- /dev/null +++ b/PAMI/fuzzyPartialPeriodicPatterns/cuda/abstract.py @@ -0,0 +1,167 @@ +# Copyright (C) 2021 Rage Uday Kiran +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from abc import ABC as _ABC, abstractmethod as _abstractmethod +import time as _time +import math as _math +import csv as _csv +import pandas as _pd +from collections import defaultdict as _defaultdict +from itertools import combinations as _c +import os as _os +import os.path as _ospath +import psutil as _psutil +import sys as _sys +import validators as _validators +import cupy as _cp +import numpy as _np +from urllib.request import urlopen as _urlopen + + +class _fuzzyPartialPeriodicPatterns(_ABC): + """ + :Description: This abstract base class defines the variables and methods that every fuzzy partial periodic pattern mining algorithm must + employ in PAMI + + :Attributes: + + iFile : str + Input file name or path of the input file + minSup: int or float or str + The user can specify minSup either in count or proportion of database size. + If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. + Otherwise, it will be treated as float. + Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float + sep : str + This variable is used to distinguish items from one another in a transaction. The default seperator is tab space or \t. + However, the users can override their default separator. + startTime:float + To record the start time of the algorithm + endTime:float + To record the completion time of the algorithm + finalPatterns: dict + Storing the complete set of patterns in a dictionary variable + oFile : str + Name of the output file to store complete set of fuzzy partial periodic patterns + memoryUSS : float + To store the total amount of USS memory consumed by the program + memoryRSS : float + To store the total amount of RSS memory consumed by the program + + :Methods: + + mine() + Mining process will start from here + getPatterns() + Complete set of patterns will be retrieved with this function + save(oFile) + Complete set of fuzzy partial periodic patterns will be loaded in to a output file + getPatternsAsDataFrame() + Complete set of fuzzy partial periodic patterns will be loaded in to data frame + getMemoryUSS() + Total amount of USS memory consumed by the program will be retrieved from this function + getMemoryRSS() + Total amount of RSS memory consumed by the program will be retrieved from this function + getRuntime() + Total amount of runtime taken by the program will be retrieved from this function + """ + + def __init__(self, iFile, minSup, sep = '\t'): + """ + :param iFile: Input file name or path of the input file + :type iFile: str + :param minSup: The user can specify minSup either in count or proportion of database size. + If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. + Otherwise, it will be treated as float. + Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float + :type minSup: int or float or str + :param sep: separator used in user specified input file + :type sep: str + """ + + self._iFile = iFile + self._minSup = minSup + self._sep = sep + self._finalPatterns = {} + self._startTime = float() + self._endTime = float() + self._memoryRSS = float() + self._memoryUSS = float() + self._oFile = " " + + @_abstractmethod + def startMine(self): + """ + Code for the mining process will start from this function + """ + + pass + + @_abstractmethod + def getPatterns(self): + """ + Complete set of fuzzy partial periodic patterns generated will be retrieved from this function + """ + + pass + + @_abstractmethod + def save(self, oFile): + """ + Complete set of fuzzy partial periodic patterns will be saved in to an output file from this function + :param oFile: Name of the output file + :type oFile: csvfile + """ + + pass + + @_abstractmethod + def getPatternsAsDataFrame(self): + """ + Complete set of fuzzy partial periodic patterns will be loaded in to data frame from this function + """ + + pass + + @_abstractmethod + def getMemoryUSS(self): + """ + Total amount of USS memory consumed by the program will be retrieved from this function + """ + + pass + + @_abstractmethod + def getMemoryRSS(self): + """ + Total amount of RSS memory consumed by the program will be retrieved from this function + """ + pass + + @_abstractmethod + def getRuntime(self): + """ + Total amount of runtime taken by the program will be retrieved from this function + """ + + pass + + @_abstractmethod + def printResults(self): + """ + To print results of the execution. + """ + + pass diff --git a/PAMI/fuzzyPartialPeriodicPatterns/cuda/cuF3PMiner.py b/PAMI/fuzzyPartialPeriodicPatterns/cuda/cuF3PMiner.py new file mode 100644 index 000000000..96367e319 --- /dev/null +++ b/PAMI/fuzzyPartialPeriodicPatterns/cuda/cuF3PMiner.py @@ -0,0 +1,439 @@ +# cuF3PMiner algorithm discovers the fuzzy partial periodic patterns in quantitative irregular multiple timeseries databases using CUDA. This program employs the downward closure property to reduce the search space effectively. This algorithm employs breadth-first search technique to find the complete set of fuzzy partial periodic patterns. +# +# +# **Importing this algorithm into a python program** +# ---------------------------------------------------- +# +# import PAMI.fuzzyPartialPeriodicPatterns.cuda.cuF3PMiner as alg +# +# obj = alg.cuF3PMiner(iFile, minSup) +# +# obj.mine() +# +# fuzzyPartialPeriodicPatterns = obj.getPatterns() +# +# print("Total number of Fuzzy Partial Periodic Patterns:", len(fuzzyPartialPeriodicPatterns)) +# +# obj.save(oFile) +# +# Df = obj.getPatternInDataFrame() +# +# memUSS = obj.getMemoryUSS() +# +# print("Total Memory in USS:", memUSS) +# +# memRSS = obj.getMemoryRSS() +# +# print("Total Memory in RSS", memRSS) +# +# run = obj.getRuntime() +# +# print("Total ExecutionTime in seconds:", run) +# + + + + +__copyright__ = """ +Copyright (C) 2021 Rage Uday Kiran + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +""" + +from deprecated import deprecated +from PAMI.fuzzyPartialPeriodicPatterns.cuda import abstract as _ab +# import abstract as _ab + +class cuF3PMiner(_ab._fuzzyPartialPeriodicPatterns): + """ + :Description: cuF3PMiner algorithm discovers the fuzzy partial periodic patterns in quantitative irregular multiple timeseries databases using Cuda. This program employs the downward closure property to reduce the search space effectively. This algorithm employs breadth-first search technique to find the complete set of fuzzy partial periodic patterns. + + :param iFile: str : + Name of the Input file to mine complete set of fuzzy partial periodic patterns + :param oFile: str : + Name of the output file to store complete set of fuzzy partial periodic patterns + :param minSup: int : + The user can specify minSup either in count or proportion of database size. If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. Otherwise, it will be treated as float. + :param sep: str : + This variable is used to distinguish items from one another in a transaction. The default seperator is tab space. However, the users can override their default separator. + + :Attributes: + + startTime : float + To record the start time of the mining process + + endTime : float + To record the completion time of the mining process + + finalPatterns : dict + Storing the complete set of patterns in a dictionary variable + + memoryUSS : float + To store the total amount of USS memory consumed by the program + + memoryRSS : float + To store the total amount of RSS memory consumed by the program + + Database : list + To store the transactions of a database in list + + + + **Methods to execute code on terminal** + ---------------------------------------------------- + + .. code-block:: console + + Format: + + (.venv) $ python3 cuF3PMiner.py + + Example Usage: + + (.venv) $ python3 cuF3PMiner.py sampleDB.txt patterns.txt 10.0 + + .. note:: minSup will be considered in percentage of database transactions + + + **Importing this algorithm into a python program** + ---------------------------------------------------- + + .. code-block:: python + + import PAMI.fuzzyPartialPeriodicPatterns.cuda.cuF3PMiner as alg + + obj = alg.cuF3PMiner(iFile, minSup) + + obj.mine() + + fuzzyPartialPeriodicPatterns = obj.getPatterns() + + print("Total number of Fuzzy Partial Periodic Patterns:", len(fuzzyPartialPeriodicPatterns)) + + obj.save(oFile) + + Df = obj.getPatternInDataFrame() + + memUSS = obj.getMemoryUSS() + + print("Total Memory in USS:", memUSS) + + memRSS = obj.getMemoryRSS() + + print("Total Memory in RSS", memRSS) + + run = obj.getRuntime() + + print("Total ExecutionTime in seconds:", run) + + + **Credits:** + ------------- + + The complete program was written by Mithun Thangaraj under the supervision of Professor Rage Uday Kiran. + + """ + + _minSup = float() + _startTime = float() + _endTime = float() + _finalPatterns = {} + _iFile = " " + _oFile = " " + _sep = "\t" + _memoryUSS = float() + _memoryRSS = float() + _transactions = [] + _fuzzyValues = [] + _ts = [] + _dbLen = 0 + + _supportKernel = _ab._cp.RawKernel(r''' + + extern "C" __global__ + + void supportKernel(const float *matrix, const unsigned int *pairsA, const unsigned int *pairsB, + float *supports, unsigned int numElements, unsigned int numPairs) + { + __shared__ float partial[256]; + unsigned int p = blockIdx.x; + if (p >= numPairs) return; + const float *a = matrix + (unsigned long long)pairsA[p] * numElements; + const float *b = matrix + (unsigned long long)pairsB[p] * numElements; + float s = 0.0f; + for (unsigned int t = threadIdx.x; t < numElements; t += blockDim.x) + { + float va = a[t]; + float vb = b[t]; + s += va < vb ? va : vb; + } + partial[threadIdx.x] = s; + __syncthreads(); + for (unsigned int stride = blockDim.x / 2; stride > 0; stride >>= 1) + { + if (threadIdx.x < stride) + partial[threadIdx.x] += partial[threadIdx.x + stride]; + __syncthreads(); + } + if (threadIdx.x == 0) + supports[p] = partial[0]; + } + + ''', 'supportKernel') + + def _creatingItemSets(self): + """ + Storing the complete transactions of the database/input file in a database variable + """ + self._transactions, self._fuzzyValues, self._ts = [], [], [] + if isinstance(self._iFile, _ab._pd.DataFrame): + if self._iFile.empty: + print("its empty..") + i = self._iFile.columns.values.tolist() + if 'Transactions' in i: + self._transactions = self._iFile['Transactions'].tolist() + if 'fuzzyValues' in i: + self._fuzzyValues = self._iFile['fuzzyValues'].tolist() + if isinstance(self._iFile, str): + if _ab._validators.url(self._iFile): + data = _ab._urlopen(self._iFile) + for line in data: + line = line.decode("utf-8") + line = line.strip() + parts = line.split(":") + times = [x for x in parts[0].strip().split(self._sep) if x] + items = [x for x in parts[1].strip().split(self._sep) if x] + quantities = [float(x) for x in parts[2].strip().split(self._sep) if x] + tempList = ["(" + times[k] + "," + items[k] + ")" for k in range(len(times))] + self._ts.append(times) + self._transactions.append(tempList) + self._fuzzyValues.append(quantities) + else: + try: + with open(self._iFile, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + parts = line.split(":") + times = [x for x in parts[0].strip().split(self._sep) if x] + items = [x for x in parts[1].strip().split(self._sep) if x] + quantities = [float(x) for x in parts[2].strip().split(self._sep) if x] + tempList = ["(" + times[k] + "," + items[k] + ")" for k in range(len(times))] + self._ts.append(times) + self._transactions.append(tempList) + self._fuzzyValues.append(quantities) + except IOError: + print("File Not Found") + quit() + + def _convert(self, value): + """ + + To convert the user specified minSup value + + :param value: user specified minSup value + + :type value: int or float or str + + :return: converted type + + """ + if type(value) is int: + value = int(value) + if type(value) is float: + value = (self._dbLen * value) + if type(value) is str: + if '.' in value: + value = float(value) + value = (self._dbLen * value) + else: + value = int(value) + return value + + def arraysAndItems(self): + ArraysAndItems = {} + + for i in range(self._dbLen): + for item, fuzzyValue in zip(self._transactions[i], self._fuzzyValues[i]): + j = tuple([item]) + if j not in ArraysAndItems: + ArraysAndItems[j] = _ab._np.zeros(self._dbLen, dtype=_ab._np.float32) + ArraysAndItems[j][i] += fuzzyValue + + newArraysAndItems = {} + + for k, v in ArraysAndItems.items(): + support = float(v.sum()) + if support >= self._minSup: + self._finalPatterns[k] = support + newArraysAndItems[k] = _ab._cp.array(v) + + return newArraysAndItems + + @deprecated("It is recommended to use 'mine()' instead of 'startMine()' for mining process. Starting from January 2025, 'startMine()' will be completely terminated.") + def startMine(self): + """ + Fuzzy partial periodic pattern mining process will start from here + """ + self.mine() + + def mine(self): + """ + Fuzzy partial periodic pattern mining process will start from here + """ + _ab._cp.cuda.Device(0).use() + self._startTime = _ab._time.time() + self._creatingItemSets() + self._dbLen = len(self._transactions) + self._minSup = self._convert(self._minSup) + + ArraysAndItems = self.arraysAndItems() + + while len(ArraysAndItems) > 0: + # print("Total number of ArraysAndItems:", len(ArraysAndItems)) + newArraysAndItems = {} + keys = list(ArraysAndItems.keys()) + + pairsA, pairsB, unions = [], [], [] + seen = set() + for i in range(len(ArraysAndItems)): + # print(i, "/", len(ArraysAndItems), end="\r") + iList = list(keys[i]) + for j in range(i + 1, len(ArraysAndItems)): + jList = list(keys[j]) + union = tuple(sorted(set(iList + jList))) + if union in self._finalPatterns or union in seen: + continue + seen.add(union) + pairsA.append(i) + pairsB.append(j) + unions.append(union) + + if len(pairsA) > 0: + numPairs = len(pairsA) + matrix = _ab._cp.stack(list(ArraysAndItems.values())) + pairsA = _ab._np.asarray(pairsA, dtype=_ab._np.uint32) + pairsB = _ab._np.asarray(pairsB, dtype=_ab._np.uint32) + supports = _ab._cp.zeros(numPairs, dtype=_ab._cp.float32) + self._supportKernel((numPairs,), (256,), + (matrix, _ab._cp.array(pairsA), _ab._cp.array(pairsB), supports, + _ab._np.uint32(self._dbLen), _ab._np.uint32(numPairs))) + supports = supports.get() + + survivors = _ab._np.where(supports >= self._minSup)[0] + if len(survivors) > 0: + survA = _ab._cp.array(pairsA[survivors]) + survB = _ab._cp.array(pairsB[survivors]) + newMatrix = _ab._cp.minimum(matrix[survA], matrix[survB]) + for row, idx in enumerate(survivors): + union = unions[idx] + self._finalPatterns[union] = float(supports[idx]) + newArraysAndItems[union] = newMatrix[row] + + ArraysAndItems = newArraysAndItems + # print() + + self._endTime = _ab._time.time() + process = _ab._psutil.Process(_ab._os.getpid()) + self._memoryUSS = float() + self._memoryRSS = float() + self._memoryUSS = process.memory_full_info().uss + self._memoryRSS = process.memory_info().rss + print("Fuzzy partial periodic patterns were generated successfully using cuF3PMiner algorithm ") + + def getMemoryUSS(self): + """ + Total amount of USS memory consumed by the mining process will be retrieved from this function + :return: returning USS memory consumed by the mining process + :rtype: float + """ + + return self._memoryUSS + + def getMemoryRSS(self): + """ + Total amount of RSS memory consumed by the mining process will be retrieved from this function + :return: returning RSS memory consumed by the mining process + :rtype: float + """ + + return self._memoryRSS + + def getRuntime(self): + """ + Calculating the total amount of runtime taken by the mining process + :return: returning total amount of runtime taken by the mining process + :rtype: float + """ + + return self._endTime - self._startTime + + def getPatternsAsDataFrame(self): + """ + Storing final fuzzy partial periodic patterns in a dataframe + :return: returning fuzzy partial periodic patterns in a dataframe + :rtype: pd.DataFrame + """ + + dataFrame = {} + data = [] + for a, b in self._finalPatterns.items(): + data.append([" ".join(a), b]) + dataFrame = _ab._pd.DataFrame(data, columns=['Patterns', 'Support']) + # dataFrame = dataFrame.replace(r'\r+|\n+|\t+',' ', regex=True) + return dataFrame + + def save(self, outFile): + """ + Complete set of fuzzy partial periodic patterns will be loaded in to an output file + :param outFile: name of the output file + :type outFile: csvfile + """ + self._oFile = outFile + writer = open(self._oFile, 'w+') + for x, y in self._finalPatterns.items(): + s1 = "\t".join(x) + ":" + str(y) + writer.write("%s \n" % s1) + + def getPatterns(self): + """ + Function to send the set of fuzzy partial periodic patterns after completion of the mining process + :return: returning fuzzy partial periodic patterns + :rtype: dict + """ + return self._finalPatterns + + def printResults(self): + """ + This function is used to print results + """ + print("Total number of Fuzzy Partial Periodic Patterns:", len(self.getPatterns())) + print("Total Memory in USS:", self.getMemoryUSS()) + print("Total Memory in RSS", self.getMemoryRSS()) + print("Total ExecutionTime in s:", self.getRuntime()) + +if __name__ == "__main__": + _ap = str() + if len(_ab._sys.argv) == 4 or len(_ab._sys.argv) == 5: + if len(_ab._sys.argv) == 5: + _ap = cuF3PMiner(_ab._sys.argv[1], _ab._sys.argv[3], _ab._sys.argv[4]) + if len(_ab._sys.argv) == 4: + _ap = cuF3PMiner(_ab._sys.argv[1], _ab._sys.argv[3]) + _ap.mine() + print("Total number of Fuzzy Partial Periodic Patterns:", len(_ap.getPatterns())) + _ap.save(_ab._sys.argv[2]) + print("Total Memory in USS:", _ap.getMemoryUSS()) + print("Total Memory in RSS", _ap.getMemoryRSS()) + print("Total ExecutionTime in s:", _ap.getRuntime()) + else: + print("Error! The number of input parameters do not match the total number of parameters provided") From e94404080a16f9731feae89509473832d81e0188 Mon Sep 17 00:00:00 2001 From: MithunThangaraj Date: Tue, 14 Jul 2026 15:53:03 +0000 Subject: [PATCH 3/5] fixed dropped first item and faster bitset construction for CMine --- PAMI/coveragePattern/basic/CMine.py | 59 +++++++++++++++-------------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/PAMI/coveragePattern/basic/CMine.py b/PAMI/coveragePattern/basic/CMine.py index 8b1dcde4d..3274dcf99 100644 --- a/PAMI/coveragePattern/basic/CMine.py +++ b/PAMI/coveragePattern/basic/CMine.py @@ -58,7 +58,7 @@ from PAMI.coveragePattern.basic import abstract as _ab from typing import List, Dict, Tuple, Set, Union, Any, Generator -from deprecation import deprecated +from deprecated import deprecated class CMine(_ab._coveragePatterns): @@ -241,41 +241,45 @@ def creatingCoverageItems(self) -> Dict[str, List[str]]: tidData = {} self._lno = 0 for transaction in self._Database: - self._lno = self._lno + 1 - for item in transaction[1:]: + for item in transaction: if item not in tidData: tidData[item] = [self._lno] else: tidData[item].append(self._lno) + self._lno = self._lno + 1 coverageTidData = {k: v for k, v in tidData.items() if len(v) / len(self._Database) >= self._minRF} coverageTidData = dict(sorted(coverageTidData.items(), reverse=True, key=lambda x: len(x[1]))) return coverageTidData - def tidToBitset(self,item_set: Dict[str, int]) -> Dict[str, int]: + def tidToBitset(self,item_set: Dict[str, List[int]]) -> Dict[str, int]: """ - This function converts tid list to bitset. + This function converts tid list to bitset. Each item's transactions become one + integer with one bit per transaction of the database. - :param item_set: + :param item_set: coverage items and their tid lists :return: Dictionary :rtype: dict[str,int] """ bitset = {} + size = (self._lno + 7) >> 3 for k,v in item_set.items(): - bitset[k] = 0b1 - bitset[k] = (bitset[k] << int(v[0])) | 0b1 - for i in range(1,len(v)): - diff = int(v[i]) - int(v[i-1]) - bitset[k] = (bitset[k] << diff) | 0b1 - bitset[k] = (bitset[k] << (self._lno - int(v[-1]))) + buffer = bytearray(size) + for tid in v: + buffer[tid >> 3] |= 128 >> (tid & 7) + bitset[k] = int.from_bytes(bytes(buffer), 'big') return bitset - def genPatterns(self,prefix: Tuple[str, int],tidData: List[Tuple[str, int]]) -> None: + def genPatterns(self,prefix: Tuple[str, int],tidData: List[Tuple[str, int]],start: int=0) -> None: """ - This function generate coverage pattern about prefix. - - :param prefix: String - :param tidData: list + This function generate coverage pattern about prefix. The prefix carries the union + of the transactions covered by its items, and it is extended with every later item + whose overlap ratio stays within maxOR (sorted closure property). Coverage support + only grows with more items, so it gates the output but never the growth. + + :param prefix: the pattern and the bitset of the transactions it covers + :param tidData: list of coverage items and their bitsets + :param start: index of the first item eligible to extend the prefix :return: None """ # variables to store coverage item set and @@ -283,16 +287,16 @@ def genPatterns(self,prefix: Tuple[str, int],tidData: List[Tuple[str, int]]) -> # Get the length of tidData length = len(tidData) - for i in range(length): + for i in range(start, length): tid = prefix[1] & tidData[i][1] - tid1 = prefix[1] | tidData[i][1] - andCount = bin(tid).count("1") - 1 - orCount = bin(tid1).count("1") - 1 - if orCount/len(self._Database) >= self._minCS and andCount / len(str(prefix[1])) <= self._maxOR: + andCount = tid.bit_count() + if andCount <= self._maxOR * self._mapSupport[tidData[i][0]]: + tid1 = prefix[1] | tidData[i][1] + orCount = tid1.bit_count() coverageItem_set = item_set + '\t' + tidData[i][0] - if orCount / len(self._Database) >= self._minRF: - self._finalPatterns[coverageItem_set] = andCount - self.genPatterns((coverageItem_set,tid),tidData[i+1:length]) + if orCount / len(self._Database) >= self._minCS: + self._finalPatterns[coverageItem_set] = orCount + self.genPatterns((coverageItem_set,tid1),tidData,i+1) def generateAllPatterns(self,coverageItems: Dict[str, int]) -> None: """ @@ -305,7 +309,7 @@ def generateAllPatterns(self,coverageItems: Dict[str, int]) -> None: length = len(tidData) for i in range(length): #print(i,tidData[i][0]) - self.genPatterns(tidData[i],tidData[i+1:length]) + self.genPatterns(tidData[i],tidData,i+1) @deprecated("It is recommended to use 'mine()' instead of 'mine()' for mining process. Starting from January 2025, 'mine()' will be completely terminated.") def startMine(self) -> None: @@ -324,10 +328,10 @@ def mine(self) -> None: self._minRF = self._convert(self._minRF) self._maxOR = self._convert(self._maxOR) coverageItems = self.creatingCoverageItems() + self._mapSupport = {k: len(v) for k, v in coverageItems.items()} self._finalPatterns = {k: len(v) for k, v in coverageItems.items()} coverageItemsBitset = self.tidToBitset(coverageItems) self.generateAllPatterns(coverageItemsBitset) - self.save('output.txt') self._endTime = _ab._time.time() process = _ab._psutil.Process(_ab._os.getpid()) self._memoryUSS = float() @@ -422,7 +426,6 @@ def printResults(self) -> None: if len(_ab._sys.argv) == 6: _ap = CMine(_ab._sys.argv[1], _ab._sys.argv[3], _ab._sys.argv[4], _ab._sys.argv[5]) _ap.mine() - _ap.mine() print("Total number of coverage Patterns:", len(_ap.getPatterns())) _ap.save(_ab._sys.argv[2]) print("Total Memory in USS:", _ap.getMemoryUSS()) From 82822fbaf1dd4396f2e711487ed76f56e9013cce Mon Sep 17 00:00:00 2001 From: MithunThangaraj Date: Tue, 14 Jul 2026 23:54:49 +0000 Subject: [PATCH 4/5] added cuFPFPMiner --- .../cuda/__init__.py | 0 .../cuda/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 165 bytes .../cuda/__pycache__/abstract.cpython-312.pyc | Bin 0 -> 7028 bytes .../__pycache__/cuFPFPMiner.cpython-312.pyc | Bin 0 -> 25038 bytes .../cuda/abstract.py | 174 ++++++ .../cuda/cuFPFPMiner.py | 505 ++++++++++++++++++ 6 files changed, 679 insertions(+) create mode 100644 PAMI/fuzzyPeriodicFrequentPattern/cuda/__init__.py create mode 100644 PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/__init__.cpython-312.pyc create mode 100644 PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/abstract.cpython-312.pyc create mode 100644 PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/cuFPFPMiner.cpython-312.pyc create mode 100644 PAMI/fuzzyPeriodicFrequentPattern/cuda/abstract.py create mode 100644 PAMI/fuzzyPeriodicFrequentPattern/cuda/cuFPFPMiner.py diff --git a/PAMI/fuzzyPeriodicFrequentPattern/cuda/__init__.py b/PAMI/fuzzyPeriodicFrequentPattern/cuda/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/__init__.cpython-312.pyc b/PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b810485ffc1ade263a09e505191cdccb3b9ba416 GIT binary patch literal 165 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 Ys(s;!wet75)p~9D{k4Bs^i(|l4Pgca-2eap literal 0 HcmV?d00001 diff --git a/PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/cuFPFPMiner.cpython-312.pyc b/PAMI/fuzzyPeriodicFrequentPattern/cuda/__pycache__/cuFPFPMiner.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa0cec736ed65c0dba6a2db9edcb64eb380a1389 GIT binary patch literal 25038 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 de|LXm^PbPGd;bfy. + +from abc import ABC as _ABC, abstractmethod as _abstractmethod +import time as _time +import math as _math +import csv as _csv +import pandas as _pd +from collections import defaultdict as _defaultdict +from itertools import combinations as _c +import os as _os +import os.path as _ospath +import psutil as _psutil +import sys as _sys +import validators as _validators +import cupy as _cp +import numpy as _np +from urllib.request import urlopen as _urlopen + + +class _fuzzyPeriodicFrequentPatterns(_ABC): + """ + :Description: This abstract base class defines the variables and methods that every fuzzy periodic frequent + pattern mining algorithm must employ in PAMI + + :Attributes: + + iFile : str + Input file name or path of the input file + minSup: int or float or str + The user can specify minSup either in count or proportion of database size. + If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. + Otherwise, it will be treated as float. + Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float + maxPer: int or float + The user can specify maxPer either in count or proportion of database size. + If the program detects the data type of maxPer is integer, then it treats maxPer is expressed in count. + Otherwise, it will be treated as float. + sep : str + This variable is used to distinguish items from one another in a transaction. The default seperator is tab space or \t. + However, the users can override their default separator. + startTime:float + To record the start time of the algorithm + endTime:float + To record the completion time of the algorithm + finalPatterns: dict + Storing the complete set of patterns in a dictionary variable + oFile : str + Name of the output file to store complete set of fuzzy periodic frequent patterns + memoryUSS : float + To store the total amount of USS memory consumed by the program + memoryRSS : float + To store the total amount of RSS memory consumed by the program + + :Methods: + + mine() + Mining process will start from here + getPatterns() + Complete set of patterns will be retrieved with this function + save(oFile) + Complete set of fuzzy periodic frequent patterns will be loaded in to a output file + getPatternsAsDataFrame() + Complete set of fuzzy periodic frequent patterns will be loaded in to data frame + getMemoryUSS() + Total amount of USS memory consumed by the program will be retrieved from this function + getMemoryRSS() + Total amount of RSS memory consumed by the program will be retrieved from this function + getRuntime() + Total amount of runtime taken by the program will be retrieved from this function + """ + + def __init__(self, iFile, minSup, maxPer, sep = '\t'): + """ + :param iFile: Input file name or path of the input file + :type iFile: str + :param minSup: The user can specify minSup either in count or proportion of database size. + If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. + Otherwise, it will be treated as float. + Example: minSup=10 will be treated as integer, while minSup=10.0 will be treated as float + :type minSup: int or float or str + :param maxPer: The user can specify maximum periodicity either in count or proportion of database size. + :type maxPer: int or float + :param sep: separator used in user specified input file + :type sep: str + """ + + self._iFile = iFile + self._minSup = minSup + self._maxPer = maxPer + self._sep = sep + self._finalPatterns = {} + self._startTime = float() + self._endTime = float() + self._memoryRSS = float() + self._memoryUSS = float() + self._oFile = " " + + @_abstractmethod + def startMine(self): + """ + Code for the mining process will start from this function + """ + + pass + + @_abstractmethod + def getPatterns(self): + """ + Complete set of fuzzy periodic frequent patterns generated will be retrieved from this function + """ + + pass + + @_abstractmethod + def save(self, oFile): + """ + Complete set of fuzzy periodic frequent patterns will be saved in to an output file from this function + :param oFile: Name of the output file + :type oFile: csvfile + """ + + pass + + @_abstractmethod + def getPatternsAsDataFrame(self): + """ + Complete set of fuzzy periodic frequent patterns will be loaded in to data frame from this function + """ + + pass + + @_abstractmethod + def getMemoryUSS(self): + """ + Total amount of USS memory consumed by the program will be retrieved from this function + """ + + pass + + @_abstractmethod + def getMemoryRSS(self): + """ + Total amount of RSS memory consumed by the program will be retrieved from this function + """ + pass + + @_abstractmethod + def getRuntime(self): + """ + Total amount of runtime taken by the program will be retrieved from this function + """ + + pass + + @_abstractmethod + def printResults(self): + """ + To print results of the execution. + """ + + pass diff --git a/PAMI/fuzzyPeriodicFrequentPattern/cuda/cuFPFPMiner.py b/PAMI/fuzzyPeriodicFrequentPattern/cuda/cuFPFPMiner.py new file mode 100644 index 000000000..43ef7ab91 --- /dev/null +++ b/PAMI/fuzzyPeriodicFrequentPattern/cuda/cuFPFPMiner.py @@ -0,0 +1,505 @@ +# cuFPFPMiner is a fundamental algorithm to discover fuzzy periodic frequent patterns in a quantitative temporal database using CUDA. This program employs the downward closure property to reduce the search space effectively. This algorithm employs breadth-first search technique to find the complete set of fuzzy periodic frequent patterns in a quantitative temporal database. +# +# +# **Importing this algorithm into a python program** +# ---------------------------------------------------- +# +# import PAMI.fuzzyPeriodicFrequentPattern.cuda.cuFPFPMiner as alg +# +# obj = alg.cuFPFPMiner(iFile, minSup, maxPer) +# +# obj.mine() +# +# fuzzyPeriodicFrequentPatterns = obj.getPatterns() +# +# print("Total number of Fuzzy Periodic Frequent Patterns:", len(fuzzyPeriodicFrequentPatterns)) +# +# obj.save(oFile) +# +# Df = obj.getPatternsAsDataFrame() +# +# memUSS = obj.getMemoryUSS() +# +# print("Total Memory in USS:", memUSS) +# +# memRSS = obj.getMemoryRSS() +# +# print("Total Memory in RSS", memRSS) +# +# run = obj.getRuntime() +# +# print("Total ExecutionTime in seconds:", run) +# + + + + +__copyright__ = """ +Copyright (C) 2021 Rage Uday Kiran + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +""" + +from deprecated import deprecated +from PAMI.fuzzyPeriodicFrequentPattern.cuda import abstract as _ab +# import abstract as _ab + +class cuFPFPMiner(_ab._fuzzyPeriodicFrequentPatterns): + """ + :Description: cuFPFPMiner is a fundamental algorithm to discover fuzzy periodic frequent patterns using Cuda in a quantitative temporal database. This program employs the downward closure property to reduce the search space effectively. This algorithm employs breadth-first search technique to find the complete set of fuzzy periodic frequent patterns in a quantitative temporal database. + + :Reference: R. U. Kiran et al., "Discovering Fuzzy Periodic-Frequent Patterns in Quantitative Temporal Databases," + 2020 IEEE International Conference on Fuzzy Systems (FUZZ-IEEE), Glasgow, UK, 2020, pp. + 1-8, doi: 10.1109/FUZZ48607.2020.9177579. + + :param iFile: str : + Name of the Input file to mine complete set of fuzzy periodic frequent patterns + :param oFile: str : + Name of the output file to store complete set of fuzzy periodic frequent patterns + :param minSup: int or float or str : + The user can specify minSup either in count or proportion of database size. If the program detects the data type of minSup is integer, then it treats minSup is expressed in count. Otherwise, it will be treated as float. + :param maxPer: int or float : + The user can specify maxPer either in count or proportion of database size. If the program detects the data type of maxPer is integer, then it treats maxPer is expressed in count. + :param sep: str : + This variable is used to distinguish items from one another in a transaction. The default seperator is tab space. However, the users can override their default separator. + + :Attributes: + + startTime : float + To record the start time of the mining process + + endTime : float + To record the completion time of the mining process + + finalPatterns : dict + Storing the complete set of patterns in a dictionary variable + + memoryUSS : float + To store the total amount of USS memory consumed by the program + + memoryRSS : float + To store the total amount of RSS memory consumed by the program + + Database : list + To store the transactions of a database in list + + + + **Methods to execute code on terminal** + ---------------------------------------------------- + + .. code-block:: console + + Format: + + (.venv) $ python3 cuFPFPMiner.py + + Example Usage: + + (.venv) $ python3 cuFPFPMiner.py sampleDB.txt patterns.txt 10.0 3 + + .. note:: minSup will be considered in percentage of database transactions + + + **Importing this algorithm into a python program** + ---------------------------------------------------- + + .. code-block:: python + + import PAMI.fuzzyPeriodicFrequentPattern.cuda.cuFPFPMiner as alg + + obj = alg.cuFPFPMiner(iFile, minSup, maxPer) + + obj.mine() + + fuzzyPeriodicFrequentPatterns = obj.getPatterns() + + print("Total number of Fuzzy Periodic Frequent Patterns:", len(fuzzyPeriodicFrequentPatterns)) + + obj.save(oFile) + + Df = obj.getPatternsAsDataFrame() + + memUSS = obj.getMemoryUSS() + + print("Total Memory in USS:", memUSS) + + memRSS = obj.getMemoryRSS() + + print("Total Memory in RSS", memRSS) + + run = obj.getRuntime() + + print("Total ExecutionTime in seconds:", run) + + + **Credits:** + ------------- + + The complete program was written by Mithun Thangaraj under the supervision of Professor Rage Uday Kiran. + + """ + + _minSup = float() + _maxPer = float() + _startTime = float() + _endTime = float() + _finalPatterns = {} + _iFile = " " + _oFile = " " + _sep = "\t" + _memoryUSS = float() + _memoryRSS = float() + _transactions = [] + _fuzzyValues = [] + _ts = [] + _dbLen = 0 + + _supportKernel = _ab._cp.RawKernel(r''' + + extern "C" __global__ + + void supportKernel(const float *matrix, const unsigned int *pairsA, const unsigned int *pairsB, + float *supports, unsigned int numElements, unsigned int numPairs) + { + __shared__ float partial[256]; + unsigned int p = blockIdx.x; + if (p >= numPairs) return; + const float *a = matrix + (unsigned long long)pairsA[p] * numElements; + const float *b = matrix + (unsigned long long)pairsB[p] * numElements; + float s = 0.0f; + for (unsigned int t = threadIdx.x; t < numElements; t += blockDim.x) + { + float va = a[t]; + float vb = b[t]; + s += va < vb ? va : vb; + } + partial[threadIdx.x] = s; + __syncthreads(); + for (unsigned int stride = blockDim.x / 2; stride > 0; stride >>= 1) + { + if (threadIdx.x < stride) + partial[threadIdx.x] += partial[threadIdx.x + stride]; + __syncthreads(); + } + if (threadIdx.x == 0) + supports[p] = partial[0]; + } + + ''', 'supportKernel') + + _periodKernel = _ab._cp.RawKernel(r''' + + extern "C" __global__ + + void periodKernel(const float *matrix, const float *ts, float *maxPeriods, + unsigned int numElements, unsigned int numRows) + { + unsigned int r = blockIdx.x * blockDim.x + threadIdx.x; + if (r >= numRows) return; + const float *row = matrix + (unsigned long long)r * numElements; + float prev = 0.0f; + float maxGap = 0.0f; + for (unsigned int t = 0; t < numElements; t++) + { + if (row[t] > 0.0f) + { + float gap = ts[t] - prev; + if (gap > maxGap) maxGap = gap; + prev = ts[t]; + } + } + maxPeriods[r] = maxGap; + } + + ''', 'periodKernel') + + def _creatingItemSets(self): + """ + Storing the complete transactions of the database/input file in a database variable + """ + self._transactions, self._fuzzyValues, self._ts = [], [], [] + if isinstance(self._iFile, _ab._pd.DataFrame): + if self._iFile.empty: + print("its empty..") + i = self._iFile.columns.values.tolist() + if 'TS' in i: + self._ts = self._iFile['TS'].tolist() + if 'Transactions' in i: + self._transactions = self._iFile['Transactions'].tolist() + if 'fuzzyValues' in i: + self._fuzzyValues = self._iFile['fuzzyValues'].tolist() + if isinstance(self._iFile, str): + if _ab._validators.url(self._iFile): + data = _ab._urlopen(self._iFile) + for line in data: + line = line.decode("utf-8") + line = line.split("\n")[0] + parts = line.split(":") + parts[0] = parts[0].strip() + parts[1] = parts[1].strip() + items = [x for x in parts[0].split(self._sep) if x] + quantities = [float(x) for x in parts[1].split(self._sep) if x] + self._ts.append(int(items[0])) + self._transactions.append(items[1:]) + self._fuzzyValues.append(quantities) + else: + try: + with open(self._iFile, 'r', encoding='utf-8') as f: + for line in f: + line = line.split("\n")[0] + parts = line.split(":") + parts[0] = parts[0].strip() + parts[1] = parts[1].strip() + items = [x for x in parts[0].split(self._sep) if x] + quantities = [float(x) for x in parts[1].split(self._sep) if x] + self._ts.append(int(items[0])) + self._transactions.append(items[1:]) + self._fuzzyValues.append(quantities) + except IOError: + print("File Not Found") + quit() + + def _convert(self, value): + """ + + To convert the user specified maxPer value + + :param value: user specified maxPer value + + :type value: int or float or str + + :return: converted type + + """ + if type(value) is int: + value = int(value) + if type(value) is float: + value = (self._dbLen * value) + if type(value) is str: + if '.' in value: + value = float(value) + value = (self._dbLen * value) + else: + value = int(value) + return value + + def arraysAndItems(self): + """ + Builds the fuzzy value array of every item, computes the support and the maximum + periodicity of the single items, and returns the arrays of the items that satisfy minSup. + """ + ArraysAndItems = {} + + for i in range(self._dbLen): + for item, fuzzyValue in zip(self._transactions[i], self._fuzzyValues[i]): + j = tuple([item]) + if j not in ArraysAndItems: + ArraysAndItems[j] = _ab._np.zeros(self._dbLen, dtype=_ab._np.float32) + ArraysAndItems[j][i] = fuzzyValue + + lastTs = self._ts[-1] + newArraysAndItems = {} + + for k, v in ArraysAndItems.items(): + support = float(v.sum()) + if support >= self._minSup: + maxPeriod = 0 + prev = None + for idx in _ab._np.nonzero(v)[0]: + t = self._ts[idx] + if prev is not None and t != lastTs: + maxPeriod = max(maxPeriod, t - prev) + prev = t + if maxPeriod <= self._maxPer: + self._finalPatterns[k] = [support, maxPeriod] + newArraysAndItems[k] = _ab._cp.array(v) + + return newArraysAndItems + + def _maxPeriods(self, matrix): + """ + Computes the maximum periodicity of every row of a fuzzy value matrix on the GPU. + A row's periods are the gaps between the timestamps of its consecutive non-zero + entries, including the gap from time 0 to the first occurrence. + + :param matrix: cupy matrix of fuzzy values, one candidate pattern per row + :return: numpy array with the maximum period of each row + """ + numRows = matrix.shape[0] + tsArr = _ab._cp.asarray(self._ts, dtype=_ab._cp.float32) + maxPeriods = _ab._cp.zeros(numRows, dtype=_ab._cp.float32) + threads = 256 + blocks = (numRows + threads - 1) // threads + self._periodKernel((blocks,), (threads,), + (matrix, tsArr, maxPeriods, + _ab._np.uint32(self._dbLen), _ab._np.uint32(numRows))) + return maxPeriods.get() + + @deprecated("It is recommended to use 'mine()' instead of 'startMine()' for mining process. Starting from January 2025, 'startMine()' will be completely terminated.") + def startMine(self): + """ + Fuzzy periodic frequent pattern mining process will start from here + """ + self.mine() + + def mine(self): + """ + Fuzzy periodic frequent pattern mining process will start from here + """ + _ab._cp.cuda.Device(0).use() + self._startTime = _ab._time.time() + self._creatingItemSets() + self._dbLen = len(self._transactions) + self._minSup = float(self._minSup) + self._maxPer = self._convert(self._maxPer) + + ArraysAndItems = self.arraysAndItems() + + while len(ArraysAndItems) > 0: + newArraysAndItems = {} + keys = list(ArraysAndItems.keys()) + + pairsA, pairsB, unions = [], [], [] + seen = set() + for i in range(len(ArraysAndItems)): + iList = list(keys[i]) + for j in range(i + 1, len(ArraysAndItems)): + jList = list(keys[j]) + union = tuple(sorted(set(iList + jList))) + if len(union) != len(iList) + 1 or union in seen: + continue + seen.add(union) + pairsA.append(i) + pairsB.append(j) + unions.append(union) + + if len(pairsA) > 0: + numPairs = len(pairsA) + matrix = _ab._cp.stack(list(ArraysAndItems.values())) + pairsA = _ab._np.asarray(pairsA, dtype=_ab._np.uint32) + pairsB = _ab._np.asarray(pairsB, dtype=_ab._np.uint32) + supports = _ab._cp.zeros(numPairs, dtype=_ab._cp.float32) + self._supportKernel((numPairs,), (256,), + (matrix, _ab._cp.array(pairsA), _ab._cp.array(pairsB), supports, + _ab._np.uint32(self._dbLen), _ab._np.uint32(numPairs))) + supports = supports.get() + + survivors = _ab._np.where(supports >= self._minSup)[0] + if len(survivors) > 0: + survA = _ab._cp.array(pairsA[survivors]) + survB = _ab._cp.array(pairsB[survivors]) + newMatrix = _ab._cp.minimum(matrix[survA], matrix[survB]) + maxPeriods = self._maxPeriods(newMatrix) + for row, idx in enumerate(survivors): + union = unions[idx] + if maxPeriods[row] <= self._maxPer: + self._finalPatterns[union] = [float(supports[idx]), int(maxPeriods[row])] + newArraysAndItems[union] = newMatrix[row] + + ArraysAndItems = newArraysAndItems + + self._endTime = _ab._time.time() + process = _ab._psutil.Process(_ab._os.getpid()) + self._memoryUSS = float() + self._memoryRSS = float() + self._memoryUSS = process.memory_full_info().uss + self._memoryRSS = process.memory_info().rss + print("Fuzzy periodic frequent patterns were generated successfully using cuFPFPMiner algorithm ") + + def getMemoryUSS(self): + """ + Total amount of USS memory consumed by the mining process will be retrieved from this function + :return: returning USS memory consumed by the mining process + :rtype: float + """ + + return self._memoryUSS + + def getMemoryRSS(self): + """ + Total amount of RSS memory consumed by the mining process will be retrieved from this function + :return: returning RSS memory consumed by the mining process + :rtype: float + """ + + return self._memoryRSS + + def getRuntime(self): + """ + Calculating the total amount of runtime taken by the mining process + :return: returning total amount of runtime taken by the mining process + :rtype: float + """ + + return self._endTime - self._startTime + + def getPatternsAsDataFrame(self): + """ + Storing final fuzzy periodic frequent patterns in a dataframe + :return: returning fuzzy periodic frequent patterns in a dataframe + :rtype: pd.DataFrame + """ + + dataFrame = {} + data = [] + for a, b in self._finalPatterns.items(): + data.append([" ".join(a), b[0], b[1]]) + dataFrame = _ab._pd.DataFrame(data, columns=['Patterns', 'Support', 'Periodicity']) + return dataFrame + + def save(self, outFile): + """ + Complete set of fuzzy periodic frequent patterns will be loaded in to an output file + :param outFile: name of the output file + :type outFile: csvfile + """ + self._oFile = outFile + writer = open(self._oFile, 'w+') + for x, y in self._finalPatterns.items(): + s1 = "\t".join(x) + ":" + str(y[0]) + ":" + str(y[1]) + writer.write("%s \n" % s1) + + def getPatterns(self): + """ + Function to send the set of fuzzy periodic frequent patterns after completion of the mining process + :return: returning fuzzy periodic frequent patterns + :rtype: dict + """ + return self._finalPatterns + + def printResults(self): + """ + This function is used to print results + """ + print("Total number of Fuzzy Periodic Frequent Patterns:", len(self.getPatterns())) + print("Total Memory in USS:", self.getMemoryUSS()) + print("Total Memory in RSS", self.getMemoryRSS()) + print("Total ExecutionTime in s:", self.getRuntime()) + +if __name__ == "__main__": + _ap = str() + if len(_ab._sys.argv) == 5 or len(_ab._sys.argv) == 6: + if len(_ab._sys.argv) == 6: + _ap = cuFPFPMiner(_ab._sys.argv[1], _ab._sys.argv[3], _ab._sys.argv[4], _ab._sys.argv[5]) + if len(_ab._sys.argv) == 5: + _ap = cuFPFPMiner(_ab._sys.argv[1], _ab._sys.argv[3], _ab._sys.argv[4]) + _ap.mine() + print("Total number of Fuzzy Periodic Frequent Patterns:", len(_ap.getPatterns())) + _ap.save(_ab._sys.argv[2]) + print("Total Memory in USS:", _ap.getMemoryUSS()) + print("Total Memory in RSS", _ap.getMemoryRSS()) + print("Total ExecutionTime in s:", _ap.getRuntime()) + else: + print("Error! The number of input parameters do not match the total number of parameters provided") From 6346d83ece79f843fd3647eddd91c879c4b9d6e0 Mon Sep 17 00:00:00 2001 From: MithunThangaraj <133865250+MithunThangaraj@users.noreply.github.com> Date: Wed, 15 Jul 2026 13:58:05 +0900 Subject: [PATCH 5/5] updated setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index af134b5e8..aa858fee5 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name='pami', - version='2026.07.09.1', + version='2026.07.15.1', author='Rage Uday Kiran', author_email='uday.rage@gmail.com', description='This software is being developed at the University of Aizu, Aizu-Wakamatsu, Fukushima, Japan',