kececinumbers 0.1.4__tar.gz → 0.1.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kececinumbers
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: Keçeci Numbers An Exploration of a Dynamic Sequence Across Diverse Number Sets
5
5
  Home-page: https://github.com/WhiteSymmetry/kececinumbers
6
6
  Author: Mehmet Keçeci
@@ -149,6 +149,41 @@ Enter the number of iterations (positive integer: e.g., 30): 30
149
149
 
150
150
  ![Keçeci Numbers Example](https://github.com/WhiteSymmetry/kececinumbers/blob/main/examples/kn-5.png?raw=true)
151
151
 
152
+ ---
153
+ # Keçeci Prime Number
154
+
155
+ ```python
156
+ import matplotlib.pyplot as plt
157
+ import kececinumbers as kn
158
+
159
+
160
+ print("--- Interactive Test ---")
161
+ seq_interactive = kn.get_interactive()
162
+ if seq_interactive:
163
+ kn.plot_numbers(seq_interactive, "Keçeci Numbers")
164
+
165
+ print("\n--- Random Type Test (60 Keçeci Steps) ---")
166
+ # num_iterations burada Keçeci adımı sayısıdır
167
+ seq_random = kn.get_random_type(num_iterations=60)
168
+ if seq_random:
169
+ kn.plot_numbers(seq_random, "Random Type Keçeci Numbers")
170
+
171
+ print("\n--- Fixed Params Test (Complex, 60 Keçeci Steps) ---")
172
+ seq_fixed = kn.get_with_params(
173
+ kececi_type_choice=kn.TYPE_COMPLEX,
174
+ iterations=60,
175
+ start_value_raw="1+2j",
176
+ add_value_base_scalar=3.0
177
+ )
178
+ if seq_fixed:
179
+ kn.plot_numbers(seq_fixed, "Fixed Params (Complex) Keçeci Numbers")
180
+
181
+ # İsterseniz find_kececi_prime_number'ı ayrıca da çağırabilirsiniz:
182
+ if seq_fixed:
183
+ kpn_direct = kn.find_kececi_prime_number(seq_fixed)
184
+ if kpn_direct is not None:
185
+ print(f"\nDirect call to find_kececi_prime_number for fixed numbers: {kpn_direct}")
186
+ ```
152
187
  ---
153
188
 
154
189
  ## License / Lisans
@@ -116,6 +116,41 @@ Enter the number of iterations (positive integer: e.g., 30): 30
116
116
 
117
117
  ![Keçeci Numbers Example](https://github.com/WhiteSymmetry/kececinumbers/blob/main/examples/kn-5.png?raw=true)
118
118
 
119
+ ---
120
+ # Keçeci Prime Number
121
+
122
+ ```python
123
+ import matplotlib.pyplot as plt
124
+ import kececinumbers as kn
125
+
126
+
127
+ print("--- Interactive Test ---")
128
+ seq_interactive = kn.get_interactive()
129
+ if seq_interactive:
130
+ kn.plot_numbers(seq_interactive, "Keçeci Numbers")
131
+
132
+ print("\n--- Random Type Test (60 Keçeci Steps) ---")
133
+ # num_iterations burada Keçeci adımı sayısıdır
134
+ seq_random = kn.get_random_type(num_iterations=60)
135
+ if seq_random:
136
+ kn.plot_numbers(seq_random, "Random Type Keçeci Numbers")
137
+
138
+ print("\n--- Fixed Params Test (Complex, 60 Keçeci Steps) ---")
139
+ seq_fixed = kn.get_with_params(
140
+ kececi_type_choice=kn.TYPE_COMPLEX,
141
+ iterations=60,
142
+ start_value_raw="1+2j",
143
+ add_value_base_scalar=3.0
144
+ )
145
+ if seq_fixed:
146
+ kn.plot_numbers(seq_fixed, "Fixed Params (Complex) Keçeci Numbers")
147
+
148
+ # İsterseniz find_kececi_prime_number'ı ayrıca da çağırabilirsiniz:
149
+ if seq_fixed:
150
+ kpn_direct = kn.find_kececi_prime_number(seq_fixed)
151
+ if kpn_direct is not None:
152
+ print(f"\nDirect call to find_kececi_prime_number for fixed numbers: {kpn_direct}")
153
+ ```
119
154
  ---
120
155
 
121
156
  ## License / Lisans
@@ -6,6 +6,7 @@ import numpy as np
6
6
  import math
7
7
  from fractions import Fraction
8
8
  import quaternion # pip install numpy numpy-quaternion
9
+ import collections
9
10
 
10
11
 
11
12
  # --- Helper Functions ---
@@ -33,7 +34,13 @@ def is_prime(n_input):
33
34
 
34
35
  if value_to_check < 2:
35
36
  return False
36
- for i in range(2, int(value_to_check**0.5) + 1):
37
+ # Optimize for 2 and even numbers
38
+ if value_to_check == 2:
39
+ return True
40
+ if value_to_check % 2 == 0:
41
+ return False
42
+ # Check only odd divisors up to sqrt(n)
43
+ for i in range(3, int(value_to_check**0.5) + 1, 2):
37
44
  if value_to_check % i == 0:
38
45
  return False
39
46
  return True
@@ -66,35 +73,24 @@ def unified_generator(kececi_type, start_input_raw, add_input_base_scalar, itera
66
73
  ask_unit = 1
67
74
  use_integer_division = True
68
75
  elif kececi_type == 3: # Complex Numbers
69
- # Adım 1: start_input_raw'ı bir complex sayıya dönüştür
70
76
  if isinstance(start_input_raw, complex):
71
- # Zaten bir complex sayı ise, doğrudan kullan
72
77
  start_complex_val = start_input_raw
73
78
  elif isinstance(start_input_raw, (int, float)):
74
- # Eğer int veya float ise, s+sj yap (kullanıcının beklentisi buysa)
75
79
  s_scalar = float(start_input_raw)
76
80
  start_complex_val = complex(s_scalar, s_scalar)
77
- else: # String ise (örn: "1+2j", "3", "3.0")
81
+ else:
78
82
  try:
79
- # Doğrudan complex sayı string'i mi diye dene (örn: "1+2j")
80
83
  start_complex_val = complex(str(start_input_raw))
81
84
  except ValueError:
82
- # Eğer complex() başarısız olduysa, skaler bir sayı string'i olabilir (örn: "3")
83
- # Bu durumda s+sj yapalım
84
85
  try:
85
86
  s_scalar_from_string = float(str(start_input_raw))
86
87
  start_complex_val = complex(s_scalar_from_string, s_scalar_from_string)
87
88
  except ValueError:
88
89
  raise ValueError(f"Cannot convert start_input_raw '{start_input_raw}' to a complex number.")
89
-
90
90
  current_value = start_complex_val
91
-
92
- # Adım 2: add_input_base_scalar'dan _add_value_typed oluştur
93
91
  a_scalar_for_add = float(add_input_base_scalar)
94
92
  _add_value_typed = complex(a_scalar_for_add, a_scalar_for_add) # a+aj
95
-
96
93
  ask_unit = 1 + 1j
97
- # use_integer_division = False (Zaten varsayılan)
98
94
  elif kececi_type == 4: # Floating-Point Numbers
99
95
  current_value = float(start_input_raw)
100
96
  _add_value_typed = float(add_input_base_scalar)
@@ -102,29 +98,33 @@ def unified_generator(kececi_type, start_input_raw, add_input_base_scalar, itera
102
98
  elif kececi_type == 5: # Rational Numbers
103
99
  if isinstance(start_input_raw, Fraction):
104
100
  current_value = start_input_raw
105
- else: # String ("3/2", "5") or number (5 -> 5/1)
101
+ else:
106
102
  current_value = Fraction(str(start_input_raw))
107
- _add_value_typed = Fraction(str(add_input_base_scalar)) # Convert scalar base to Fraction
103
+ _add_value_typed = Fraction(str(add_input_base_scalar))
108
104
  ask_unit = Fraction(1, 1)
109
105
  elif kececi_type == 6: # Quaternions
110
106
  s_val_q_raw = float(start_input_raw) if not isinstance(start_input_raw, np.quaternion) else start_input_raw
111
107
  a_val_q_scalar = float(add_input_base_scalar)
112
108
  if isinstance(s_val_q_raw, np.quaternion):
113
109
  current_value = s_val_q_raw
114
- else: # From scalar, make q(s,s,s,s)
110
+ else:
115
111
  current_value = np.quaternion(s_val_q_raw, s_val_q_raw, s_val_q_raw, s_val_q_raw)
116
112
  _add_value_typed = np.quaternion(a_val_q_scalar, a_val_q_scalar, a_val_q_scalar, a_val_q_scalar)
117
- ask_unit = np.quaternion(1, 1, 1, 1) # Like (1+1i+1j+1k)
113
+ ask_unit = np.quaternion(1, 1, 1, 1)
118
114
  else:
119
115
  raise ValueError("Invalid Keçeci Number Type")
120
116
 
121
117
  sequence.append(current_value)
122
- last_divisor_used = None # Last divisor used (2 or 3)
123
- ask_counter = 0 # 0: first time +unit, 1: second time -unit
118
+ last_divisor_used = None
119
+ ask_counter = 0
124
120
 
125
- for _ in range(iterations):
121
+ actual_iterations_done = 0
122
+ while actual_iterations_done < iterations:
126
123
  added_value = current_value + _add_value_typed
127
124
  sequence.append(added_value)
125
+ actual_iterations_done += 1
126
+ if actual_iterations_done >= iterations: break
127
+
128
128
 
129
129
  value_for_primality_check = added_value
130
130
 
@@ -139,28 +139,35 @@ def unified_generator(kececi_type, start_input_raw, add_input_base_scalar, itera
139
139
  if kececi_type in [1, 2]:
140
140
  can_divide = (added_value % divisor_candidate == 0)
141
141
  elif kececi_type == 3:
142
- can_divide = math.isclose(added_value.real % divisor_candidate, 0)
142
+ can_divide = math.isclose(added_value.real % divisor_candidate, 0) and math.isclose(added_value.imag % divisor_candidate, 0)
143
143
  elif kececi_type == 4:
144
144
  can_divide = math.isclose(added_value % divisor_candidate, 0) or \
145
- math.isclose(added_value % divisor_candidate, divisor_candidate)
145
+ math.isclose(added_value % divisor_candidate, divisor_candidate) # handles floating point precision
146
146
  elif kececi_type == 5:
147
147
  if divisor_candidate != 0:
148
148
  quotient_rational = added_value / divisor_candidate
149
149
  can_divide = (quotient_rational.denominator == 1)
150
150
  elif kececi_type == 6:
151
- can_divide = math.isclose(added_value.w % divisor_candidate, 0)
151
+ # For quaternions, typically division is by scalar. Check if all components are divisible.
152
+ # Or, as per your current `is_prime`, just check the scalar part.
153
+ # Let's stick to the scalar part for consistency with `is_prime` for now.
154
+ can_divide = math.isclose(added_value.w % divisor_candidate, 0) and \
155
+ math.isclose(added_value.x % divisor_candidate, 0) and \
156
+ math.isclose(added_value.y % divisor_candidate, 0) and \
157
+ math.isclose(added_value.z % divisor_candidate, 0)
158
+
152
159
 
153
160
  if can_divide:
154
161
  if use_integer_division:
155
162
  result_value = added_value // divisor_candidate
156
163
  else:
157
- result_value = added_value / divisor_candidate
164
+ result_value = added_value / divisor_candidate # For complex, float, rational, quaternion
158
165
  last_divisor_used = divisor_candidate
159
166
  divided_successfully = True
160
167
  break
161
168
 
162
169
  if not divided_successfully:
163
- if is_prime(value_for_primality_check):
170
+ if is_prime(value_for_primality_check): # is_prime checks the relevant part (e.g., real part)
164
171
  modified_value = None
165
172
  if ask_counter == 0:
166
173
  modified_value = added_value + ask_unit
@@ -169,15 +176,21 @@ def unified_generator(kececi_type, start_input_raw, add_input_base_scalar, itera
169
176
  modified_value = added_value - ask_unit
170
177
  ask_counter = 0
171
178
  sequence.append(modified_value)
172
-
179
+ actual_iterations_done += 1
180
+ if actual_iterations_done >= iterations:
181
+ result_value = modified_value # End with modified value if it's the last step
182
+ break
183
+
184
+
173
185
  current_target_for_division_mod = modified_value
174
186
  divided_after_modification = False
175
- for divisor_candidate_mod in [primary_divisor, alternative_divisor]:
187
+ for divisor_candidate_mod in [primary_divisor, alternative_divisor]: # Re-use primary/alternative logic
176
188
  can_divide_mod = False
177
189
  if kececi_type in [1, 2]:
178
190
  can_divide_mod = (current_target_for_division_mod % divisor_candidate_mod == 0)
179
191
  elif kececi_type == 3:
180
- can_divide_mod = math.isclose(current_target_for_division_mod.real % divisor_candidate_mod, 0)
192
+ can_divide_mod = math.isclose(current_target_for_division_mod.real % divisor_candidate_mod, 0) and \
193
+ math.isclose(current_target_for_division_mod.imag % divisor_candidate_mod, 0)
181
194
  elif kececi_type == 4:
182
195
  can_divide_mod = math.isclose(current_target_for_division_mod % divisor_candidate_mod, 0) or \
183
196
  math.isclose(current_target_for_division_mod % divisor_candidate_mod, divisor_candidate_mod)
@@ -186,25 +199,32 @@ def unified_generator(kececi_type, start_input_raw, add_input_base_scalar, itera
186
199
  quotient_rational_mod = current_target_for_division_mod / divisor_candidate_mod
187
200
  can_divide_mod = (quotient_rational_mod.denominator == 1)
188
201
  elif kececi_type == 6:
189
- can_divide_mod = math.isclose(current_target_for_division_mod.w % divisor_candidate_mod, 0)
202
+ can_divide_mod = math.isclose(current_target_for_division_mod.w % divisor_candidate_mod, 0) and \
203
+ math.isclose(current_target_for_division_mod.x % divisor_candidate_mod, 0) and \
204
+ math.isclose(current_target_for_division_mod.y % divisor_candidate_mod, 0) and \
205
+ math.isclose(current_target_for_division_mod.z % divisor_candidate_mod, 0)
206
+
190
207
 
191
208
  if can_divide_mod:
192
209
  if use_integer_division:
193
210
  result_value = current_target_for_division_mod // divisor_candidate_mod
194
211
  else:
195
212
  result_value = current_target_for_division_mod / divisor_candidate_mod
196
- last_divisor_used = divisor_candidate_mod
213
+ last_divisor_used = divisor_candidate_mod # Update last_divisor_used
197
214
  divided_after_modification = True
198
215
  break
199
216
  if not divided_after_modification:
200
217
  result_value = modified_value
201
- else:
218
+ else: # Not prime and not divisible
202
219
  result_value = added_value
203
220
 
204
221
  sequence.append(result_value)
222
+ actual_iterations_done += 1
223
+ if actual_iterations_done >= iterations: break
205
224
  current_value = result_value
206
225
 
207
- return sequence
226
+ return sequence[:iterations+1] # Ensure correct length, as we add start + iterations*2 steps
227
+
208
228
 
209
229
  # --- Control Mechanisms (Exportable Functions) ---
210
230
  def get_interactive():
@@ -227,8 +247,8 @@ def get_interactive():
227
247
  except ValueError: print("Please enter a numeric value.")
228
248
 
229
249
  start_prompt = "Enter the starting number (e.g., 0 or 2.5, complex:3+4j, rational: 3/4, quaternions: 1) : "
230
- if type_choice == 3: start_prompt += "(e.g., 3+4j or just 3): "
231
- elif type_choice == 5: start_prompt += "(e.g., 7/2 or 5): "
250
+ if type_choice == 3: start_prompt = "Enter starting complex number (e.g., 3+4j or just 3 for 3+3j): "
251
+ elif type_choice == 5: start_prompt = "Enter starting rational (e.g., 7/2 or 5 for 5/1): "
232
252
 
233
253
  start_input_val_raw = input(start_prompt)
234
254
 
@@ -240,12 +260,27 @@ def get_interactive():
240
260
 
241
261
  while True:
242
262
  try:
243
- num_iterations = int(input("Enter the number of iterations (positive integer: e.g., 30): "))
244
- if num_iterations > 0: break
245
- else: print("Number of iterations must be positive.")
263
+ # Iterations'ı Keçeci adımları olarak düşünelim (her adımda 2 sayı eklenir: added_value, result_value)
264
+ num_kececi_steps = int(input("Enter the number of Keçeci steps (positive integer: e.g., 15, generates ~30 numbers): "))
265
+ if num_kececi_steps > 0: break
266
+ else: print("Number of Keçeci steps must be positive.")
246
267
  except ValueError: print("Please enter an integer value.")
247
268
 
248
- return unified_generator(type_choice, start_input_val_raw, add_base_scalar_val, num_iterations)
269
+ generated_sequence = unified_generator(type_choice, start_input_val_raw, add_base_scalar_val, num_kececi_steps)
270
+
271
+ # *** YENİ EKLENEN KISIM BAŞLANGICI ***
272
+ if generated_sequence:
273
+ print(f"\nGenerated Keçeci Sequence (first 20 of {len(generated_sequence)}): {generated_sequence[:20]}...")
274
+ kpn = find_kececi_prime_number(generated_sequence)
275
+ if kpn is not None:
276
+ print(f"Keçeci Prime Number for this sequence: {kpn}")
277
+ else:
278
+ print("No Keçeci Prime Number found for this sequence.")
279
+ else:
280
+ print("No sequence generated.")
281
+ # *** YENİ EKLENEN KISIM SONU ***
282
+
283
+ return generated_sequence # Fonksiyon yine de diziyi döndürmeli
249
284
 
250
285
  def get_with_params(kececi_type_choice, iterations, start_value_raw="0", add_value_base_scalar=9.0, fixed_params=True, random_range_factor=10):
251
286
  """
@@ -257,33 +292,49 @@ def get_with_params(kececi_type_choice, iterations, start_value_raw="0", add_val
257
292
  actual_add_base = add_value_base_scalar
258
293
 
259
294
  if not fixed_params:
260
- # Basic randomization logic, can be expanded
261
- if kececi_type_choice == 1: # Positive
295
+ if kececi_type_choice == 1:
262
296
  actual_start_raw = str(random.randint(0, int(random_range_factor)))
263
297
  actual_add_base = float(random.randint(1, int(random_range_factor*1.5)))
264
- elif kececi_type_choice == 2: # Negative
298
+ elif kececi_type_choice == 2:
265
299
  actual_start_raw = str(random.randint(-int(random_range_factor), 0))
266
300
  actual_add_base = float(random.randint(-int(random_range_factor*1.5), -1))
267
- elif kececi_type_choice == 3: # Complex
268
- actual_start_raw = str(random.uniform(-random_range_factor/2, random_range_factor/2))
301
+ elif kececi_type_choice == 3:
302
+ re_start = random.uniform(-random_range_factor/2, random_range_factor/2)
303
+ im_start = random.uniform(-random_range_factor/2, random_range_factor/2)
304
+ actual_start_raw = f"{re_start}{im_start:+}j" # String formatında complex
269
305
  actual_add_base = random.uniform(1, random_range_factor/2)
270
- elif kececi_type_choice == 4: # Float
306
+ elif kececi_type_choice == 4:
271
307
  actual_start_raw = str(random.uniform(-random_range_factor, random_range_factor))
272
308
  actual_add_base = random.uniform(0.1, random_range_factor/2)
273
- elif kececi_type_choice == 5: # Rational
309
+ elif kececi_type_choice == 5:
274
310
  num = random.randint(-random_range_factor, random_range_factor)
275
311
  den = random.randint(1, int(random_range_factor/2) if random_range_factor/2 >=1 else 1)
276
312
  actual_start_raw = f"{num}/{den}"
277
313
  actual_add_base = float(random.randint(1,random_range_factor))
278
- elif kececi_type_choice == 6: # Quaternion
314
+ elif kececi_type_choice == 6:
315
+ # Quaternion için başlangıç ve ekleme skaler olsun, unified_generator q(s,s,s,s) yapsın
279
316
  actual_start_raw = str(random.uniform(-random_range_factor/2, random_range_factor/2))
280
317
  actual_add_base = random.uniform(1, random_range_factor/2)
281
- else: # Fixed parameters, but adjust for negative type if default add is positive
282
- if kececi_type_choice == 2 and actual_add_base > 0:
283
- actual_add_base = -actual_add_base
318
+ else:
319
+ if kececi_type_choice == 2 and float(actual_add_base) > 0: # add_value_base_scalar float olabilir
320
+ actual_add_base = -abs(float(actual_add_base))
284
321
 
285
322
 
286
- return unified_generator(kececi_type_choice, actual_start_raw, actual_add_base, iterations)
323
+ generated_sequence = unified_generator(kececi_type_choice, actual_start_raw, actual_add_base, iterations)
324
+
325
+ # *** YENİ EKLENEN KISIM BAŞLANGICI ***
326
+ if generated_sequence:
327
+ print(f"\nGenerated Keçeci Sequence (using get_with_params, first 20 of {len(generated_sequence)}): {generated_sequence[:20]}...")
328
+ kpn = find_kececi_prime_number(generated_sequence)
329
+ if kpn is not None:
330
+ print(f"Keçeci Prime Number for this sequence: {kpn}")
331
+ else:
332
+ print("No Keçeci Prime Number found for this sequence.")
333
+ else:
334
+ print("No sequence generated by get_with_params.")
335
+ # *** YENİ EKLENEN KISIM SONU ***
336
+
337
+ return generated_sequence
287
338
 
288
339
 
289
340
  def get_random_type(num_iterations, use_fixed_params_for_selected_type=True,
@@ -293,13 +344,16 @@ def get_random_type(num_iterations, use_fixed_params_for_selected_type=True,
293
344
  """
294
345
  random_type_choice = random.randint(1, 6)
295
346
  type_names_list = ["Positive Integer", "Negative Integer", "Complex", "Float", "Rational", "Quaternion"]
296
- print(f"Randomly selected Keçeci Number Type: {random_type_choice} ({type_names_list[random_type_choice-1]})")
347
+ print(f"\nRandomly selected Keçeci Number Type: {random_type_choice} ({type_names_list[random_type_choice-1]})")
297
348
 
298
- return get_with_params(random_type_choice, num_iterations,
299
- start_value_raw=fixed_start_raw,
300
- add_value_base_scalar=fixed_add_base_scalar,
301
- fixed_params=use_fixed_params_for_selected_type,
302
- random_range_factor=random_factor)
349
+ # get_with_params fonksiyonu zaten KPN'yi yazdıracak, bu yüzden burada tekrar yazdırmaya gerek yok.
350
+ # Sadece get_with_params'ı çağırıyoruz.
351
+ generated_sequence = get_with_params(random_type_choice, num_iterations,
352
+ start_value_raw=fixed_start_raw,
353
+ add_value_base_scalar=fixed_add_base_scalar,
354
+ fixed_params=use_fixed_params_for_selected_type,
355
+ random_range_factor=random_factor)
356
+ return generated_sequence # get_with_params zaten KPN yazdırıyor.
303
357
 
304
358
  # --- Plotting Function (can be called from the notebook) ---
305
359
  def plot_numbers(sequence, title="Keçeci Numbers"):
@@ -310,16 +364,25 @@ def plot_numbers(sequence, title="Keçeci Numbers"):
310
364
 
311
365
  if not sequence:
312
366
  print("Sequence is empty, nothing to plot.")
367
+ plt.title(title + " (Empty Sequence)")
368
+ plt.text(0.5, 0.5, "Empty Sequence", ha='center', va='center', fontsize=16)
369
+ plt.show()
313
370
  return
314
371
 
315
372
  first_elem = sequence[0]
316
373
 
317
374
  if isinstance(first_elem, np.quaternion):
318
- w_parts = [q.w for q in sequence]
319
- # x_parts = [q.x for q in sequence] # Optional
320
- # y_parts = [q.y for q in sequence] # Optional
321
- # z_parts = [q.z for q in sequence] # Optional
322
- vector_norms = [np.sqrt(q.x**2 + q.y**2 + q.z**2) for q in sequence]
375
+ # Filter out non-quaternion if any mixed types (should not happen with unified_generator)
376
+ q_sequence = [q for q in sequence if isinstance(q, np.quaternion)]
377
+ if not q_sequence:
378
+ print("No quaternion data to plot.")
379
+ plt.title(title + " (No Quaternion Data)")
380
+ plt.text(0.5, 0.5, "No Quaternion Data", ha='center', va='center', fontsize=16)
381
+ plt.show()
382
+ return
383
+
384
+ w_parts = [q.w for q in q_sequence]
385
+ vector_norms = [np.sqrt(q.x**2 + q.y**2 + q.z**2) for q in q_sequence]
323
386
 
324
387
  plt.subplot(2, 1, 1)
325
388
  plt.plot(w_parts, marker='o', linestyle='-', label='w (Scalar Part)')
@@ -332,8 +395,16 @@ def plot_numbers(sequence, title="Keçeci Numbers"):
332
395
  plt.xlabel("Index"); plt.ylabel("Value"); plt.grid(True); plt.legend()
333
396
 
334
397
  elif isinstance(first_elem, complex):
335
- real_parts = [n.real for n in sequence]
336
- imag_parts = [n.imag for n in sequence]
398
+ c_sequence = [c for c in sequence if isinstance(c, complex)]
399
+ if not c_sequence:
400
+ print("No complex data to plot.")
401
+ plt.title(title + " (No Complex Data)")
402
+ plt.text(0.5, 0.5, "No Complex Data", ha='center', va='center', fontsize=16)
403
+ plt.show()
404
+ return
405
+
406
+ real_parts = [n.real for n in c_sequence]
407
+ imag_parts = [n.imag for n in c_sequence]
337
408
 
338
409
  plt.subplot(2, 1, 1)
339
410
  plt.plot(real_parts, marker='o', linestyle='-', label='Real Part')
@@ -347,31 +418,113 @@ def plot_numbers(sequence, title="Keçeci Numbers"):
347
418
 
348
419
  plt.figure(figsize=(8,8))
349
420
  plt.plot(real_parts, imag_parts, marker='.', linestyle='-')
350
- if real_parts:
351
- plt.plot(real_parts[0], imag_parts[0], 'go', markersize=8, label='Start')
352
- plt.plot(real_parts[-1], imag_parts[-1], 'ro', markersize=8, label='End')
421
+ if real_parts: # Check if list is not empty
422
+ plt.plot(real_parts[0], imag_parts[0], 'go', markersize=10, label='Start')
423
+ plt.plot(real_parts[-1], imag_parts[-1], 'ro', markersize=10, label='End')
353
424
  plt.title(title + " - Trajectory in Complex Plane"); plt.xlabel("Real Axis")
354
425
  plt.ylabel("Imaginary Axis"); plt.axhline(0, color='black', lw=0.5)
355
426
  plt.axvline(0, color='black', lw=0.5); plt.grid(True); plt.legend(); plt.axis('equal')
356
427
 
357
428
  elif isinstance(first_elem, Fraction):
358
- float_sequence = [float(f) for f in sequence]
429
+ f_sequence = [f for f in sequence if isinstance(f, Fraction)]
430
+ if not f_sequence:
431
+ print("No rational data to plot.")
432
+ plt.title(title + " (No Rational Data)")
433
+ plt.text(0.5, 0.5, "No Rational Data", ha='center', va='center', fontsize=16)
434
+ plt.show()
435
+ return
436
+ float_sequence = [float(f) for f in f_sequence]
359
437
  plt.plot(float_sequence, marker='o', linestyle='-')
360
438
  plt.title(title + " (Rational Numbers - plotted as float)")
361
439
  plt.xlabel("Index"); plt.ylabel("Value (float)"); plt.grid(True)
362
440
 
363
- else:
441
+ else: # Integers, Floats, or mixed (if any error in generation)
364
442
  try:
365
- numeric_sequence = np.array(sequence, dtype=float)
443
+ # Attempt to convert all to float for plotting
444
+ numeric_sequence = [float(x) for x in sequence if isinstance(x, (int, float, np.number))]
445
+ if not numeric_sequence: # If all were non-numeric after filtering
446
+ raise ValueError("No numeric data to plot after filtering.")
366
447
  plt.plot(numeric_sequence, marker='o', linestyle='-')
367
- except ValueError:
368
- print("Sequence contains non-plottable values. Plotting only numeric ones.")
369
- plt.plot([x for x in sequence if isinstance(x, (int, float))], marker='o', linestyle='-')
448
+ except (ValueError, TypeError):
449
+ print(f"Warning: Sequence for '{title}' contains non-standard numeric or mixed types. Attempting basic plot.")
450
+ # Fallback for truly mixed or unplottable types: plot what you can as numbers
451
+ plottable_part = []
452
+ for x in sequence:
453
+ try: plottable_part.append(float(x))
454
+ except: pass # Ignore non-convertible
455
+ if plottable_part:
456
+ plt.plot(plottable_part, marker='o', linestyle='-')
457
+ else:
458
+ print("Could not plot any part of the sequence.")
459
+ plt.title(title + " (Non-Numeric or Unplottable Data)")
460
+ plt.text(0.5, 0.5, "Non-Numeric or Unplottable Data", ha='center', va='center', fontsize=16)
461
+
370
462
  plt.title(title); plt.xlabel("Index")
371
463
  plt.ylabel("Value"); plt.grid(True)
372
464
 
373
465
  plt.tight_layout()
374
- plt.show()
466
+ # plt.show() # Genellikle notebook'ta %matplotlib inline ile otomatik gösterilir.
467
+ # .py script'te bu satırın yorumunu kaldırmak gerekebilir.
468
+
469
+ def find_kececi_prime_number(kececi_numbers_list):
470
+ """
471
+ Verilen Keçeci sayıları listesinden Keçeci Asal Sayısını bulur.
472
+ Keçeci Asal Sayısı, listede en sık tekrarlayan (veya reel/skaler kısmı asal olan) sayının
473
+ asal tamsayı temsilcisinin en sık tekrarlayanıdır.
474
+ Eğer frekanslar eşitse, daha büyük olan asal tamsayı temsilcisi tercih edilir.
475
+ """
476
+ if not kececi_numbers_list:
477
+ # Modül içinde çağrıldığı için print yerine None dönmesi daha sessiz olur.
478
+ return None
479
+
480
+ integer_prime_representations = []
481
+ for num_original in kececi_numbers_list:
482
+ if is_prime(num_original):
483
+ value_checked = 0
484
+ if isinstance(num_original, (int, float)):
485
+ value_checked = abs(int(num_original))
486
+ elif isinstance(num_original, Fraction):
487
+ value_checked = abs(int(num_original))
488
+ elif isinstance(num_original, complex):
489
+ value_checked = abs(int(num_original.real))
490
+ elif isinstance(num_original, np.quaternion):
491
+ value_checked = abs(int(num_original.w))
492
+ else:
493
+ try:
494
+ value_checked = abs(int(num_original))
495
+ except (ValueError, TypeError):
496
+ continue
497
+ integer_prime_representations.append(value_checked)
498
+
499
+ if not integer_prime_representations:
500
+ return None
501
+
502
+ counts = collections.Counter(integer_prime_representations)
503
+ repeating_primes_info = []
504
+ for prime_int_val, freq in counts.items():
505
+ if freq > 1: # Sadece tekrarlayan asallar
506
+ repeating_primes_info.append((freq, prime_int_val))
507
+
508
+ if not repeating_primes_info:
509
+ return None
510
+
511
+ # En yüksek frekansa sahip olanı bul. Frekanslar eşitse,
512
+ # max() ikinci elemanı (prime_int_val) kullanarak büyük olanı seçer.
513
+ # (frekans, sayı) tuple'ları karşılaştırılır.
514
+ try:
515
+ best_freq, kececi_prime_integer = max(repeating_primes_info)
516
+ except ValueError: # repeating_primes_info boşsa (yukarıdaki if ile yakalanmalı ama ekstra güvence)
517
+ return None
518
+
519
+ return kececi_prime_integer
520
+
521
+ # Constants for Keçeci Types (makes it easier to use from outside)
522
+ TYPE_POSITIVE_REAL = 1
523
+ TYPE_NEGATIVE_REAL = 2
524
+ TYPE_COMPLEX = 3
525
+ TYPE_FLOAT = 4
526
+ TYPE_RATIONAL = 5
527
+ TYPE_QUATERNION = 6
375
528
 
376
529
  # --- DEFINITIONS (as a multiline string, can be accessed as kececinumbers.DEFINITIONS) ---
377
530
  DEFINITIONS = """
@@ -380,13 +533,13 @@ Keçeci NumberS UNIFIED DEFINITION
380
533
  A Keçeci Number sequence is derived from a `start_input_raw` and an `add_input_base_scalar`.
381
534
  These inputs are interpreted according to the selected Keçeci Number Type to become the `current_value` and a type-specific `_add_value_typed`.
382
535
 
383
- In each step:
536
+ In each "Keçeci step" (which typically adds 2 or 3 numbers to the sequence):
384
537
  1. `added_value = current_value + _add_value_typed`.
385
538
  2. `added_value` is recorded in the sequence.
386
539
  3. A `result_value` is obtained by applying the Division Rule and, if necessary, the ASK Rule to `added_value`.
387
540
  4. `result_value` is recorded in the sequence.
388
541
  5. `current_value = result_value`.
389
- This process is repeated for the specified `number_of_iterations`.
542
+ This process is repeated for the specified `number_of_iterations` (Keçeci steps).
390
543
 
391
544
  Division Rule:
392
545
  * A `last_divisor_used` (2 or 3) is tracked.
@@ -394,6 +547,7 @@ Division Rule:
394
547
  * `alternative_divisor`: The other of `primary_divisor` (2 or 3).
395
548
  * `value_to_check_division`: This is `added_value` (or `modified_value` after ASK).
396
549
  * The part of this value used for divisibility depends on the number type (e.g., real/scalar part for complex/quaternion, the fraction itself for rational).
550
+ * For Complex/Quaternion, all components should be divisible by the integer divisor for perfect division.
397
551
  * First, division by `primary_divisor` is attempted:
398
552
  * If `value_to_check_division` (or its relevant part) is "perfectly divisible" by `primary_divisor` (in a type-specific sense, e.g., for rationals, the result is an integer),
399
553
  then `result_value = value_to_check_division / primary_divisor`. `last_divisor_used = primary_divisor`.
@@ -402,7 +556,7 @@ Division Rule:
402
556
  then `result_value = value_to_check_division / alternative_divisor`. `last_divisor_used = alternative_divisor`.
403
557
 
404
558
  Primality and ASK (Augment/Shrink then Check) Rule (if Division Fails):
405
- * `value_for_primality_check`: The part/representation of `added_value` used for primality testing (e.g., integer part, real part).
559
+ * `value_for_primality_check`: The part/representation of `added_value` used for primality testing (e.g., integer part of real, real part of complex).
406
560
  * If `is_prime(value_for_primality_check)` is true:
407
561
  * An `ask_counter` (0 or 1) is used.
408
562
  * `ask_unit`: A type-specific unit value (e.g., 1 for real, 1+1j for complex, Fraction(1,1) for rational, quaternion(1,1,1,1) for quaternion).
@@ -426,7 +580,7 @@ Number Types and Specifics:
426
580
  * ASK unit: `1`. Primality: `abs(int(number))`.
427
581
  3. Complex Numbers (`complex`):
428
582
  * Start/Increment: Complex numbers. Scalar input `s` is interpreted as `s+sj` for start, and scalar `a` as `a+aj` for increment.
429
- * Division: Complex division (`/`). Perfect divisibility: Real part is `math.isclose(real_part % integer_divisor, 0)`.
583
+ * Division: Complex division (`/`). Perfect divisibility: Both real and imaginary parts are `math.isclose(part % integer_divisor, 0)`.
430
584
  * ASK unit: `1+1j`. Primality: `abs(int(number.real))`.
431
585
  4. Floating-Point Numbers (Treated as Float):
432
586
  * Start/Increment: Decimal numbers.
@@ -438,20 +592,11 @@ Number Types and Specifics:
438
592
  * ASK unit: `Fraction(1,1)`. Primality: `abs(int(fraction))`.
439
593
  6. Quaternions (`numpy.quaternion`):
440
594
  * Start/Increment: Quaternions. Scalar input `s` is interpreted as `q(s,s,s,s)` for start, and scalar `a` as `q(a,a,a,a)` for increment.
441
- * Division: Quaternion division (`/`). Perfect divisibility: Scalar (w) part is `math.isclose(w_part % integer_divisor, 0)`.
595
+ * Division: Quaternion division (`/`). Perfect divisibility: All w,x,y,z parts are `math.isclose(part % integer_divisor, 0)`.
442
596
  * ASK unit: `quaternion(1,1,1,1)`. Primality: `abs(int(number.w))`.
443
597
  """
444
598
 
445
- # Constants for Kececi Types (makes it easier to use from outside)
446
- TYPE_POSITIVE_REAL = 1
447
- TYPE_NEGATIVE_REAL = 2
448
- TYPE_COMPLEX = 3
449
- TYPE_FLOAT = 4
450
- TYPE_RATIONAL = 5
451
- TYPE_QUATERNION = 6
452
599
 
453
- # You can remove the __main__ block if this is purely a module
454
- # or keep it for testing the module directly.
455
600
  if __name__ == "__main__":
456
601
  print("Keçeci Numbers Module Loaded.")
457
602
  print("This module provides functions to generate and plot Keçeci Numbers.")
@@ -461,15 +606,23 @@ if __name__ == "__main__":
461
606
  print("- kn.get_with_params(kececi_type, iterations, ...)")
462
607
  print("- kn.get_random_type(iterations, ...)")
463
608
  print("- kn.plot_numbers(sequence, title)")
609
+ print("- kn.find_kececi_prime_number(sequence)") # Explicitly list it
464
610
  print("- kn.unified_generator(...) (low-level)")
465
- print("\nAccess definitions with: kn.DEFINITIONS")
611
+ print("\nAccess definitions by printing kn.DEFINITIONS") # Changed to instruction
466
612
  print("\nAccess type constants like: kn.TYPE_COMPLEX")
467
613
 
468
- # Basic test
469
- print("\nRunning a quick test for Complex numbers (fixed params):")
470
- test_seq = get_with_params(TYPE_COMPLEX, 10, start_value_raw="1", add_value_base_scalar=2.0, fixed_params=True)
471
- if test_seq:
472
- for i, val in enumerate(test_seq[:5]):
473
- if isinstance(val, complex): print(f" {i}: {val.real:.1f}{val.imag:+.1f}j")
474
- else: print(f" {i}: {val}")
475
- # plot_numbers(test_seq, "Module Test - Complex") # Uncomment to plot if running directly
614
+ print("\nRunning a quick test for Complex numbers (fixed params, 5 Keçeci steps):")
615
+ # `iterations` in get_with_params is number of Keçeci steps
616
+ test_seq = get_with_params(TYPE_COMPLEX, 5, start_value_raw="1+1j", add_value_base_scalar=2.0, fixed_params=True)
617
+ # KPN will be printed by get_with_params
618
+
619
+ # Example of calling find_kececi_prime_number directly if needed
620
+ # if test_seq:
621
+ # kpn_direct = find_kececi_prime_number(test_seq)
622
+ # if kpn_direct is not None:
623
+ # print(f"Direct call to find_kececi_prime_number result: {kpn_direct}")
624
+ # else:
625
+ # print("Direct call: No Keçeci Prime Number found.")
626
+
627
+ # print("\nRunning a quick test for Negative Integers (10 Keçeci steps):")
628
+ # test_seq_neg = get_random_type(num_iterations=10) # KPN will be printed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kececinumbers
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: Keçeci Numbers An Exploration of a Dynamic Sequence Across Diverse Number Sets
5
5
  Home-page: https://github.com/WhiteSymmetry/kececinumbers
6
6
  Author: Mehmet Keçeci
@@ -149,6 +149,41 @@ Enter the number of iterations (positive integer: e.g., 30): 30
149
149
 
150
150
  ![Keçeci Numbers Example](https://github.com/WhiteSymmetry/kececinumbers/blob/main/examples/kn-5.png?raw=true)
151
151
 
152
+ ---
153
+ # Keçeci Prime Number
154
+
155
+ ```python
156
+ import matplotlib.pyplot as plt
157
+ import kececinumbers as kn
158
+
159
+
160
+ print("--- Interactive Test ---")
161
+ seq_interactive = kn.get_interactive()
162
+ if seq_interactive:
163
+ kn.plot_numbers(seq_interactive, "Keçeci Numbers")
164
+
165
+ print("\n--- Random Type Test (60 Keçeci Steps) ---")
166
+ # num_iterations burada Keçeci adımı sayısıdır
167
+ seq_random = kn.get_random_type(num_iterations=60)
168
+ if seq_random:
169
+ kn.plot_numbers(seq_random, "Random Type Keçeci Numbers")
170
+
171
+ print("\n--- Fixed Params Test (Complex, 60 Keçeci Steps) ---")
172
+ seq_fixed = kn.get_with_params(
173
+ kececi_type_choice=kn.TYPE_COMPLEX,
174
+ iterations=60,
175
+ start_value_raw="1+2j",
176
+ add_value_base_scalar=3.0
177
+ )
178
+ if seq_fixed:
179
+ kn.plot_numbers(seq_fixed, "Fixed Params (Complex) Keçeci Numbers")
180
+
181
+ # İsterseniz find_kececi_prime_number'ı ayrıca da çağırabilirsiniz:
182
+ if seq_fixed:
183
+ kpn_direct = kn.find_kececi_prime_number(seq_fixed)
184
+ if kpn_direct is not None:
185
+ print(f"\nDirect call to find_kececi_prime_number for fixed numbers: {kpn_direct}")
186
+ ```
152
187
  ---
153
188
 
154
189
  ## License / Lisans
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name="kececinumbers",
6
- version="0.1.4",
6
+ version="0.1.5",
7
7
  description="Keçeci Numbers An Exploration of a Dynamic Sequence Across Diverse Number Sets",
8
8
  long_description=open("README.md").read(),
9
9
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes