bda-practicals 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include LICENSE
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: bda-practicals
3
+ Version: 0.1.0
4
+ Summary: A collection of Big Data Analytics (BDA) practicals with instant one-word download commands (bda-3, bda-5, bda-6, bda-7).
5
+ Home-page: https://github.com/yourusername/bda-practicals
6
+ Author: Your Name
7
+ Author-email: your.email@example.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: description
18
+ Dynamic: description-content-type
19
+ Dynamic: home-page
20
+ Dynamic: license-file
21
+ Dynamic: requires-python
22
+ Dynamic: summary
23
+
24
+ # Big Data Analytics Practicals (`bda-practicals`)
25
+
26
+ A complete collection of Big Data Analytics (BDA) practical implementations with **instant one-word download commands** (`bda-3`, `bda-5`, `bda-6`, `bda-7`).
27
+
28
+ ---
29
+
30
+ ## ⚡ Instant One-Word Commands
31
+
32
+ Once installed via pip, just type the practical number you want:
33
+
34
+ | Command | Action | Output File in Downloads |
35
+ |---|---|---|
36
+ | **`bda-3`** | Downloads **Practical 3** (MapReduce Word Count Simulation) | `practical_3.py` |
37
+ | **`bda-5`** | Downloads **Practical 5** (DGIM Algorithm for Counting 1s) | `practical_5.py` |
38
+ | **`bda-6`** | Downloads **Practical 6** (Flajolet-Martin Algorithm for Distinct Count) | `practical_6.py` |
39
+ | **`bda-7`** | Downloads **Practical 7** (Bloom Filter Implementation) | `practical_7.py` |
40
+
41
+ > Running any command like `bda-5` immediately puts the clean `.py` file into your **Downloads** folder and **pops open Windows Explorer** so you can view, edit, and run the code!
42
+
43
+ ### Download All Practicals at Once:
44
+ ```bash
45
+ bda all
46
+ # OR
47
+ bda-all
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 🚀 How to Run on Any Computer
53
+
54
+ 1. Open Terminal or Command Prompt:
55
+ ```bash
56
+ pip install bda-practicals
57
+ ```
58
+ 2. Download any practical:
59
+ ```bash
60
+ bda-5
61
+ # (Or bda-3, bda-6, bda-7)
62
+ ```
63
+ 3. Open the folder and run:
64
+ ```bash
65
+ python practical_5.py
66
+ ```
67
+
68
+ ---
69
+
70
+ ## License
71
+ MIT License
@@ -0,0 +1,48 @@
1
+ # Big Data Analytics Practicals (`bda-practicals`)
2
+
3
+ A complete collection of Big Data Analytics (BDA) practical implementations with **instant one-word download commands** (`bda-3`, `bda-5`, `bda-6`, `bda-7`).
4
+
5
+ ---
6
+
7
+ ## ⚡ Instant One-Word Commands
8
+
9
+ Once installed via pip, just type the practical number you want:
10
+
11
+ | Command | Action | Output File in Downloads |
12
+ |---|---|---|
13
+ | **`bda-3`** | Downloads **Practical 3** (MapReduce Word Count Simulation) | `practical_3.py` |
14
+ | **`bda-5`** | Downloads **Practical 5** (DGIM Algorithm for Counting 1s) | `practical_5.py` |
15
+ | **`bda-6`** | Downloads **Practical 6** (Flajolet-Martin Algorithm for Distinct Count) | `practical_6.py` |
16
+ | **`bda-7`** | Downloads **Practical 7** (Bloom Filter Implementation) | `practical_7.py` |
17
+
18
+ > Running any command like `bda-5` immediately puts the clean `.py` file into your **Downloads** folder and **pops open Windows Explorer** so you can view, edit, and run the code!
19
+
20
+ ### Download All Practicals at Once:
21
+ ```bash
22
+ bda all
23
+ # OR
24
+ bda-all
25
+ ```
26
+
27
+ ---
28
+
29
+ ## 🚀 How to Run on Any Computer
30
+
31
+ 1. Open Terminal or Command Prompt:
32
+ ```bash
33
+ pip install bda-practicals
34
+ ```
35
+ 2. Download any practical:
36
+ ```bash
37
+ bda-5
38
+ # (Or bda-3, bda-6, bda-7)
39
+ ```
40
+ 3. Open the folder and run:
41
+ ```bash
42
+ python practical_5.py
43
+ ```
44
+
45
+ ---
46
+
47
+ ## License
48
+ MIT License
@@ -0,0 +1,13 @@
1
+ from bda_package import *
2
+ from bda_package import (
3
+ practical_3,
4
+ practical_5,
5
+ practical_6,
6
+ practical_7,
7
+ download,
8
+ export,
9
+ run_practical,
10
+ run_all,
11
+ )
12
+
13
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from bda_package.__main__ import main
2
+
3
+ if __name__ == '__main__':
4
+ main()
@@ -0,0 +1,53 @@
1
+ """
2
+ bda_package
3
+ ===========
4
+ Big Data Analytics (BDA) practical implementations:
5
+ - Practical 3: MapReduce Word Count Simulation
6
+ - Practical 5: DGIM Algorithm (Counting 1s in a Sliding Window)
7
+ - Practical 6: Flajolet-Martin Algorithm (Distinct Elements Counting)
8
+ - Practical 7: Bloom Filter Implementation
9
+ """
10
+
11
+ from . import practical_3
12
+ from . import practical_5
13
+ from . import practical_6
14
+ from . import practical_7
15
+ from .downloader import download
16
+
17
+ export = download
18
+
19
+ __version__ = "0.1.0"
20
+ __all__ = [
21
+ "practical_3",
22
+ "practical_5",
23
+ "practical_6",
24
+ "practical_7",
25
+ "run_practical",
26
+ "run_all",
27
+ "download",
28
+ "export",
29
+ ]
30
+
31
+ PRACTICALS = {
32
+ 3: practical_3,
33
+ 5: practical_5,
34
+ 6: practical_6,
35
+ 7: practical_7,
36
+ }
37
+
38
+
39
+ def run_practical(number: int, **kwargs):
40
+ """Run a specific BDA practical by number."""
41
+ if number not in PRACTICALS:
42
+ available = ", ".join(map(str, sorted(PRACTICALS.keys())))
43
+ raise ValueError(f"Practical {number} not found. Available: {available}")
44
+ return PRACTICALS[number].run(**kwargs)
45
+
46
+
47
+ def run_all():
48
+ """Run all BDA practicals sequentially."""
49
+ results = {}
50
+ for num, mod in sorted(PRACTICALS.items()):
51
+ print(f"\n{'='*25} RUNNING BDA PRACTICAL {num} {'='*25}")
52
+ results[num] = mod.run()
53
+ return results
@@ -0,0 +1,105 @@
1
+ import sys
2
+ from . import run_practical, run_all, PRACTICALS
3
+ from .downloader import download
4
+
5
+
6
+ def make_cli_for(num: int):
7
+ """Factory to handle direct practical commands like bda-3, bda-5, etc."""
8
+ def handler():
9
+ if len(sys.argv) > 1:
10
+ arg = sys.argv[1].strip().lower()
11
+ if arg in ('--run', 'run'):
12
+ run_practical(num)
13
+ return
14
+ if arg in ('-h', '--help', 'help'):
15
+ print(f"Usage for bda-{num}:")
16
+ print(f" bda-{num} -> Download Practical {num} to Downloads")
17
+ print(f" bda-{num} run -> Run Practical {num} directly in terminal")
18
+ return
19
+ # Default behavior: download practical into Downloads and open folder!
20
+ download(num)
21
+ return handler
22
+
23
+
24
+ cli_p3 = make_cli_for(3)
25
+ cli_p5 = make_cli_for(5)
26
+ cli_p6 = make_cli_for(6)
27
+ cli_p7 = make_cli_for(7)
28
+
29
+
30
+ def print_help():
31
+ print("""
32
+ Big Data Analytics (BDA) Practicals CLI
33
+ =======================================
34
+ Quick One-Word Download Commands:
35
+ bda-3 -> Downloads Practical 3 (MapReduce Word Count) to Downloads
36
+ bda-5 -> Downloads Practical 5 (DGIM Algorithm) to Downloads
37
+ bda-6 -> Downloads Practical 6 (Flajolet-Martin Algorithm) to Downloads
38
+ bda-7 -> Downloads Practical 7 (Bloom Filter) to Downloads
39
+
40
+ Download ALL BDA Practicals:
41
+ bda all -> Downloads all 4 practicals into Downloads/BDA_Practicals
42
+ bda-all -> Downloads all 4 practicals into Downloads/BDA_Practicals
43
+
44
+ Run in terminal:
45
+ bda-3 run -> Runs Practical 3 in terminal
46
+ bda-5 run -> Runs Practical 5 in terminal
47
+ bda run 6 -> Runs Practical 6 in terminal
48
+ """)
49
+
50
+
51
+ def main():
52
+ if len(sys.argv) < 2:
53
+ # Default action when just running "bda":
54
+ # Download Practical 5 into Downloads folder and open it!
55
+ print("No practical specified. Downloading BDA Practical 5 (DGIM Algorithm)...")
56
+ download(5)
57
+ return
58
+
59
+ command = sys.argv[1].strip().lower()
60
+
61
+ if command in ("-h", "--help", "help"):
62
+ print_help()
63
+ return
64
+
65
+ # Check for download / get / export commands
66
+ if command in ("download", "get", "export"):
67
+ target_num = sys.argv[2].strip().lower() if len(sys.argv) > 2 else "5"
68
+ download(target_num)
69
+ return
70
+
71
+ # Check for run command
72
+ if command == "run":
73
+ target = sys.argv[2].strip().lower() if len(sys.argv) > 2 else "5"
74
+ if target == "all":
75
+ run_all()
76
+ else:
77
+ try:
78
+ num = int(target)
79
+ run_practical(num)
80
+ except ValueError:
81
+ print(f"Error: Invalid practical number '{target}'.")
82
+ return
83
+
84
+ if command in ("all", "bda-all"):
85
+ download("all")
86
+ return
87
+
88
+ # Direct number (e.g. "bda 5")
89
+ try:
90
+ num = int(command)
91
+ if num in PRACTICALS:
92
+ download(num)
93
+ else:
94
+ available = ", ".join(map(str, sorted(PRACTICALS.keys())))
95
+ print(f"Error: Practical number must be one of: {available}. Received: {num}")
96
+ print_help()
97
+ sys.exit(1)
98
+ except ValueError:
99
+ print(f"Error: Unrecognized option '{command}'.")
100
+ print_help()
101
+ sys.exit(1)
102
+
103
+
104
+ if __name__ == '__main__':
105
+ main()
@@ -0,0 +1,107 @@
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ TEMPLATES = {}
6
+
7
+ # Read templates directly from the package files so they always stay 100% in sync!
8
+ def _load_templates():
9
+ pkg_dir = Path(__file__).parent
10
+ mapping = {
11
+ 3: pkg_dir / "practical_3.py",
12
+ 5: pkg_dir / "practical_5.py",
13
+ 6: pkg_dir / "practical_6.py",
14
+ 7: pkg_dir / "practical_7.py",
15
+ }
16
+ for num, filepath in mapping.items():
17
+ if filepath.exists():
18
+ with open(filepath, "r", encoding="utf-8") as f:
19
+ TEMPLATES[num] = f.read()
20
+
21
+ _load_templates()
22
+
23
+ PRACTICAL_NAMES = {
24
+ 3: "MapReduce Word Count Simulation",
25
+ 5: "DGIM Algorithm (Counting 1s in Sliding Window)",
26
+ 6: "Flajolet-Martin Algorithm (Distinct Elements Counting)",
27
+ 7: "Bloom Filter Implementation",
28
+ }
29
+
30
+
31
+ def get_default_download_dir(practical_num=None):
32
+ """Returns the Downloads directory on Windows/Mac/Linux."""
33
+ downloads_path = Path.home() / "Downloads"
34
+ if not downloads_path.exists():
35
+ downloads_path = Path.cwd()
36
+
37
+ if practical_num is None or str(practical_num).lower() == 'all':
38
+ target_dir = downloads_path / "BDA_Practicals"
39
+ else:
40
+ target_dir = downloads_path / f"BDA_Practical_{practical_num}"
41
+
42
+ target_dir.mkdir(parents=True, exist_ok=True)
43
+ return target_dir
44
+
45
+
46
+ def download(practical_num=3, target_dir=None, open_folder=True):
47
+ """
48
+ Downloads/exports the specified BDA practical script
49
+ directly to the user's Downloads folder or a specified target directory.
50
+ """
51
+ if not TEMPLATES:
52
+ _load_templates()
53
+
54
+ if isinstance(practical_num, str) and practical_num.lower() == 'all':
55
+ numbers = sorted(list(TEMPLATES.keys()))
56
+ if target_dir is None:
57
+ target_path = get_default_download_dir('all')
58
+ else:
59
+ target_path = Path(target_dir)
60
+ target_path.mkdir(parents=True, exist_ok=True)
61
+ else:
62
+ try:
63
+ num = int(practical_num)
64
+ if num not in TEMPLATES:
65
+ available = ", ".join(map(str, sorted(TEMPLATES.keys())))
66
+ raise ValueError(f"Practical {num} not found. Available practicals: {available}")
67
+ numbers = [num]
68
+ if target_dir is None:
69
+ target_path = get_default_download_dir(num)
70
+ else:
71
+ target_path = Path(target_dir)
72
+ target_path.mkdir(parents=True, exist_ok=True)
73
+ except ValueError as e:
74
+ raise ValueError(f"Invalid practical number: '{practical_num}'. {e}")
75
+
76
+ created_files = []
77
+
78
+ for num in numbers:
79
+ py_filename = f"practical_{num}.py"
80
+ py_filepath = target_path / py_filename
81
+ with open(py_filepath, 'w', encoding='utf-8') as f:
82
+ f.write(TEMPLATES[num])
83
+ created_files.append((py_filename, PRACTICAL_NAMES.get(num, "BDA Practical")))
84
+
85
+ print("\n" + "=" * 65)
86
+ print("SUCCESS! Downloaded BDA Practical files:")
87
+ print(f"Folder: {target_path}")
88
+ for fname, desc in created_files:
89
+ print(f" - {fname} ({desc})")
90
+ print("=" * 65)
91
+ print("To run:")
92
+ if len(numbers) == 1:
93
+ print(f" cd \"{target_path}\"")
94
+ print(f" python practical_{numbers[0]}.py")
95
+ else:
96
+ print(f" cd \"{target_path}\"")
97
+ print(" python practical_3.py (or practical_5.py, practical_6.py, practical_7.py)")
98
+ print("=" * 65 + "\n")
99
+
100
+ # Automatically open folder in Windows Explorer / OS file manager
101
+ if open_folder and sys.platform == 'win32':
102
+ try:
103
+ os.startfile(target_path)
104
+ except Exception:
105
+ pass
106
+
107
+ return str(target_path)
@@ -0,0 +1,86 @@
1
+ from collections import defaultdict
2
+
3
+ # ==========================================
4
+ # 1. MAPPER FUNCTION
5
+ # ==========================================
6
+ def mapper(document_id: int, text: str):
7
+ """
8
+ Takes a document, cleans/tokenizes it, and emits
9
+ key-value pairs of the format: (word, 1).
10
+ """
11
+ mapped_pairs = []
12
+ # Convert text to lowercase and split into words
13
+ words = text.lower().split()
14
+
15
+ for word in words:
16
+ # Strip common punctuation marks
17
+ cleaned_word = word.strip(".,!?;:\"'")
18
+ if cleaned_word:
19
+ mapped_pairs.append((cleaned_word, 1))
20
+
21
+ return mapped_pairs
22
+
23
+
24
+ # ==========================================
25
+ # 2. SHUFFLE & SORT PHASE (Framework step)
26
+ # ==========================================
27
+ def shuffle_and_sort(mapped_results):
28
+ """
29
+ Groups all values associated with the same key (word)
30
+ into a single list: {word: [1, 1, 1, ...]}
31
+ """
32
+ grouped_data = defaultdict(list)
33
+ for word, count in mapped_results:
34
+ grouped_data[word].append(count)
35
+ return grouped_data
36
+
37
+
38
+ # ==========================================
39
+ # 3. REDUCER FUNCTION
40
+ # ==========================================
41
+ def reducer(word, counts):
42
+ """
43
+ Takes a word and its list of counts, aggregates them,
44
+ and outputs the final total frequency for that word.
45
+ """
46
+ return (word, sum(counts))
47
+
48
+
49
+ # ==========================================
50
+ # DRIVER PROGRAM / SIMULATION
51
+ # ==========================================
52
+ def run():
53
+ # Sample input dataset (representing multiple documents/lines in a stream)
54
+ documents = {
55
+ 1: "Big Data analysis using MapReduce framework.",
56
+ 2: "MapReduce is a programming model for data processing.",
57
+ 3: "Big data and map reduce make data processing fast and scalable."
58
+ }
59
+
60
+ print("=== Step 1: Mapping Phase ===")
61
+ all_mapped = []
62
+ for doc_id, text in documents.items():
63
+ pairs = mapper(doc_id, text)
64
+ print(f"Doc {doc_id} Mapped -> {pairs}")
65
+ all_mapped.extend(pairs)
66
+
67
+ print("\n=== Step 2: Shuffle and Sort Phase ===")
68
+ grouped_data = shuffle_and_sort(all_mapped)
69
+ for word, counts in grouped_data.items():
70
+ print(f"Key: '{word}' => Values: {counts}")
71
+
72
+ print("\n=== Step 3: Reducing Phase ===")
73
+ final_word_counts = {}
74
+ for word, counts in grouped_data.items():
75
+ reduced_word, total_count = reducer(word, counts)
76
+ final_word_counts[reduced_word] = total_count
77
+
78
+ print("\n=== Final Output (Word Counts) ===")
79
+ for word, count in sorted(final_word_counts.items()):
80
+ print(f" {word}: {count}")
81
+
82
+ return final_word_counts
83
+
84
+
85
+ if __name__ == "__main__":
86
+ run()
@@ -0,0 +1,162 @@
1
+ class DGIMStream:
2
+ def __init__(self, window_size: int):
3
+ self.window_size = window_size
4
+ self.current_time = 0
5
+ self.buckets = []
6
+
7
+ def _resolve_buckets(self, verbose: bool = False):
8
+ i = 0
9
+ while i < len(self.buckets):
10
+ current_size = self.buckets[i]['size']
11
+ matching_indices = [idx for idx, b in enumerate(self.buckets) if b['size'] == current_size]
12
+ if len(matching_indices) > 2:
13
+ if verbose:
14
+ print(f" [MERGE TRIGGER] Found {len(matching_indices)} buckets of size {current_size}. Merging the two oldest...")
15
+
16
+ oldest_idx_2 = matching_indices[-1]
17
+ oldest_idx_1 = matching_indices[-2]
18
+
19
+ merged_size = current_size * 2
20
+ merged_timestamp = self.buckets[oldest_idx_1]['timestamp']
21
+
22
+ if verbose:
23
+ print(f" - Merging bucket (size {current_size}, ts {self.buckets[oldest_idx_2]['timestamp']}) "
24
+ f"and bucket (size {current_size}, ts {self.buckets[oldest_idx_1]['timestamp']})")
25
+ print(f" - Created new bucket: size {merged_size}, timestamp {merged_timestamp}")
26
+
27
+ del self.buckets[oldest_idx_2]
28
+ del self.buckets[oldest_idx_1]
29
+
30
+ inserted = False
31
+ for idx, b in enumerate(self.buckets):
32
+ if b['timestamp'] < merged_timestamp:
33
+ self.buckets.insert(idx, {'size': merged_size, 'timestamp': merged_timestamp})
34
+ inserted = True
35
+ break
36
+ if not inserted:
37
+ self.buckets.append({'size': merged_size, 'timestamp': merged_timestamp})
38
+
39
+ # Restart check from the beginning to handle cascading merges
40
+ i = 0
41
+ else:
42
+ i += 1
43
+
44
+ def add_bit(self, bit: int, verbose: bool = True):
45
+ """Processes an incoming bit (0 or 1) into the stream."""
46
+ if bit not in (0, 1):
47
+ print("Error: Bit must be 0 or 1.")
48
+ return
49
+
50
+ self.current_time += 1
51
+ if verbose:
52
+ print(f"\n[STREAM EVENT] Time t={self.current_time} | Received Bit: {bit}")
53
+
54
+ # Expire old buckets outside the current sliding window window_size
55
+ cutoff_time = self.current_time - self.window_size
56
+ expired_buckets = [b for b in self.buckets if b['timestamp'] <= cutoff_time]
57
+ if expired_buckets and verbose:
58
+ print(f" [EXPIRY] Removing buckets with timestamp <= {cutoff_time}")
59
+ self.buckets = [b for b in self.buckets if b['timestamp'] > cutoff_time]
60
+
61
+ # If bit is 1, create a new bucket of size 1 at the current timestamp
62
+ if bit == 1:
63
+ if verbose:
64
+ print(f" [INSERT] Bit is 1. Adding new bucket: size=1, timestamp={self.current_time}")
65
+ self.buckets.insert(0, {'size': 1, 'timestamp': self.current_time})
66
+ self._resolve_buckets(verbose=verbose)
67
+ else:
68
+ if verbose:
69
+ print(f" [INFO] Bit is 0. No new bucket created.")
70
+
71
+ if verbose:
72
+ self.print_buckets()
73
+
74
+ def query(self, k: int) -> int:
75
+ """Estimates the number of 1s in the last k elements of the stream."""
76
+ if k <= 0:
77
+ return 0
78
+
79
+ start_time = self.current_time - k + 1
80
+ estimated_ones = 0
81
+
82
+ print(f"\n[QUERY EVALUATION] Estimating 1s in last {k} elements (Window: t={start_time} to t={self.current_time})")
83
+
84
+ last_bucket = None
85
+ for b in self.buckets:
86
+ if b['timestamp'] >= start_time:
87
+ estimated_ones += b['size']
88
+ print(f" - Fully inside window: Bucket(size={b['size']}, ts={b['timestamp']}) -> Added {b['size']}")
89
+ else:
90
+ # This bucket is partially outside the window
91
+ last_bucket = b
92
+ print(f" - Partially outside window: Bucket(size={b['size']}, ts={b['timestamp']}) -> Will add half weight")
93
+ break
94
+
95
+ # DGIM Heuristic: Add half the size of the oldest bucket that overlaps the boundary
96
+ if last_bucket:
97
+ half_size = last_bucket['size'] // 2
98
+ estimated_ones += half_size
99
+ print(f" -> Added half of boundary bucket size ({last_bucket['size']} / 2 = {half_size})")
100
+
101
+ print(f"Final Estimated Count of 1s in last {k} elements: **{estimated_ones}**\n")
102
+ return estimated_ones
103
+
104
+ def print_buckets(self):
105
+ """Displays the current structural state of DGIM buckets."""
106
+ print(f"[CURRENT BUCKETS STATE (Newest -> Oldest)]")
107
+ if not self.buckets:
108
+ print(" (No active buckets)")
109
+ else:
110
+ for idx, b in enumerate(self.buckets):
111
+ print(f" [{idx}] Size: {b['size']} | Timestamp: {b['timestamp']}")
112
+ print("")
113
+
114
+
115
+ def main():
116
+ try:
117
+ window_size = int(input("Enter sliding window size N "))
118
+ except ValueError:
119
+ print("Invalid input. Using default window size N=10.")
120
+ window_size = 10
121
+
122
+ dgim = DGIMStream(window_size=window_size)
123
+
124
+ while True:
125
+ print("Menu:")
126
+ print(" 1. Add a bit to stream (0 or 1)")
127
+ print(" 2. Query count of 1s in last k elements")
128
+ print(" 3. View current buckets state")
129
+ print(" 4. Exit")
130
+
131
+ choice = input("\nChoose an option (1-4): ").strip()
132
+
133
+ if choice == '1':
134
+ try:
135
+ bit = int(input("Enter bit (0 or 1): ").strip())
136
+ if bit in (0, 1):
137
+ dgim.add_bit(bit, verbose=True)
138
+ else:
139
+ print("Please enter strictly 0 or 1.")
140
+ except ValueError:
141
+ print("Invalid input. Enter an integer 0 or 1.")
142
+ elif choice == '2':
143
+ try:
144
+ k = int(input(f"Enter query length k (1 to {dgim.window_size}): ").strip())
145
+ dgim.query(k)
146
+ except ValueError:
147
+ print("Invalid input. Enter a valid integer.")
148
+ elif choice == '3':
149
+ dgim.print_buckets()
150
+ elif choice == '4':
151
+ print("Exiting DGIM Stream CLI. Goodbye!")
152
+ break
153
+ else:
154
+ print("Invalid option. Please choose between 1 and 4.")
155
+
156
+
157
+ def run():
158
+ main()
159
+
160
+
161
+ if __name__ == "__main__":
162
+ main()
@@ -0,0 +1,95 @@
1
+ import hashlib
2
+
3
+ class FlajoletMartin:
4
+ def __init__(self, num_hashes: int = 4):
5
+ self.num_hashes = num_hashes
6
+ self.max_zeros = [0] * num_hashes
7
+ self.stream_count = 0
8
+
9
+ def _hash(self, item: str, seed: int, verbose: bool = False) -> int:
10
+ salted = (str(seed) + item).encode('utf-8')
11
+ digest_hex = hashlib.md5(salted).hexdigest()
12
+ digest_int = int(digest_hex, 16)
13
+ if verbose:
14
+ print(f" [Hash Function #{seed + 1}]")
15
+ print(f" - Salted String : '{salted.decode()}'")
16
+ print(f" - MD5 Hex Digest: {digest_hex}")
17
+ print(f" - Integer Value : {digest_int}")
18
+ return digest_int
19
+
20
+ def _trailing_zeros(self, n: int) -> int:
21
+ if n == 0:
22
+ return 0
23
+ return (n & -n).bit_length() - 1
24
+
25
+ def add_item(self, item: str, verbose: bool = True):
26
+ self.stream_count += 1
27
+ if verbose:
28
+ print(f"\n[STREAM ITEM #{self.stream_count}] Processing item: '{item}'")
29
+ for i in range(self.num_hashes):
30
+ h_val = self._hash(item, seed=i, verbose=verbose)
31
+ tz = self._trailing_zeros(h_val)
32
+ prev_max = self.max_zeros[i]
33
+ updated = False
34
+ if tz > prev_max:
35
+ self.max_zeros[i] = tz
36
+ updated = True
37
+ if verbose:
38
+ print(f" - Trailing Zeros (R): {tz}")
39
+ print(f" - Max R[{i+1}] Tracked: {prev_max} -> Updated Max: {self.max_zeros[i]} {'(NEW MAX!)' if updated else ''}")
40
+
41
+ if verbose:
42
+ print(f"Current Max Zeros Array across all hash functions: {self.max_zeros}\n")
43
+
44
+ def get_estimate(self) -> float:
45
+ phi = 0.77351
46
+ avg_two_to_r = sum(2 ** r for r in self.max_zeros) / self.num_hashes
47
+ estimate = avg_two_to_r / phi
48
+ return round(estimate, 2)
49
+
50
+
51
+ def main():
52
+ try:
53
+ num_hashes = int(input("Enter number of hash functions: "))
54
+ except ValueError:
55
+ print("Invalid input. Using default: 4 hash functions.")
56
+ num_hashes = 4
57
+
58
+ fm = FlajoletMartin(num_hashes=num_hashes)
59
+
60
+ while True:
61
+ print("Menu:")
62
+ print(" 1. Add an item to stream")
63
+ print(" 2. View current distinct element estimation")
64
+ print(" 3. View current Max Zeros array state (R)")
65
+ print(" 4. Exit")
66
+ choice = input("\nChoose an option (1-4): ").strip()
67
+ if choice == '1':
68
+ item = input("Enter item/element: ").strip()
69
+ if item:
70
+ fm.add_item(item, verbose=True)
71
+ else:
72
+ print("Item cannot be empty.")
73
+ elif choice == '2':
74
+ estimate = fm.get_estimate()
75
+ print(f"\n[ESTIMATION REPORT]")
76
+ print(f" - Total items processed : {fm.stream_count}")
77
+ print(f" - Max Zeros Array (R) : {fm.max_zeros}")
78
+ print(f" - Estimated Distinct Count: **{estimate}**\n")
79
+ elif choice == '3':
80
+ print(f"\n[STATE INSPECTION]")
81
+ print(f" - Total items streamed : {fm.stream_count}")
82
+ print(f" - Max Zeros Array (R) : {fm.max_zeros}\n")
83
+ elif choice == '4':
84
+ print("Exiting FM Algorithm CLI. Goodbye!")
85
+ break
86
+ else:
87
+ print("Invalid option. Please choose between 1 and 4.")
88
+
89
+
90
+ def run():
91
+ main()
92
+
93
+
94
+ if __name__ == "__main__":
95
+ main()
@@ -0,0 +1,149 @@
1
+ import hashlib
2
+
3
+ class BloomFilter:
4
+ def __init__(self, size: int, num_hashes: int):
5
+ self.size = size
6
+ self.num_hashes = num_hashes
7
+ self.bit_array = [0] * size
8
+
9
+ def _hashes(self, item: str, verbose: bool = False):
10
+ """Generates k different hash indices for a given item, with optional detailed logging."""
11
+ indices = []
12
+ if verbose:
13
+ print(f"[DEBUG] Processing item: '{item}'")
14
+ print(f"[DEBUG] Target Bit Array Size: {self.size}, Hash Count: {self.num_hashes}")
15
+
16
+ for i in range(self.num_hashes):
17
+ # Create salted string and encode to bytes
18
+ salted_str = str(i) + item
19
+ salted_bytes = salted_str.encode('utf-8')
20
+
21
+ # Generate MD5 hash digest
22
+ digest_hex = hashlib.md5(salted_bytes).hexdigest()
23
+
24
+ # Convert hex digest to integer and map to array index
25
+ digest_int = int(digest_hex, 16)
26
+ index = digest_int % self.size
27
+ indices.append(index)
28
+
29
+ if verbose:
30
+ print(f" [Hash #{i + 1}]")
31
+ print(f" - Salted String : '{salted_str}'")
32
+ print(f" - Byte Encoding : {list(salted_bytes)}")
33
+ print(f" - MD5 Hex Digest: {digest_hex}")
34
+ print(f" - Integer Value : {digest_int}")
35
+ print(f" - Mapped Index : {digest_int} % {self.size} = **Index {index}**")
36
+
37
+ if verbose:
38
+ print(f"[DEBUG] Final Computed Indices: {indices}")
39
+
40
+ return indices
41
+
42
+ def add(self, item: str, verbose: bool = True):
43
+ """Adds an item to the Bloom filter and displays bit changes."""
44
+ if verbose:
45
+ print(f"\n[ADD OPERATION] Adding '{item}'...")
46
+
47
+ indices = self._hashes(item, verbose=verbose)
48
+
49
+ changed_bits = []
50
+ for index in indices:
51
+ previous_state = self.bit_array[index]
52
+ self.bit_array[index] = 1
53
+ changed_bits.append((index, previous_state, self.bit_array[index]))
54
+
55
+ if verbose:
56
+ print(f"[BIT-FLIP SUMMARY]")
57
+ for idx, prev, curr in changed_bits:
58
+ status = "changed 0 -> 1" if prev == 0 else "already 1"
59
+ print(f" - Bit Index [{idx}]: {status}")
60
+ self.print_bit_array()
61
+
62
+ def check(self, item: str, verbose: bool = True) -> bool:
63
+ """Checks if an item is in the Bloom filter with detailed inspection steps."""
64
+ if verbose:
65
+ print(f"\n[CHECK OPERATION] Checking if '{item}' exists...")
66
+
67
+ indices = self._hashes(item, verbose=verbose)
68
+
69
+ exists = True
70
+ if verbose:
71
+ print(f"[LOOKUP EVALUATION]")
72
+
73
+ for index in indices:
74
+ val = self.bit_array[index]
75
+ if verbose:
76
+ print(f" - Inspecting Index [{index}]: Found value **{val}**")
77
+ if val == 0:
78
+ exists = False
79
+
80
+ if verbose:
81
+ print(f" -> Conclusion: All indices checked. Final result = {exists}")
82
+
83
+ return exists
84
+
85
+ def print_bit_array(self):
86
+ print(f"\n[CURRENT BIT ARRAY STATE]")
87
+ if self.size <= 60:
88
+ indices_str = " ".join(f"{i:2}" for i in range(self.size))
89
+ separator = "-" * len(indices_str)
90
+ print(f" Indices: {indices_str}")
91
+ print(f" {separator}")
92
+ bits_str = " ".join(f"{b:2}" for b in self.bit_array)
93
+ print(f" Values : {bits_str}")
94
+ else:
95
+ non_zero_count = sum(self.bit_array)
96
+ print(f" Size: {self.size} bits | Active bits (1s): {non_zero_count} | Zero bits (0s): {self.size - non_zero_count}")
97
+ print(f" Raw Bit Array {self.bit_array[:50]}...")
98
+ print("")
99
+
100
+
101
+ def main():
102
+ try:
103
+ size = int(input("Enter bit array size: "))
104
+ num_hashes = int(input("Enter number of hash functions: "))
105
+ except ValueError:
106
+ print("Using default values: size=40, num_hashes=3")
107
+ size, num_hashes = 40, 3
108
+
109
+ bf = BloomFilter(size, num_hashes)
110
+ bf.print_bit_array()
111
+
112
+ while True:
113
+ print("Menu:")
114
+ print(" 1. Add an item")
115
+ print(" 2. Check an item")
116
+ print(" 3. View current bit array")
117
+ print(" 4. Exit")
118
+ choice = input("\nChoose an option (1-4): ").strip()
119
+ if choice == '1':
120
+ item = input("Enter string to add: ").strip()
121
+ if item:
122
+ bf.add(item, verbose=True)
123
+ else:
124
+ print("Item cannot be empty.")
125
+ elif choice == '2':
126
+ item = input("Enter string to check: ").strip()
127
+ if item:
128
+ found = bf.check(item, verbose=True)
129
+ if found:
130
+ print(f"RESULT: '{item}' **MIGHT BE PRESENT** in the set.")
131
+ else:
132
+ print(f"RESULT: '{item}' is **DEFINITELY NOT PRESENT** in the set.")
133
+ else:
134
+ print("Item cannot be empty.")
135
+ elif choice == '3':
136
+ bf.print_bit_array()
137
+ elif choice == '4':
138
+ print("Exiting Bloom Filter CLI. Goodbye!")
139
+ break
140
+ else:
141
+ print("Invalid option. Please choose between 1 and 4.")
142
+
143
+
144
+ def run():
145
+ main()
146
+
147
+
148
+ if __name__ == "__main__":
149
+ main()
@@ -0,0 +1,71 @@
1
+ Metadata-Version: 2.4
2
+ Name: bda-practicals
3
+ Version: 0.1.0
4
+ Summary: A collection of Big Data Analytics (BDA) practicals with instant one-word download commands (bda-3, bda-5, bda-6, bda-7).
5
+ Home-page: https://github.com/yourusername/bda-practicals
6
+ Author: Your Name
7
+ Author-email: your.email@example.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: description
18
+ Dynamic: description-content-type
19
+ Dynamic: home-page
20
+ Dynamic: license-file
21
+ Dynamic: requires-python
22
+ Dynamic: summary
23
+
24
+ # Big Data Analytics Practicals (`bda-practicals`)
25
+
26
+ A complete collection of Big Data Analytics (BDA) practical implementations with **instant one-word download commands** (`bda-3`, `bda-5`, `bda-6`, `bda-7`).
27
+
28
+ ---
29
+
30
+ ## ⚡ Instant One-Word Commands
31
+
32
+ Once installed via pip, just type the practical number you want:
33
+
34
+ | Command | Action | Output File in Downloads |
35
+ |---|---|---|
36
+ | **`bda-3`** | Downloads **Practical 3** (MapReduce Word Count Simulation) | `practical_3.py` |
37
+ | **`bda-5`** | Downloads **Practical 5** (DGIM Algorithm for Counting 1s) | `practical_5.py` |
38
+ | **`bda-6`** | Downloads **Practical 6** (Flajolet-Martin Algorithm for Distinct Count) | `practical_6.py` |
39
+ | **`bda-7`** | Downloads **Practical 7** (Bloom Filter Implementation) | `practical_7.py` |
40
+
41
+ > Running any command like `bda-5` immediately puts the clean `.py` file into your **Downloads** folder and **pops open Windows Explorer** so you can view, edit, and run the code!
42
+
43
+ ### Download All Practicals at Once:
44
+ ```bash
45
+ bda all
46
+ # OR
47
+ bda-all
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 🚀 How to Run on Any Computer
53
+
54
+ 1. Open Terminal or Command Prompt:
55
+ ```bash
56
+ pip install bda-practicals
57
+ ```
58
+ 2. Download any practical:
59
+ ```bash
60
+ bda-5
61
+ # (Or bda-3, bda-6, bda-7)
62
+ ```
63
+ 3. Open the folder and run:
64
+ ```bash
65
+ python practical_5.py
66
+ ```
67
+
68
+ ---
69
+
70
+ ## License
71
+ MIT License
@@ -0,0 +1,19 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ setup.py
6
+ bda/__init__.py
7
+ bda/__main__.py
8
+ bda_package/__init__.py
9
+ bda_package/__main__.py
10
+ bda_package/downloader.py
11
+ bda_package/practical_3.py
12
+ bda_package/practical_5.py
13
+ bda_package/practical_6.py
14
+ bda_package/practical_7.py
15
+ bda_practicals.egg-info/PKG-INFO
16
+ bda_practicals.egg-info/SOURCES.txt
17
+ bda_practicals.egg-info/dependency_links.txt
18
+ bda_practicals.egg-info/entry_points.txt
19
+ bda_practicals.egg-info/top_level.txt
@@ -0,0 +1,8 @@
1
+ [console_scripts]
2
+ bda = bda_package.__main__:main
3
+ bda-3 = bda_package.__main__:cli_p3
4
+ bda-5 = bda_package.__main__:cli_p5
5
+ bda-6 = bda_package.__main__:cli_p6
6
+ bda-7 = bda_package.__main__:cli_p7
7
+ bda-all = bda_package.__main__:main
8
+ bda-practicals = bda_package.__main__:main
@@ -0,0 +1,2 @@
1
+ bda
2
+ bda_package
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,38 @@
1
+ import os
2
+ from setuptools import setup, find_namespace_packages
3
+
4
+ long_description = ""
5
+ if os.path.exists('README.md'):
6
+ with open('README.md', 'r', encoding='utf-8') as f:
7
+ long_description = f.read()
8
+
9
+ setup(
10
+ name='bda-practicals',
11
+ version='0.1.0',
12
+ packages=find_namespace_packages(include=['bda_package', 'bda_package.*', 'bda', 'bda.*']),
13
+ include_package_data=True,
14
+ install_requires=[], # Standard library only (hashlib, collections, etc.)
15
+ entry_points={
16
+ 'console_scripts': [
17
+ 'bda-3=bda_package.__main__:cli_p3',
18
+ 'bda-5=bda_package.__main__:cli_p5',
19
+ 'bda-6=bda_package.__main__:cli_p6',
20
+ 'bda-7=bda_package.__main__:cli_p7',
21
+ 'bda=bda_package.__main__:main',
22
+ 'bda-all=bda_package.__main__:main',
23
+ 'bda-practicals=bda_package.__main__:main',
24
+ ],
25
+ },
26
+ description='A collection of Big Data Analytics (BDA) practicals with instant one-word download commands (bda-3, bda-5, bda-6, bda-7).',
27
+ long_description=long_description,
28
+ long_description_content_type='text/markdown',
29
+ author='Your Name',
30
+ author_email='your.email@example.com',
31
+ url='https://github.com/yourusername/bda-practicals',
32
+ classifiers=[
33
+ 'Programming Language :: Python :: 3',
34
+ 'License :: OSI Approved :: MIT License',
35
+ 'Operating System :: OS Independent',
36
+ ],
37
+ python_requires='>=3.8',
38
+ )