kececinumbers 0.0.0__py3-none-any.whl
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.
- kececinumbers/__init__.py +119 -0
- kececinumbers/_version.py +9 -0
- kececinumbers/kececinumbers.py +913 -0
- kececinumbers-0.0.0.dist-info/METADATA +634 -0
- kececinumbers-0.0.0.dist-info/RECORD +8 -0
- kececinumbers-0.0.0.dist-info/WHEEL +5 -0
- kececinumbers-0.0.0.dist-info/licenses/LICENSE +21 -0
- kececinumbers-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,913 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
Keçeci Numbers Module (kececinumbers.py)
|
4
|
+
|
5
|
+
This module provides a comprehensive framework for generating, analyzing, and
|
6
|
+
visualizing Keçeci Numbers across various number systems. It supports 11
|
7
|
+
distinct types, from standard integers and complex numbers to more exotic
|
8
|
+
constructs like neutrosophic and bicomplex numbers.
|
9
|
+
|
10
|
+
The core of the module is the `unified_generator`, which implements the
|
11
|
+
specific algorithm for creating Keçeci Number sequences. High-level functions
|
12
|
+
are available for easy interaction, parameter-based generation, and plotting.
|
13
|
+
|
14
|
+
Key Features:
|
15
|
+
- Generation of 11 types of Keçeci Numbers.
|
16
|
+
- A robust, unified algorithm for all number types.
|
17
|
+
- Helper functions for mathematical properties like primality and divisibility.
|
18
|
+
- Advanced plotting capabilities tailored to each number system.
|
19
|
+
- Functions for interactive use or programmatic integration.
|
20
|
+
---
|
21
|
+
|
22
|
+
Keçeci Conjecture: Keçeci Varsayımı, Keçeci-Vermutung, Conjecture de Keçeci, Гипотеза Кечеджи, 凯杰西猜想, ケジェジ予想, Keçeci Huds, Keçeci Hudsiye, Keçeci Hudsia, كَچَه جِي ,حدس کچه جی, کچہ جی حدسیہ
|
23
|
+
|
24
|
+
Keçeci Varsayımı (Keçeci Conjecture) - Önerilen
|
25
|
+
|
26
|
+
Her Keçeci Sayı türü için, `unified_generator` fonksiyonu tarafından oluşturulan dizilerin, sonlu adımdan sonra periyodik bir yapıya veya tekrar eden bir asal temsiline (Keçeci Asal Sayısı, KPN) yakınsadığı sanılmaktadır. Bu davranış, Collatz Varsayımı'nın çoklu cebirsel sistemlere genişletilmiş bir hali olarak değerlendirilebilir.
|
27
|
+
|
28
|
+
Henüz kanıtlanmamıştır ve bu modül bu varsayımı test etmek için bir çerçeve sunar.
|
29
|
+
"""
|
30
|
+
|
31
|
+
# --- Standard Library Imports ---
|
32
|
+
import collections
|
33
|
+
from dataclasses import dataclass
|
34
|
+
from fractions import Fraction
|
35
|
+
import math
|
36
|
+
from matplotlib.gridspec import GridSpec
|
37
|
+
import matplotlib.pyplot as plt
|
38
|
+
import numpy as np
|
39
|
+
import quaternion
|
40
|
+
import random
|
41
|
+
import re
|
42
|
+
import sympy
|
43
|
+
from typing import Any, Dict, List, Optional, Tuple
|
44
|
+
|
45
|
+
|
46
|
+
# ==============================================================================
|
47
|
+
# --- MODULE CONSTANTS: KEÇECI NUMBER TYPES ---
|
48
|
+
# ==============================================================================
|
49
|
+
TYPE_POSITIVE_REAL = 1
|
50
|
+
TYPE_NEGATIVE_REAL = 2
|
51
|
+
TYPE_COMPLEX = 3
|
52
|
+
TYPE_FLOAT = 4
|
53
|
+
TYPE_RATIONAL = 5
|
54
|
+
TYPE_QUATERNION = 6
|
55
|
+
TYPE_NEUTROSOPHIC = 7
|
56
|
+
TYPE_NEUTROSOPHIC_COMPLEX = 8
|
57
|
+
TYPE_HYPERREAL = 9
|
58
|
+
TYPE_BICOMPLEX = 10
|
59
|
+
TYPE_NEUTROSOPHIC_BICOMPLEX = 11
|
60
|
+
|
61
|
+
# ==============================================================================
|
62
|
+
# --- CUSTOM NUMBER CLASS DEFINITIONS ---
|
63
|
+
# ==============================================================================
|
64
|
+
|
65
|
+
@dataclass
|
66
|
+
class NeutrosophicNumber:
|
67
|
+
"""Represents a neutrosophic number of the form a + bI where I^2 = I."""
|
68
|
+
a: float
|
69
|
+
b: float
|
70
|
+
|
71
|
+
def __add__(self, other: Any) -> "NeutrosophicNumber":
|
72
|
+
if isinstance(other, NeutrosophicNumber):
|
73
|
+
return NeutrosophicNumber(self.a + other.a, self.b + other.b)
|
74
|
+
if isinstance(other, (int, float)):
|
75
|
+
return NeutrosophicNumber(self.a + other, self.b)
|
76
|
+
return NotImplemented
|
77
|
+
|
78
|
+
def __sub__(self, other: Any) -> "NeutrosophicNumber":
|
79
|
+
if isinstance(other, NeutrosophicNumber):
|
80
|
+
return NeutrosophicNumber(self.a - other.a, self.b - other.b)
|
81
|
+
if isinstance(other, (int, float)):
|
82
|
+
return NeutrosophicNumber(self.a - other, self.b)
|
83
|
+
return NotImplemented
|
84
|
+
|
85
|
+
def __mul__(self, other: Any) -> "NeutrosophicNumber":
|
86
|
+
if isinstance(other, NeutrosophicNumber):
|
87
|
+
return NeutrosophicNumber(
|
88
|
+
self.a * other.a,
|
89
|
+
self.a * other.b + self.b * other.a + self.b * other.b,
|
90
|
+
)
|
91
|
+
if isinstance(other, (int, float)):
|
92
|
+
return NeutrosophicNumber(self.a * other, self.b * other)
|
93
|
+
return NotImplemented
|
94
|
+
|
95
|
+
def __truediv__(self, divisor: float) -> "NeutrosophicNumber":
|
96
|
+
if isinstance(divisor, (int, float)):
|
97
|
+
if divisor == 0:
|
98
|
+
raise ZeroDivisionError("Cannot divide by zero.")
|
99
|
+
return NeutrosophicNumber(self.a / divisor, self.b / divisor)
|
100
|
+
raise TypeError("Only scalar division is supported.")
|
101
|
+
|
102
|
+
def __str__(self) -> str:
|
103
|
+
return f"{self.a} + {self.b}I"
|
104
|
+
|
105
|
+
@dataclass
|
106
|
+
class NeutrosophicComplexNumber:
|
107
|
+
"""Represents a number with a complex part and an indeterminacy level."""
|
108
|
+
real: float = 0.0
|
109
|
+
imag: float = 0.0
|
110
|
+
indeterminacy: float = 0.0
|
111
|
+
|
112
|
+
def __repr__(self) -> str:
|
113
|
+
return f"NeutrosophicComplexNumber(real={self.real}, imag={self.imag}, indeterminacy={self.indeterminacy})"
|
114
|
+
|
115
|
+
def __str__(self) -> str:
|
116
|
+
return f"({self.real}{self.imag:+}j) + {self.indeterminacy}I"
|
117
|
+
|
118
|
+
def __add__(self, other: Any) -> "NeutrosophicComplexNumber":
|
119
|
+
if isinstance(other, NeutrosophicComplexNumber):
|
120
|
+
return NeutrosophicComplexNumber(
|
121
|
+
self.real + other.real, self.imag + other.imag, self.indeterminacy + other.indeterminacy
|
122
|
+
)
|
123
|
+
if isinstance(other, (int, float)):
|
124
|
+
return NeutrosophicComplexNumber(self.real + other, self.imag, self.indeterminacy)
|
125
|
+
return NotImplemented
|
126
|
+
|
127
|
+
def __sub__(self, other: Any) -> "NeutrosophicComplexNumber":
|
128
|
+
if isinstance(other, NeutrosophicComplexNumber):
|
129
|
+
return NeutrosophicComplexNumber(
|
130
|
+
self.real - other.real, self.imag - other.imag, self.indeterminacy - other.indeterminacy
|
131
|
+
)
|
132
|
+
if isinstance(other, (int, float)):
|
133
|
+
return NeutrosophicComplexNumber(self.real - other, self.imag, self.indeterminacy)
|
134
|
+
return NotImplemented
|
135
|
+
|
136
|
+
def __mul__(self, other: Any) -> "NeutrosophicComplexNumber":
|
137
|
+
if isinstance(other, NeutrosophicComplexNumber):
|
138
|
+
new_real = self.real * other.real - self.imag * other.imag
|
139
|
+
new_imag = self.real * other.imag + self.imag * other.real
|
140
|
+
new_indeterminacy = self.indeterminacy + other.indeterminacy + (self.magnitude_sq() * other.indeterminacy)
|
141
|
+
return NeutrosophicComplexNumber(new_real, new_imag, new_indeterminacy)
|
142
|
+
if isinstance(other, complex):
|
143
|
+
new_real = self.real * other.real - self.imag * other.imag
|
144
|
+
new_imag = self.real * other.imag + self.imag * other.real
|
145
|
+
return NeutrosophicComplexNumber(new_real, new_imag, self.indeterminacy)
|
146
|
+
if isinstance(other, (int, float)):
|
147
|
+
return NeutrosophicComplexNumber(self.real * other, self.imag * other, self.indeterminacy * other)
|
148
|
+
return NotImplemented
|
149
|
+
|
150
|
+
def __truediv__(self, divisor: float) -> "NeutrosophicComplexNumber":
|
151
|
+
if isinstance(divisor, (int, float)):
|
152
|
+
if divisor == 0:
|
153
|
+
raise ZeroDivisionError("Cannot divide by zero.")
|
154
|
+
return NeutrosophicComplexNumber(
|
155
|
+
self.real / divisor, self.imag / divisor, self.indeterminacy / divisor
|
156
|
+
)
|
157
|
+
raise TypeError("Only scalar division is supported.")
|
158
|
+
|
159
|
+
def __radd__(self, other: Any) -> "NeutrosophicComplexNumber":
|
160
|
+
return self.__add__(other)
|
161
|
+
|
162
|
+
def __rsub__(self, other: Any) -> "NeutrosophicComplexNumber":
|
163
|
+
if isinstance(other, (int, float)):
|
164
|
+
return NeutrosophicComplexNumber(other - self.real, -self.imag, -self.indeterminacy)
|
165
|
+
return NotImplemented
|
166
|
+
|
167
|
+
def __rmul__(self, other: Any) -> "NeutrosophicComplexNumber":
|
168
|
+
return self.__mul__(other)
|
169
|
+
|
170
|
+
def magnitude_sq(self) -> float:
|
171
|
+
return self.real**2 + self.imag**2
|
172
|
+
|
173
|
+
@dataclass
|
174
|
+
class HyperrealNumber:
|
175
|
+
"""Represents a hyperreal number as a sequence of real numbers."""
|
176
|
+
sequence: list
|
177
|
+
|
178
|
+
def __add__(self, other: Any) -> "HyperrealNumber":
|
179
|
+
if isinstance(other, HyperrealNumber):
|
180
|
+
return HyperrealNumber([a + b for a, b in zip(self.sequence, other.sequence)])
|
181
|
+
return NotImplemented
|
182
|
+
|
183
|
+
def __sub__(self, other: Any) -> "HyperrealNumber":
|
184
|
+
if isinstance(other, HyperrealNumber):
|
185
|
+
return HyperrealNumber([a - b for a, b in zip(self.sequence, other.sequence)])
|
186
|
+
return NotImplemented
|
187
|
+
|
188
|
+
def __mul__(self, scalar: float) -> "HyperrealNumber":
|
189
|
+
if isinstance(scalar, (int, float)):
|
190
|
+
return HyperrealNumber([x * scalar for x in self.sequence])
|
191
|
+
return NotImplemented
|
192
|
+
|
193
|
+
def __rmul__(self, scalar: float) -> "HyperrealNumber":
|
194
|
+
return self.__mul__(scalar)
|
195
|
+
|
196
|
+
def __truediv__(self, divisor: float) -> "HyperrealNumber":
|
197
|
+
if isinstance(divisor, (int, float)):
|
198
|
+
if divisor == 0:
|
199
|
+
raise ZeroDivisionError("Scalar division by zero.")
|
200
|
+
return HyperrealNumber([x / divisor for x in self.sequence])
|
201
|
+
raise TypeError("Only scalar division is supported.")
|
202
|
+
|
203
|
+
def __mod__(self, divisor: float) -> List[float]:
|
204
|
+
if isinstance(divisor, (int, float)):
|
205
|
+
return [x % divisor for x in self.sequence]
|
206
|
+
raise TypeError("Modulo only supported with a scalar divisor.")
|
207
|
+
|
208
|
+
def __str__(self) -> str:
|
209
|
+
return f"Hyperreal({self.sequence[:30]}...)"
|
210
|
+
|
211
|
+
@dataclass
|
212
|
+
class BicomplexNumber:
|
213
|
+
"""Represents a bicomplex number z1 + j*z2, where i^2 = j^2 = -1."""
|
214
|
+
z1: complex
|
215
|
+
z2: complex
|
216
|
+
|
217
|
+
def __add__(self, other: Any) -> "BicomplexNumber":
|
218
|
+
if isinstance(other, BicomplexNumber):
|
219
|
+
return BicomplexNumber(self.z1 + other.z1, self.z2 + other.z2)
|
220
|
+
return NotImplemented
|
221
|
+
|
222
|
+
def __sub__(self, other: Any) -> "BicomplexNumber":
|
223
|
+
if isinstance(other, BicomplexNumber):
|
224
|
+
return BicomplexNumber(self.z1 - other.z1, self.z2 - other.z2)
|
225
|
+
return NotImplemented
|
226
|
+
|
227
|
+
def __mul__(self, other: Any) -> "BicomplexNumber":
|
228
|
+
if isinstance(other, BicomplexNumber):
|
229
|
+
return BicomplexNumber(
|
230
|
+
(self.z1 * other.z1) - (self.z2 * other.z2),
|
231
|
+
(self.z1 * other.z2) + (self.z2 * other.z1),
|
232
|
+
)
|
233
|
+
return NotImplemented
|
234
|
+
|
235
|
+
def __truediv__(self, scalar: float) -> "BicomplexNumber":
|
236
|
+
if isinstance(scalar, (int, float)):
|
237
|
+
if scalar == 0:
|
238
|
+
raise ZeroDivisionError("Cannot divide by zero.")
|
239
|
+
return BicomplexNumber(self.z1 / scalar, self.z2 / scalar)
|
240
|
+
raise TypeError("Only scalar division is supported.")
|
241
|
+
|
242
|
+
def __str__(self) -> str:
|
243
|
+
return f"Bicomplex({self.z1}, {self.z2})"
|
244
|
+
|
245
|
+
@dataclass
|
246
|
+
class NeutrosophicBicomplexNumber:
|
247
|
+
"""Represents a simplified neutrosophic-bicomplex number."""
|
248
|
+
real: float
|
249
|
+
imag: float
|
250
|
+
neut_real: float
|
251
|
+
neut_imag: float
|
252
|
+
j_real: float
|
253
|
+
j_imag: float
|
254
|
+
j_neut_real: float
|
255
|
+
j_neut_imag: float
|
256
|
+
|
257
|
+
def __add__(self, other: Any) -> "NeutrosophicBicomplexNumber":
|
258
|
+
if isinstance(other, NeutrosophicBicomplexNumber):
|
259
|
+
return NeutrosophicBicomplexNumber(*(a + b for a, b in zip(self.__dict__.values(), other.__dict__.values())))
|
260
|
+
return NotImplemented
|
261
|
+
|
262
|
+
def __sub__(self, other: Any) -> "NeutrosophicBicomplexNumber":
|
263
|
+
if isinstance(other, NeutrosophicBicomplexNumber):
|
264
|
+
return NeutrosophicBicomplexNumber(*(a - b for a, b in zip(self.__dict__.values(), other.__dict__.values())))
|
265
|
+
return NotImplemented
|
266
|
+
|
267
|
+
def __truediv__(self, scalar: float) -> "NeutrosophicBicomplexNumber":
|
268
|
+
if isinstance(scalar, (int, float)):
|
269
|
+
if scalar == 0:
|
270
|
+
raise ZeroDivisionError("Cannot divide by zero.")
|
271
|
+
return NeutrosophicBicomplexNumber(*(val / scalar for val in self.__dict__.values()))
|
272
|
+
raise TypeError("Only scalar division supported.")
|
273
|
+
|
274
|
+
def __str__(self) -> str:
|
275
|
+
return f"NeutroBicomplex(r={self.real}, i={self.imag}, Ir={self.neut_real}, ...)"
|
276
|
+
|
277
|
+
# ==============================================================================
|
278
|
+
# --- HELPER FUNCTIONS ---
|
279
|
+
# ==============================================================================
|
280
|
+
|
281
|
+
def _get_integer_representation(n_input: Any) -> Optional[int]:
|
282
|
+
"""Extracts the primary integer component from any supported number type."""
|
283
|
+
try:
|
284
|
+
if isinstance(n_input, (int, float, Fraction)):
|
285
|
+
return abs(int(n_input))
|
286
|
+
if isinstance(n_input, complex):
|
287
|
+
return abs(int(n_input.real))
|
288
|
+
if isinstance(n_input, np.quaternion):
|
289
|
+
return abs(int(n_input.w))
|
290
|
+
if isinstance(n_input, NeutrosophicNumber):
|
291
|
+
return abs(int(n_input.a))
|
292
|
+
if isinstance(n_input, NeutrosophicComplexNumber):
|
293
|
+
return abs(int(n_input.real))
|
294
|
+
if isinstance(n_input, HyperrealNumber):
|
295
|
+
return abs(int(n_input.sequence[0])) if n_input.sequence else 0
|
296
|
+
if isinstance(n_input, BicomplexNumber):
|
297
|
+
return abs(int(n_input.z1.real))
|
298
|
+
if isinstance(n_input, NeutrosophicBicomplexNumber):
|
299
|
+
return abs(int(n_input.real))
|
300
|
+
return abs(int(n_input))
|
301
|
+
except (ValueError, TypeError, IndexError):
|
302
|
+
return None
|
303
|
+
|
304
|
+
def is_prime(n_input: Any) -> bool:
|
305
|
+
"""
|
306
|
+
Checks if a given number (or its principal component) is prime
|
307
|
+
using the robust sympy.isprime function.
|
308
|
+
"""
|
309
|
+
# Adım 1: Karmaşık sayı türünden tamsayıyı çıkarma (Bu kısım aynı kalıyor)
|
310
|
+
value_to_check = _get_integer_representation(n_input)
|
311
|
+
|
312
|
+
# Adım 2: Tamsayı geçerli değilse False döndür
|
313
|
+
if value_to_check is None:
|
314
|
+
return False
|
315
|
+
|
316
|
+
# Adım 3: Asallık testini sympy'ye bırak
|
317
|
+
# sympy.isprime, 2'den küçük sayılar (1, 0, negatifler) için zaten False döndürür.
|
318
|
+
return sympy.isprime(value_to_check)
|
319
|
+
|
320
|
+
"""
|
321
|
+
def is_prime(n_input: Any) -> bool:
|
322
|
+
#Checks if a given number (or its principal component) is prime.
|
323
|
+
value_to_check = _get_integer_representation(n_input)
|
324
|
+
if value_to_check is None or value_to_check < 2:
|
325
|
+
return False
|
326
|
+
if value_to_check == 2:
|
327
|
+
return True
|
328
|
+
if value_to_check % 2 == 0:
|
329
|
+
return False
|
330
|
+
for i in range(3, int(math.sqrt(value_to_check)) + 1, 2):
|
331
|
+
if value_to_check % i == 0:
|
332
|
+
return False
|
333
|
+
return True
|
334
|
+
"""
|
335
|
+
|
336
|
+
def _is_divisible(value: Any, divisor: int, kececi_type: int) -> bool:
|
337
|
+
"""Helper to check divisibility for different number types."""
|
338
|
+
try:
|
339
|
+
if kececi_type in [TYPE_POSITIVE_REAL, TYPE_NEGATIVE_REAL]:
|
340
|
+
return value % divisor == 0
|
341
|
+
if kececi_type == TYPE_FLOAT:
|
342
|
+
return math.isclose(value % divisor, 0)
|
343
|
+
if kececi_type == TYPE_RATIONAL:
|
344
|
+
return (value / divisor).denominator == 1
|
345
|
+
if kececi_type == TYPE_COMPLEX:
|
346
|
+
return math.isclose(value.real % divisor, 0) and math.isclose(value.imag % divisor, 0)
|
347
|
+
if kececi_type == TYPE_QUATERNION:
|
348
|
+
return all(math.isclose(c % divisor, 0) for c in [value.w, value.x, value.y, value.z])
|
349
|
+
if kececi_type == TYPE_NEUTROSOPHIC:
|
350
|
+
return math.isclose(value.a % divisor, 0) and math.isclose(value.b % divisor, 0)
|
351
|
+
if kececi_type == TYPE_NEUTROSOPHIC_COMPLEX:
|
352
|
+
return all(math.isclose(c % divisor, 0) for c in [value.real, value.imag, value.indeterminacy])
|
353
|
+
if kececi_type == TYPE_HYPERREAL:
|
354
|
+
return all(math.isclose(x % divisor, 0) for x in value.sequence)
|
355
|
+
if kececi_type == TYPE_BICOMPLEX:
|
356
|
+
return _is_divisible(value.z1, divisor, TYPE_COMPLEX) and _is_divisible(value.z2, divisor, TYPE_COMPLEX)
|
357
|
+
if kececi_type == TYPE_NEUTROSOPHIC_BICOMPLEX:
|
358
|
+
return all(math.isclose(c % divisor, 0) for c in value.__dict__.values())
|
359
|
+
except (TypeError, ValueError):
|
360
|
+
return False
|
361
|
+
return False
|
362
|
+
|
363
|
+
def _parse_complex(s: str) -> complex:
|
364
|
+
"""Parses a string into a complex number. '3' becomes 3+3j."""
|
365
|
+
s_clean = s.strip().lower()
|
366
|
+
try:
|
367
|
+
c = complex(s_clean)
|
368
|
+
if c.imag == 0 and 'j' not in s_clean:
|
369
|
+
return complex(c.real, c.real)
|
370
|
+
return c
|
371
|
+
except ValueError as e:
|
372
|
+
raise ValueError(f"Invalid complex number format: '{s}'") from e
|
373
|
+
|
374
|
+
def _parse_neutrosophic(s: str) -> Tuple[float, float]:
|
375
|
+
"""Parses a neutrosophic string 'a+bI' into a tuple (a, b)."""
|
376
|
+
s = s.strip().replace(" ", "").upper()
|
377
|
+
if not s:
|
378
|
+
return 0.0, 0.0
|
379
|
+
|
380
|
+
if 'I' not in s:
|
381
|
+
return float(s), 0.0
|
382
|
+
|
383
|
+
pattern = re.compile(r"^(?P<a>[+-]?\d+\.?\d*)?(?P<b>[+-]?)I$")
|
384
|
+
match = re.match(r"^(?P<val>[+-]?\d+\.?\d*)$", s)
|
385
|
+
if match: # Just a number
|
386
|
+
return float(match.group('val')), 0.0
|
387
|
+
|
388
|
+
pattern = re.compile(r"^(?P<a>[+-]?\d+\.?\d*)?(?P<b>[+-]?\d*\.?\d*)I$")
|
389
|
+
full_match = pattern.match(s)
|
390
|
+
if not full_match:
|
391
|
+
raise ValueError(f"Invalid neutrosophic format: {s}")
|
392
|
+
|
393
|
+
parts = full_match.groupdict()
|
394
|
+
a_part = parts.get('a') or "0"
|
395
|
+
b_part = parts.get('b')
|
396
|
+
|
397
|
+
if b_part in (None, "", "+"):
|
398
|
+
b_val = 1.0
|
399
|
+
elif b_part == "-":
|
400
|
+
b_val = -1.0
|
401
|
+
else:
|
402
|
+
b_val = float(b_part)
|
403
|
+
|
404
|
+
return float(a_part), b_val
|
405
|
+
|
406
|
+
|
407
|
+
def _parse_hyperreal(s: str) -> Tuple[float, float]:
|
408
|
+
"""Parses 'a+be' string into a tuple (a, b)."""
|
409
|
+
s = s.strip().replace(" ", "").lower()
|
410
|
+
if not s:
|
411
|
+
return 0.0, 0.0
|
412
|
+
if 'e' not in s:
|
413
|
+
return float(s), 0.0
|
414
|
+
|
415
|
+
pattern = re.compile(r"^(?P<a>[+-]?\d+\.?\d*)?(?P<b>[+-]?\d*\.?\d*)e$")
|
416
|
+
match = pattern.match(s)
|
417
|
+
if not match:
|
418
|
+
raise ValueError(f"Invalid hyperreal format: {s}")
|
419
|
+
|
420
|
+
parts = match.groupdict()
|
421
|
+
a_part = parts.get('a') or "0"
|
422
|
+
b_part = parts.get('b')
|
423
|
+
|
424
|
+
if b_part in (None, "", "+"):
|
425
|
+
b_val = 1.0
|
426
|
+
elif b_part == "-":
|
427
|
+
b_val = -1.0
|
428
|
+
else:
|
429
|
+
b_val = float(b_part)
|
430
|
+
|
431
|
+
return float(a_part), b_val
|
432
|
+
|
433
|
+
def _parse_quaternion(s: str) -> np.quaternion:
|
434
|
+
"""Parses user string ('a+bi+cj+dk' or scalar) into a quaternion."""
|
435
|
+
s_clean = s.replace(" ", "").lower()
|
436
|
+
if not s_clean:
|
437
|
+
raise ValueError("Input cannot be empty.")
|
438
|
+
|
439
|
+
try:
|
440
|
+
val = float(s_clean)
|
441
|
+
return np.quaternion(val, val, val, val)
|
442
|
+
except ValueError:
|
443
|
+
pass
|
444
|
+
|
445
|
+
s_temp = re.sub(r'([+-])([ijk])', r'\g<1>1\g<2>', s_clean)
|
446
|
+
if s_temp.startswith(('i', 'j', 'k')):
|
447
|
+
s_temp = '1' + s_temp
|
448
|
+
|
449
|
+
pattern = re.compile(r'([+-]?\d*\.?\d*)([ijk])?')
|
450
|
+
matches = pattern.findall(s_temp)
|
451
|
+
|
452
|
+
parts = {'w': 0.0, 'x': 0.0, 'y': 0.0, 'z': 0.0}
|
453
|
+
for value_str, component in matches:
|
454
|
+
if not value_str:
|
455
|
+
continue
|
456
|
+
value = float(value_str)
|
457
|
+
if component == 'i':
|
458
|
+
parts['x'] += value
|
459
|
+
elif component == 'j':
|
460
|
+
parts['y'] += value
|
461
|
+
elif component == 'k':
|
462
|
+
parts['z'] += value
|
463
|
+
else:
|
464
|
+
parts['w'] += value
|
465
|
+
|
466
|
+
return np.quaternion(parts['w'], parts['x'], parts['y'], parts['z'])
|
467
|
+
|
468
|
+
def get_random_type(num_iterations: int, fixed_start_raw: str = "0", fixed_add_base_scalar: float = 9.0) -> List[Any]:
|
469
|
+
"""Generates Keçeci Numbers for a randomly selected type."""
|
470
|
+
random_type_choice = random.randint(1, 11)
|
471
|
+
type_names_list = [
|
472
|
+
"Positive Real", "Negative Real", "Complex", "Float", "Rational",
|
473
|
+
"Quaternion", "Neutrosophic", "Neutro-Complex", "Hyperreal",
|
474
|
+
"Bicomplex", "Neutro-Bicomplex"
|
475
|
+
]
|
476
|
+
print(f"\nRandomly selected Keçeci Number Type: {random_type_choice} ({type_names_list[random_type_choice-1]})")
|
477
|
+
|
478
|
+
return get_with_params(
|
479
|
+
kececi_type_choice=random_type_choice,
|
480
|
+
iterations=num_iterations,
|
481
|
+
start_value_raw=fixed_start_raw,
|
482
|
+
add_value_base_scalar=fixed_add_base_scalar
|
483
|
+
)
|
484
|
+
|
485
|
+
# ==============================================================================
|
486
|
+
# --- CORE GENERATOR ---
|
487
|
+
# ==============================================================================
|
488
|
+
|
489
|
+
def unified_generator(kececi_type: int, start_input_raw: str, add_input_base_scalar: float, iterations: int) -> List[Any]:
|
490
|
+
"""Core engine to generate Keçeci Number sequences."""
|
491
|
+
current_value = None
|
492
|
+
add_value_typed = None
|
493
|
+
ask_unit = None
|
494
|
+
use_integer_division = False
|
495
|
+
|
496
|
+
try:
|
497
|
+
a_float = float(add_input_base_scalar)
|
498
|
+
|
499
|
+
if kececi_type in [TYPE_POSITIVE_REAL, TYPE_NEGATIVE_REAL]:
|
500
|
+
current_value = int(float(start_input_raw))
|
501
|
+
add_value_typed = int(a_float)
|
502
|
+
ask_unit = 1
|
503
|
+
use_integer_division = True
|
504
|
+
elif kececi_type == TYPE_FLOAT:
|
505
|
+
current_value = float(start_input_raw)
|
506
|
+
add_value_typed = a_float
|
507
|
+
ask_unit = 1.0
|
508
|
+
elif kececi_type == TYPE_RATIONAL:
|
509
|
+
current_value = Fraction(start_input_raw)
|
510
|
+
add_value_typed = Fraction(add_input_base_scalar)
|
511
|
+
ask_unit = Fraction(1)
|
512
|
+
elif kececi_type == TYPE_COMPLEX:
|
513
|
+
current_value = _parse_complex(start_input_raw)
|
514
|
+
add_value_typed = complex(a_float, a_float)
|
515
|
+
ask_unit = 1 + 1j
|
516
|
+
elif kececi_type == TYPE_NEUTROSOPHIC:
|
517
|
+
a, b = _parse_neutrosophic(start_input_raw)
|
518
|
+
current_value = NeutrosophicNumber(a, b)
|
519
|
+
add_value_typed = NeutrosophicNumber(a_float, 0)
|
520
|
+
ask_unit = NeutrosophicNumber(1, 1)
|
521
|
+
elif kececi_type == TYPE_NEUTROSOPHIC_COMPLEX:
|
522
|
+
s_complex = _parse_complex(start_input_raw)
|
523
|
+
current_value = NeutrosophicComplexNumber(s_complex.real, s_complex.imag, 0.0)
|
524
|
+
add_value_typed = NeutrosophicComplexNumber(a_float, 0.0, 0.0)
|
525
|
+
ask_unit = NeutrosophicComplexNumber(1, 1, 1)
|
526
|
+
elif kececi_type == TYPE_HYPERREAL:
|
527
|
+
a, b = _parse_hyperreal(start_input_raw)
|
528
|
+
sequence_list = [a + b / n for n in range(1, 11)]
|
529
|
+
current_value = HyperrealNumber(sequence_list)
|
530
|
+
add_sequence = [a_float] + [0.0] * 9
|
531
|
+
add_value_typed = HyperrealNumber(add_sequence)
|
532
|
+
ask_unit = HyperrealNumber([1.0] * 10)
|
533
|
+
elif kececi_type == TYPE_BICOMPLEX:
|
534
|
+
s_complex = _parse_complex(start_input_raw)
|
535
|
+
a_complex = complex(a_float)
|
536
|
+
current_value = BicomplexNumber(s_complex, s_complex / 2)
|
537
|
+
add_value_typed = BicomplexNumber(a_complex, a_complex / 2)
|
538
|
+
ask_unit = BicomplexNumber(complex(1, 1), complex(0.5, 0.5))
|
539
|
+
elif kececi_type == TYPE_NEUTROSOPHIC_BICOMPLEX:
|
540
|
+
s_complex = _parse_complex(start_input_raw)
|
541
|
+
current_value = NeutrosophicBicomplexNumber(s_complex.real, s_complex.imag, 0, 0, 0, 0, 0, 0)
|
542
|
+
add_value_typed = NeutrosophicBicomplexNumber(a_float, 0, 0, 0, 0, 0, 0, 0)
|
543
|
+
ask_unit = NeutrosophicBicomplexNumber(*([1.0] * 8))
|
544
|
+
elif kececi_type == TYPE_QUATERNION:
|
545
|
+
current_value = _parse_quaternion(start_input_raw)
|
546
|
+
add_value_typed = np.quaternion(a_float, a_float, a_float, a_float)
|
547
|
+
ask_unit = np.quaternion(1, 1, 1, 1)
|
548
|
+
else:
|
549
|
+
raise ValueError(f"Invalid Keçeci Number Type: {kececi_type}")
|
550
|
+
|
551
|
+
except (ValueError, TypeError) as e:
|
552
|
+
print(f"ERROR: Failed to initialize type {kececi_type} with input '{start_input_raw}': {e}")
|
553
|
+
return []
|
554
|
+
|
555
|
+
sequence = [current_value]
|
556
|
+
last_divisor_used = None
|
557
|
+
ask_counter = 0
|
558
|
+
|
559
|
+
for _ in range(iterations):
|
560
|
+
added_value = current_value + add_value_typed
|
561
|
+
sequence.append(added_value)
|
562
|
+
|
563
|
+
result_value = added_value
|
564
|
+
divided_successfully = False
|
565
|
+
|
566
|
+
primary_divisor = 3 if last_divisor_used == 2 or last_divisor_used is None else 2
|
567
|
+
alternative_divisor = 2 if primary_divisor == 3 else 3
|
568
|
+
|
569
|
+
for divisor in [primary_divisor, alternative_divisor]:
|
570
|
+
if _is_divisible(added_value, divisor, kececi_type):
|
571
|
+
result_value = added_value // divisor if use_integer_division else added_value / divisor
|
572
|
+
last_divisor_used = divisor
|
573
|
+
divided_successfully = True
|
574
|
+
break
|
575
|
+
|
576
|
+
if not divided_successfully and is_prime(added_value):
|
577
|
+
modified_value = (added_value + ask_unit) if ask_counter == 0 else (added_value - ask_unit)
|
578
|
+
ask_counter = 1 - ask_counter
|
579
|
+
sequence.append(modified_value)
|
580
|
+
|
581
|
+
result_value = modified_value
|
582
|
+
|
583
|
+
for divisor in [primary_divisor, alternative_divisor]:
|
584
|
+
if _is_divisible(modified_value, divisor, kececi_type):
|
585
|
+
result_value = modified_value // divisor if use_integer_division else modified_value / divisor
|
586
|
+
last_divisor_used = divisor
|
587
|
+
break
|
588
|
+
|
589
|
+
sequence.append(result_value)
|
590
|
+
current_value = result_value
|
591
|
+
|
592
|
+
return sequence
|
593
|
+
|
594
|
+
def print_detailed_report(sequence: List[Any], params: Dict[str, Any]):
|
595
|
+
"""Generates and prints a detailed report of the sequence results."""
|
596
|
+
if not sequence:
|
597
|
+
print("\n--- REPORT ---\nSequence could not be generated.")
|
598
|
+
return
|
599
|
+
|
600
|
+
print("\n\n" + "="*50)
|
601
|
+
print("--- DETAILED SEQUENCE REPORT ---")
|
602
|
+
print("="*50)
|
603
|
+
|
604
|
+
print("\n[Parameters Used]")
|
605
|
+
print(f" - Keçeci Type: {params.get('type_name', 'N/A')} ({params['type_choice']})")
|
606
|
+
print(f" - Start Value: '{params['start_val']}'")
|
607
|
+
print(f" - Increment: {params['add_val']}")
|
608
|
+
print(f" - Keçeci Steps: {params['steps']}")
|
609
|
+
|
610
|
+
print("\n[Sequence Summary]")
|
611
|
+
print(f" - Total Numbers Generated: {len(sequence)}")
|
612
|
+
|
613
|
+
kpn = find_kececi_prime_number(sequence)
|
614
|
+
print(f" - Keçeci Prime Number (KPN): {kpn if kpn is not None else 'Not found'}")
|
615
|
+
|
616
|
+
print("\n[Sequence Preview]")
|
617
|
+
preview_count = min(len(sequence), 30)
|
618
|
+
print(f" --- First {preview_count} Numbers ---")
|
619
|
+
for i in range(preview_count):
|
620
|
+
print(f" {i}: {sequence[i]}")
|
621
|
+
|
622
|
+
if len(sequence) > preview_count:
|
623
|
+
print(f"\n --- Last {preview_count} Numbers ---")
|
624
|
+
for i in range(len(sequence) - preview_count, len(sequence)):
|
625
|
+
print(f" {i}: {sequence[i]}")
|
626
|
+
|
627
|
+
print("\n" + "="*50)
|
628
|
+
|
629
|
+
while True:
|
630
|
+
show_all = input("Do you want to print the full sequence? (y/n): ").lower().strip()
|
631
|
+
if show_all in ['y', 'n']:
|
632
|
+
break
|
633
|
+
|
634
|
+
if show_all == 'y':
|
635
|
+
print("\n--- FULL SEQUENCE ---")
|
636
|
+
for i, num in enumerate(sequence):
|
637
|
+
print(f"{i}: {num}")
|
638
|
+
print("="*50)
|
639
|
+
|
640
|
+
# ==============================================================================
|
641
|
+
# --- HIGH-LEVEL CONTROL FUNCTIONS ---
|
642
|
+
# ==============================================================================
|
643
|
+
|
644
|
+
def get_with_params(kececi_type_choice: int, iterations: int, start_value_raw: str = "0", add_value_base_scalar: float = 9.0) -> List[Any]:
|
645
|
+
"""Generates Keçeci Numbers with specified parameters."""
|
646
|
+
print(f"\n--- Generating Sequence: Type {kececi_type_choice}, Steps {iterations} ---")
|
647
|
+
print(f"Start: '{start_value_raw}', Increment: {add_value_base_scalar}")
|
648
|
+
|
649
|
+
generated_sequence = unified_generator(
|
650
|
+
kececi_type_choice, start_value_raw, add_value_base_scalar, iterations
|
651
|
+
)
|
652
|
+
|
653
|
+
if generated_sequence:
|
654
|
+
print(f"Generated {len(generated_sequence)} numbers. Preview: {generated_sequence[:30]}...")
|
655
|
+
kpn = find_kececi_prime_number(generated_sequence)
|
656
|
+
if kpn is not None:
|
657
|
+
print(f"Keçeci Prime Number for this sequence: {kpn}")
|
658
|
+
else:
|
659
|
+
print("No repeating Keçeci Prime Number found.")
|
660
|
+
else:
|
661
|
+
print("Sequence generation failed.")
|
662
|
+
|
663
|
+
return generated_sequence
|
664
|
+
|
665
|
+
def get_interactive() -> Tuple[List[Any], Dict[str, Any]]:
|
666
|
+
"""Interactively gets parameters from the user to generate a sequence."""
|
667
|
+
print("\n--- Keçeci Number Interactive Generator ---")
|
668
|
+
print(" 1: Positive Real 2: Negative Real 3: Complex")
|
669
|
+
print(" 4: Float 5: Rational 6: Quaternion")
|
670
|
+
print(" 7: Neutrosophic 8: Neutro-Complex 9: Hyperreal")
|
671
|
+
print(" 10: Bicomplex 11: Neutro-Bicomplex")
|
672
|
+
|
673
|
+
while True:
|
674
|
+
try:
|
675
|
+
type_choice = int(input("Select Keçeci Number Type (1-11): "))
|
676
|
+
if 1 <= type_choice <= 11:
|
677
|
+
break
|
678
|
+
print("Invalid type. Please enter a number between 1 and 11.")
|
679
|
+
except ValueError:
|
680
|
+
print("Invalid input. Please enter a number.")
|
681
|
+
|
682
|
+
prompts = {
|
683
|
+
1: "Enter positive integer start (e.g., '10'): ",
|
684
|
+
2: "Enter negative integer start (e.g., '-5'): ",
|
685
|
+
3: "Enter complex start (e.g., '3+4j' or '3' for 3+3j): ",
|
686
|
+
4: "Enter float start (e.g., '3.14'): ",
|
687
|
+
5: "Enter rational start (e.g., '7/2' or '5'): ",
|
688
|
+
6: "Enter quaternion (e.g., '1+2i-3j+k' or '2.5'): ",
|
689
|
+
7: "Enter neutrosophic start (e.g., '5+2I' or '7'): ",
|
690
|
+
8: "Enter complex base for neutro-complex (e.g., '1-2j'): ",
|
691
|
+
9: "Enter hyperreal start (e.g., '5+3e' or '10'): ",
|
692
|
+
10: "Enter complex base for bicomplex (e.g., '2+1j'): ",
|
693
|
+
11: "Enter complex base for neutro-bicomplex (e.g., '1+2j'): "
|
694
|
+
}
|
695
|
+
|
696
|
+
start_prompt = prompts.get(type_choice, "Enter starting value: ")
|
697
|
+
start_input_val_raw = input(start_prompt)
|
698
|
+
add_base_scalar_val = float(input("Enter base scalar increment (e.g., 9.0): "))
|
699
|
+
num_kececi_steps = int(input("Enter number of Keçeci steps (e.g., 15): "))
|
700
|
+
|
701
|
+
sequence = get_with_params(type_choice, num_kececi_steps, start_input_val_raw, add_base_scalar_val)
|
702
|
+
|
703
|
+
params = {
|
704
|
+
"type_choice": type_choice,
|
705
|
+
"start_val": start_input_val_raw,
|
706
|
+
"add_val": add_base_scalar_val,
|
707
|
+
"steps": num_kececi_steps
|
708
|
+
}
|
709
|
+
return sequence, params
|
710
|
+
|
711
|
+
# ==============================================================================
|
712
|
+
# --- ANALYSIS AND PLOTTING ---
|
713
|
+
# ==============================================================================
|
714
|
+
|
715
|
+
def find_period(sequence: List[Any], min_repeats: int = 3) -> Optional[List[Any]]:
|
716
|
+
"""
|
717
|
+
Checks if the end of a sequence has a repeating cycle (period).
|
718
|
+
|
719
|
+
Args:
|
720
|
+
sequence: The list of numbers to check.
|
721
|
+
min_repeats: How many times the cycle must repeat to be considered stable.
|
722
|
+
|
723
|
+
Returns:
|
724
|
+
The repeating cycle as a list if found, otherwise None.
|
725
|
+
"""
|
726
|
+
if len(sequence) < 10: # Çok kısa dizilerde periyot aramak anlamsız
|
727
|
+
return None
|
728
|
+
|
729
|
+
# Olası periyot uzunluklarını dizinin yarısına kadar kontrol et
|
730
|
+
for p_len in range(1, len(sequence) // min_repeats):
|
731
|
+
# Dizinin sonundan potansiyel döngüyü al
|
732
|
+
candidate_cycle = sequence[-p_len:]
|
733
|
+
|
734
|
+
# Döngünün en az `min_repeats` defa tekrar edip etmediğini kontrol et
|
735
|
+
is_periodic = True
|
736
|
+
for i in range(1, min_repeats):
|
737
|
+
start_index = -(i + 1) * p_len
|
738
|
+
end_index = -i * p_len
|
739
|
+
|
740
|
+
# Dizinin o bölümünü al
|
741
|
+
previous_block = sequence[start_index:end_index]
|
742
|
+
|
743
|
+
# Eğer bloklar uyuşmuyorsa, bu periyot değildir
|
744
|
+
if candidate_cycle != previous_block:
|
745
|
+
is_periodic = False
|
746
|
+
break
|
747
|
+
|
748
|
+
# Eğer döngü tüm kontrollerden geçtiyse, periyodu bulduk demektir
|
749
|
+
if is_periodic:
|
750
|
+
return candidate_cycle
|
751
|
+
|
752
|
+
# Hiçbir periyot bulunamadı
|
753
|
+
return None
|
754
|
+
|
755
|
+
def find_kececi_prime_number(kececi_numbers_list: List[Any]) -> Optional[int]:
|
756
|
+
"""Finds the Keçeci Prime Number from a generated sequence."""
|
757
|
+
if not kececi_numbers_list:
|
758
|
+
return None
|
759
|
+
|
760
|
+
integer_prime_reps = [
|
761
|
+
rep for num in kececi_numbers_list
|
762
|
+
if is_prime(num) and (rep := _get_integer_representation(num)) is not None
|
763
|
+
]
|
764
|
+
|
765
|
+
if not integer_prime_reps:
|
766
|
+
return None
|
767
|
+
|
768
|
+
counts = collections.Counter(integer_prime_reps)
|
769
|
+
repeating_primes = [(freq, prime) for prime, freq in counts.items() if freq > 1]
|
770
|
+
if not repeating_primes:
|
771
|
+
return None
|
772
|
+
|
773
|
+
_, best_prime = max(repeating_primes)
|
774
|
+
return best_prime
|
775
|
+
|
776
|
+
def plot_numbers(sequence: List[Any], title: str = "Keçeci Number Sequence Analysis"):
|
777
|
+
"""Plots the generated sequence with detailed visualizations for each type."""
|
778
|
+
plt.style.use('seaborn-v0_8-whitegrid')
|
779
|
+
|
780
|
+
if not sequence:
|
781
|
+
print("Sequence is empty, nothing to plot.")
|
782
|
+
return
|
783
|
+
|
784
|
+
fig = plt.figure(figsize=(16, 9))
|
785
|
+
plt.suptitle(title, fontsize=16, y=0.98)
|
786
|
+
first_elem = sequence[0]
|
787
|
+
|
788
|
+
if isinstance(first_elem, (int, float, Fraction)):
|
789
|
+
ax = fig.add_subplot(1, 1, 1)
|
790
|
+
ax.plot([float(x) for x in sequence], 'o-', label="Value")
|
791
|
+
ax.set_title("Value over Iterations")
|
792
|
+
ax.set_xlabel("Index"), ax.set_ylabel("Value"), ax.legend()
|
793
|
+
|
794
|
+
elif isinstance(first_elem, complex):
|
795
|
+
gs = GridSpec(2, 2, figure=fig)
|
796
|
+
ax1, ax2, ax3 = fig.add_subplot(gs[0, 0]), fig.add_subplot(gs[0, 1]), fig.add_subplot(gs[1, :])
|
797
|
+
real_parts, imag_parts = [c.real for c in sequence], [c.imag for c in sequence]
|
798
|
+
ax1.plot(real_parts, 'o-', label='Real Part'), ax1.set_title("Real Part"), ax1.legend()
|
799
|
+
ax2.plot(imag_parts, 'o-', color='red', label='Imaginary Part'), ax2.set_title("Imaginary Part"), ax2.legend()
|
800
|
+
ax3.plot(real_parts, imag_parts, '.-', label='Trajectory')
|
801
|
+
ax3.scatter(real_parts[0], imag_parts[0], c='g', s=100, label='Start', zorder=5)
|
802
|
+
ax3.scatter(real_parts[-1], imag_parts[-1], c='r', s=100, label='End', zorder=5)
|
803
|
+
ax3.set_title("Trajectory in Complex Plane"), ax3.set_xlabel("Real"), ax3.set_ylabel("Imaginary"), ax3.legend(), ax3.axis('equal')
|
804
|
+
|
805
|
+
elif isinstance(first_elem, np.quaternion):
|
806
|
+
gs = GridSpec(2, 1, figure=fig)
|
807
|
+
ax1 = fig.add_subplot(gs[0, 0])
|
808
|
+
ax2 = fig.add_subplot(gs[1, 0], sharex=ax1)
|
809
|
+
ax1.plot([q.w for q in sequence], 'o-', label='w (scalar)'), ax1.plot([q.x for q in sequence], 's--', label='x')
|
810
|
+
ax1.plot([q.y for q in sequence], '^--', label='y'), ax1.plot([q.z for q in sequence], 'd--', label='z')
|
811
|
+
ax1.set_title("Quaternion Components"), ax1.legend()
|
812
|
+
magnitudes = [abs(q) for q in sequence]
|
813
|
+
ax2.plot(magnitudes, 'o-', color='purple', label='Magnitude'), ax2.set_title("Magnitude"), ax2.legend(), ax2.set_xlabel("Index")
|
814
|
+
|
815
|
+
elif isinstance(first_elem, BicomplexNumber):
|
816
|
+
gs = GridSpec(2, 2, figure=fig)
|
817
|
+
ax1, ax2, ax3, ax4 = fig.add_subplot(gs[0,0]), fig.add_subplot(gs[0,1]), fig.add_subplot(gs[1,0]), fig.add_subplot(gs[1,1])
|
818
|
+
z1r, z1i = [x.z1.real for x in sequence], [x.z1.imag for x in sequence]
|
819
|
+
z2r, z2i = [x.z2.real for x in sequence], [x.z2.imag for x in sequence]
|
820
|
+
ax1.plot(z1r, label='z1.real'), ax1.plot(z1i, label='z1.imag'), ax1.set_title("Component z1"), ax1.legend()
|
821
|
+
ax2.plot(z2r, label='z2.real'), ax2.plot(z2i, label='z2.imag'), ax2.set_title("Component z2"), ax2.legend()
|
822
|
+
ax3.plot(z1r, z1i, '.-'), ax3.set_title("z1 Trajectory"), ax3.set_xlabel("Real"), ax3.set_ylabel("Imaginary")
|
823
|
+
ax4.plot(z2r, z2i, '.-'), ax4.set_title("z2 Trajectory"), ax4.set_xlabel("Real"), ax4.set_ylabel("Imaginary")
|
824
|
+
|
825
|
+
elif isinstance(first_elem, NeutrosophicNumber):
|
826
|
+
gs = GridSpec(1, 2, figure=fig)
|
827
|
+
ax1, ax2 = fig.add_subplot(gs[0, 0]), fig.add_subplot(gs[0, 1])
|
828
|
+
a, b = [x.a for x in sequence], [x.b for x in sequence]
|
829
|
+
ax1.plot(a, label='Determinate (a)'), ax1.plot(b, label='Indeterminate (b)'), ax1.set_title("Components"), ax1.legend()
|
830
|
+
sc = ax2.scatter(a, b, c=range(len(a)), cmap='viridis')
|
831
|
+
ax2.set_title("Trajectory"), ax2.set_xlabel("Determinate"), ax2.set_ylabel("Indeterminate"), fig.colorbar(sc, ax=ax2, label="Iteration")
|
832
|
+
|
833
|
+
elif isinstance(first_elem, NeutrosophicComplexNumber):
|
834
|
+
gs = GridSpec(2, 1, figure=fig)
|
835
|
+
ax1, ax2 = fig.add_subplot(gs[0, 0]), fig.add_subplot(gs[1, 0])
|
836
|
+
r, i, ind = [x.real for x in sequence], [x.imag for x in sequence], [x.indeterminacy for x in sequence]
|
837
|
+
ax1.plot(r, label='Real'), ax1.plot(i, label='Imag'), ax1.plot(ind, label='Indeterminacy', linestyle=':')
|
838
|
+
ax1.set_title("Components"), ax1.legend()
|
839
|
+
sc = ax2.scatter(r, i, c=ind, cmap='magma', s=20)
|
840
|
+
ax2.set_title("Trajectory (colored by Indeterminacy)"), ax2.set_xlabel("Real"), ax2.set_ylabel("Imaginary")
|
841
|
+
fig.colorbar(sc, ax=ax2, label='Indeterminacy'), ax2.axis('equal')
|
842
|
+
|
843
|
+
elif isinstance(first_elem, HyperrealNumber):
|
844
|
+
gs = GridSpec(2, 1, figure=fig)
|
845
|
+
ax1, ax2 = fig.add_subplot(gs[0, 0]), fig.add_subplot(gs[1, 0])
|
846
|
+
num_components = min(len(first_elem.sequence), 4)
|
847
|
+
for i in range(num_components):
|
848
|
+
ax1.plot([h.sequence[i] for h in sequence], label=f'Comp {i}')
|
849
|
+
ax1.set_title("Hyperreal Components"), ax1.legend()
|
850
|
+
comp0, comp1 = [h.sequence[0] for h in sequence], [h.sequence[1] for h in sequence]
|
851
|
+
sc = ax2.scatter(comp0, comp1, c=range(len(comp0)), cmap='plasma')
|
852
|
+
ax2.set_title("Trajectory (C0 vs C1)"), ax2.set_xlabel("C0"), ax2.set_ylabel("C1"), fig.colorbar(sc, ax=ax2, label="Iteration")
|
853
|
+
|
854
|
+
elif isinstance(first_elem, NeutrosophicBicomplexNumber):
|
855
|
+
gs = GridSpec(2, 2, figure=fig)
|
856
|
+
ax1, ax2 = fig.add_subplot(gs[0, 0]), fig.add_subplot(gs[0, 1])
|
857
|
+
ax3, ax4 = fig.add_subplot(gs[1, 0]), fig.add_subplot(gs[1, 1])
|
858
|
+
ax1.plot([n.real for n in sequence], [n.imag for n in sequence], '.-'), ax1.set_title("Primary Deterministic")
|
859
|
+
ax2.plot([n.neut_real for n in sequence], [n.neut_imag for n in sequence], '.-'), ax2.set_title("Primary Neutrosophic")
|
860
|
+
ax3.plot([n.j_real for n in sequence], [n.j_imag for n in sequence], '.-'), ax3.set_title("Secondary Deterministic")
|
861
|
+
ax4.plot([n.j_neut_real for n in sequence], [n.j_neut_imag for n in sequence], '.-'), ax4.set_title("Secondary Neutrosophic")
|
862
|
+
|
863
|
+
else:
|
864
|
+
ax = fig.add_subplot(1, 1, 1)
|
865
|
+
ax.text(0.5, 0.5, f"Plotting for '{type(first_elem).__name__}' not implemented.", ha='center')
|
866
|
+
|
867
|
+
plt.tight_layout(rect=[0, 0, 1, 0.96])
|
868
|
+
|
869
|
+
# ==============================================================================
|
870
|
+
# --- MAIN EXECUTION BLOCK ---
|
871
|
+
# ==============================================================================
|
872
|
+
if __name__ == "__main__":
|
873
|
+
print("="*60)
|
874
|
+
print(" Keçeci Numbers Module - Demonstration")
|
875
|
+
print("="*60)
|
876
|
+
print("This script demonstrates the generation of various Keçeci Number types.")
|
877
|
+
|
878
|
+
# --- Example 1: Interactive Mode ---
|
879
|
+
# Uncomment the following lines to run in interactive mode:
|
880
|
+
# seq, params = get_interactive()
|
881
|
+
# if seq:
|
882
|
+
# plot_numbers(seq, title=f"Keçeci Type {params['type_choice']} Sequence")
|
883
|
+
# plt.show()
|
884
|
+
|
885
|
+
# --- Example 2: Programmatic Generation and Plotting ---
|
886
|
+
print("\nRunning programmatic tests for all 11 number types...")
|
887
|
+
|
888
|
+
STEPS = 30
|
889
|
+
START_VAL = "2.5"
|
890
|
+
ADD_VAL = 3.0
|
891
|
+
|
892
|
+
all_types = {
|
893
|
+
"Positive Real": TYPE_POSITIVE_REAL, "Negative Real": TYPE_NEGATIVE_REAL,
|
894
|
+
"Complex": TYPE_COMPLEX, "Float": TYPE_FLOAT, "Rational": TYPE_RATIONAL,
|
895
|
+
"Quaternion": TYPE_QUATERNION, "Neutrosophic": TYPE_NEUTROSOPHIC,
|
896
|
+
"Neutrosophic Complex": TYPE_NEUTROSOPHIC_COMPLEX, "Hyperreal": TYPE_HYPERREAL,
|
897
|
+
"Bicomplex": TYPE_BICOMPLEX, "Neutrosophic Bicomplex": TYPE_NEUTROSOPHIC_BICOMPLEX
|
898
|
+
}
|
899
|
+
|
900
|
+
types_to_plot = [
|
901
|
+
"Complex", "Quaternion", "Bicomplex", "Neutrosophic Complex", "Hyperreal"
|
902
|
+
]
|
903
|
+
|
904
|
+
for name, type_id in all_types.items():
|
905
|
+
start = "-5" if type_id == TYPE_NEGATIVE_REAL else "2+3j" if type_id in [TYPE_COMPLEX, TYPE_BICOMPLEX] else START_VAL
|
906
|
+
|
907
|
+
seq = get_with_params(type_id, STEPS, start, ADD_VAL)
|
908
|
+
|
909
|
+
if name in types_to_plot and seq:
|
910
|
+
plot_numbers(seq, title=f"Demonstration: {name} Keçeci Numbers")
|
911
|
+
|
912
|
+
print("\n\nDemonstration finished. Plots for selected types are shown.")
|
913
|
+
plt.show()
|