-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode_04_carryless.py
More file actions
144 lines (114 loc) · 4.83 KB
/
code_04_carryless.py
File metadata and controls
144 lines (114 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# -*- coding: utf-8 -*-
"""code_04_carryless.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1kv8CcNtD2rkbfI8aHVAGs_pfPBJKBS9_
"""
# Copyright (c) 2026 Hiroshi Harada
# Licensed under the MIT License.
# Date: April 4, 2026
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
# ---------------------------------------------------------
# Utility: Convert integer to fixed-length bit array
# ---------------------------------------------------------
def to_bit_array(n, length):
""" Converts an integer to a right-aligned bit array. """
bits = [int(b) for b in bin(n)[2:]]
arr = np.zeros(length, dtype=np.int8)
if len(bits) > 0:
arr[-len(bits):] = bits
return arr
# ---------------------------------------------------------
# Model B: Shiftless (3n + LSB) (carry ON, noise ON)
# ---------------------------------------------------------
def generate_shiftless_history(seed, steps):
""" Generates the Shiftless trajectory using standard integer arithmetic. """
n = seed
history = []
for _ in range(steps + 1):
history.append(n)
lsb = n & -n
n = 3 * n + lsb
return history
# ---------------------------------------------------------
# Model C: Carryless Shiftless (GF(2)) 3n + LSB
# ---------------------------------------------------------
def generate_carryless_history(seed, steps):
"""
Generates the Carryless Shiftless trajectory in GF(2).
LSB noise is synchronized with the standard Shiftless model.
"""
n_shiftless = seed
bits = [int(b) for b in bin(seed)[2:][::-1]]
p = np.array(bits, dtype=np.int8)
history = []
for _ in range(steps + 1):
val = int("".join(map(str, p[::-1])), 2) if len(p) > 0 else 0
history.append(val)
# Extract LSB from the integer Shiftless trajectory to synchronize noise
lsb = n_shiftless & -n_shiftless
lsb_pos = lsb.bit_length() - 1
# Polynomial multiplication: P(x) * (x+1) in GF(2)
shifted = np.zeros(len(p) + 1, dtype=np.int8)
shifted[1:] = p
original = np.zeros(len(p) + 1, dtype=np.int8)
original[:-1] = p
p_next = np.bitwise_xor(shifted, original)
# Inject LSB noise x^{LSB_pos} into the GF(2) polynomial
if lsb_pos >= len(p_next):
ext = np.zeros(lsb_pos + 1, dtype=np.int8)
ext[:len(p_next)] = p_next
p_next = ext
p_next[lsb_pos] ^= 1
p = p_next
# Update the integer Shiftless n_k for the next step's LSB extraction
n_shiftless = 3 * n_shiftless + lsb
return history
# ---------------------------------------------------------
# Main: Generate and Plot Comparison
# ---------------------------------------------------------
def plot_comparison(seed, steps):
""" Generates the matrices and exports the visual comparison to PNG. """
hist_sft = generate_shiftless_history(seed, steps)
hist_cl = generate_carryless_history(seed, steps)
max_val = max(max(hist_sft), max(hist_cl))
width = max(1, max_val.bit_length()) + 2
def build_matrix(history):
mat = np.zeros((len(history), width), dtype=np.int8)
for i, val in enumerate(history):
mat[i] = to_bit_array(val, width)
return mat
mat_sft = build_matrix(hist_sft)
mat_cl = build_matrix(hist_cl)
fig, axes = plt.subplots(1, 2, figsize=(16, 10), facecolor="#0a0a0a")
cmap = ListedColormap(["#0a0a0a", "#00FFCC"])
titles = [
"1. Shiftless 3n + LSB\n(Carry Avalanche + LSB Noise)",
"2. Carryless 3n + LSB in GF(2)\n(LSB Noise Only)"
]
mats = [mat_sft, mat_cl]
tick_step = 50 if width > 100 else 10
bit_labels = list(range(0, width, tick_step))
x_positions = [width - 1 - b for b in bit_labels]
for ax, mat, title in zip(axes, mats, titles):
ax.imshow(mat, cmap=cmap, aspect="auto", interpolation="nearest")
ax.set_title(title, color="white", fontsize=14, pad=15)
ax.set_xticks(x_positions)
ax.set_xticklabels(bit_labels)
ax.set_xlabel("Bit Position (MSB ← → LSB=0)", color="gray")
ax.tick_params(colors="gray", labelsize=8)
for spine in ax.spines.values():
spine.set_color("#333333")
axes[0].set_ylabel(f"Step k (Seed = {seed})", color="gray")
plt.suptitle(f"The Anatomy of Chaos: Seed {seed} (Steps: {steps})",
color="white", fontsize=22, fontweight="bold", y=0.98)
plt.tight_layout(rect=[0, 0, 1, 0.95])
filename = f"shiftless_vs_carryless_seed_{seed}.png"
plt.savefig(filename, dpi=300, facecolor="#0a0a0a", bbox_inches="tight")
print(f"Success! Exported rendered plot to: {filename}")
plt.show()
if __name__ == "__main__":
# plot_comparison(seed=1, steps=64)
plot_comparison(seed=1, steps=64)