Source code for kececinumbers.kececinumbers

# -*- coding: utf-8 -*-
"""
Keçeci Numbers Module (kececinumbers.py)

This module provides a comprehensive framework for generating, analyzing, and
visualizing Keçeci Numbers across various number systems. It supports 23
distinct types, from standard integers and complex numbers to more exotic
constructs like neutrosophic and bicomplex numbers.

The core of the module is the `unified_generator`, which implements the
specific algorithm for generating Keçeci Number sequences. High-level functions
are available for easy interaction, parameter-based generation, and plotting.

Key Features:
- Generation of 23 types of Keçeci Numbers.
- A robust, unified algorithm for all number types.
- Helper functions for mathematical properties like primality and divisibility.
- Advanced plotting capabilities tailored to each number system.
- Functions for interactive use or programmatic integration.

ASK: Augment/Shrink then Check

Türkçe
Keçeci Sayıları Nedir?

Keçeci Sayıları, bir başlangıç değerinden özyineli (rekürsif) bir kuralla üretilen sayı dizileridir. Her adımda şu süreç izlenir:

    Ekle ve Kaydet: Geçerli değere sabit bir artış değeri eklenir ve bu yeni "eklenmiş değer" diziye kaydedilir.
    Bölmeyi Dene: "Eklenmiş değer", bir önceki adımda kullanılmayan sayıya (2 veya 3) bölünmeye çalışılır. Bölme başarılı olursa, sonuç bir sonraki eleman olur.
    ASK (Artır/Azalt ve Kontrol Et) Kuralı: Eğer sayı bölünemiyor ve ana bileşeni asal ise, türe özgü bir birim değer eklenir veya çıkarılır. Elde edilen bu "değiştirilmiş değer" kaydedilir ve bölme işlemi yeniden denenir.
    Aktar: Bölme yine başarısız olursa veya sayı asal değilse, mevcut değer (eklenmiş veya değiştirilmiş değer) doğrudan dizinin bir sonraki elemanı olur.

Bu esnek mekanizma, 23 farklı sayı türünde (Pozitif Reel'den Hiperkomplekse, Nötrosofik'ten Ternary'ye kadar) başarıyla test edilmiş olup, sayı dizilerinin çeşitli cebirsel sistemlerdeki davranışını incelemek için zengin ve evrensel bir çerçeve sunar.

Son Genişlemeler ve Ulaşılan Olgular:

Tüm bu türlerde, diziler içinde "Keçeci Asal Sayıları (KPN)" olarak adlandırılan, tekrar eden ve asal olan özel sayılar keşfedilmiştir. Bu KPN'lerin dizilerdeki ardışık konumları arasındaki maksimum boşluklar analiz edildiğinde, boşluk oranının (Cramér'in (log N)² sınırına göre) tüm türlerde 1'in oldukça altında kaldığı ampirik olarak doğrulanmıştır. Bu bulgu, "Keçeci-Cramér Konjektürü"nün sadece klasik sayılarda değil, standart olmayan sayı kümelerinde de geçerli olduğunu göstermekte ve asal-benzeri sayıların dağılımına dair yeni bir bakış açısı kazandırmaktadır.

English
What are Keçeci Numbers?

Keçeci Numbers are sequences generated from a starting value using a recursive rule. The process for each step is:

    Add & Record: A fixed increment value is added to the current value, and this new "added value" is recorded in the sequence.
    Attempt Division: An attempt is made to divide the "added value" by either 2 or 3 (whichever was not used in the previous step). If successful, the result becomes the next element.
    ASK (Augment/Shrink then Check) Rule: If the number is indivisible and its principal component is prime, a type‑specific unit value is either added (augment) or subtracted (shrink). This "modified value" is recorded, and the division is re‑attempted.
    Carry Over: If division fails again, or if the number is not prime, the current value (either the "added value" or the "modified value") becomes the next element in the sequence.

This flexible mechanism has been successfully tested across 23 distinct number types—ranging from Positive Real to Hypercomplex, and including Neutrosophic, Ternary, and Quaternionic algebras—providing a rich and universal framework for studying the behavior of numerical sequences in various algebraic systems.

Recent Extensions and Established Facts:

Within all of these types, special repeating prime numbers called "Keçeci Prime Numbers (KPN)" have been identified. Analysis of the maximum gaps between consecutive KPN positions in the sequences has empirically confirmed that the gap ratio (normalized by Cramér's (log N)² bound) remains well below 1 for every tested type. This finding demonstrates that the "Keçeci–Cramér Conjecture" holds not only for classical integers but also across non‑standard number systems, offering a new perspective on the distribution of prime‑like numbers.


Keçeci Conjecture: Keçeci Varsayımı, Keçeci-Vermutung, Conjecture de Keçeci, Гипотеза Кечеджи, 凯杰西猜想, ケジェジ予想, Keçeci Huds, Keçeci Hudsiye, Keçeci Hudsia, [...]

Keçeci Varsayımı (Keçeci Conjecture) - Önerilen

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ı[...]

Henüz kanıtlanmamıştır ve bu modül bu varsayımı test etmek için bir çerçeve sunar.

*   0.9.7-0.9.9: Keçeci Numbers Sapce (KNS: Keçeci Sayıları Uzayı, KSU):

Keçeci Sayıları 0.9.7 sürümünde, artık seri üretimi için **ilk bölen** (`first_divisor`) ve **ASK sırası** (`ask_plus_first`) parametreleri doğrudan kullanılabilmektedir. Böylece farklı bölen sayıları (3,2,5,...) ve ASK önceliği (+1 önce / -1 önce) ile aynı başlangıç ve artım değerlerine sahip seriler kolayca karşılaştırılabilir. `get_with_params` fonksiyonu da bu yeni parametreleri destekleyecek şekilde güncellenmiştir.

In version 0.9.7 of Keçeci Numbers, the sequence generation now supports **first divisor** (`first_divisor`) and **ASK order** (`ask_plus_first`) parameters directly. This allows easy comparison of sequences with the same start and increment but different divisors (3,2,5,...) and ASK priorities (+1 first / -1 first). The `get_with_params` function has been updated to accept these new parameters.

*   1.0.2: quantum random
*   0.9.5: 23 Numbers
*   0.8.2: 22 Numbers
*   0.7.9: 20 Numbers
*   0.7.8: 16 Numbers
*   0.6.7: 11 Numbers

"""

# --- Standard Library Imports ---
from __future__ import annotations

import cmath
import logging
import math

# from numbers import Real
import random
import re
import time
import warnings
from abc import ABC
from collections import Counter
from dataclasses import dataclass, field
from decimal import Decimal
from fractions import Fraction
from numbers import Number
from typing import (
    TYPE_CHECKING,
    Any,
    Callable,
    Dict,
    Iterable,
    List,
    Optional,
    Tuple,
    TypeVar,
    Union,
)

import matplotlib.pyplot as plt
import numpy as np
import requests
import sympy
from matplotlib.gridspec import GridSpec
from PIL import Image, ImageDraw  # pip install pillow
from scipy.fft import fft, fftfreq
from scipy.signal import find_peaks
from scipy.stats import ks_2samp
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sympy import isprime

# Module logger — library code should not configure logging handlers.
logger = logging.getLogger(__name__)

# Optional sklearn import for PCA; if not available, PCA disabled gracefully
try:
    from sklearn.decomposition import PCA

    _HAS_SKLEARN = True
except Exception:
    PCA = None
    _HAS_SKLEARN = False

"""
try:
    # numpy-quaternion kütüphanesinin sınıfını yüklemeye çalış. Artık bu modüle ihtiyaç kalmadı
    # conda install -c conda-forge quaternion # pip install numpy-quaternion
    from quaternion import quaternion as quaternion  # type: ignore
except Exception:
    # Eğer yoksa `quaternion` isimli sembolü None yap, kodun diğer yerleri bunu kontrol edebilir
    quaternion = None
    logger.warning("numpy-quaternion paketine ulaşılamadı — quaternion tip desteği devre dışı bırakıldı.")
"""

# Better type definition
Numeric = Union[int, float, complex]
Number = Union[int, float, complex]
_T = TypeVar("_T", bound="BaseNumber")

# ==============================================================================
# --- MODULE CONSTANTS: Keçeci NUMBER TYPES ---
# ==============================================================================
TYPE_POSITIVE_REAL = 1
TYPE_NEGATIVE_REAL = 2
TYPE_COMPLEX = 3
TYPE_FLOAT = 4
TYPE_RATIONAL = 5
TYPE_QUATERNION = 6
TYPE_NEUTROSOPHIC = 7
TYPE_NEUTROSOPHIC_COMPLEX = 8
TYPE_HYPERREAL = 9
TYPE_BICOMPLEX = 10
TYPE_NEUTROSOPHIC_BICOMPLEX = 11
TYPE_OCTONION = 12
TYPE_SEDENION = 13
TYPE_CLIFFORD = 14
TYPE_DUAL = 15
TYPE_SPLIT_COMPLEX = 16
TYPE_PATHION = 17
TYPE_CHINGON = 18
TYPE_ROUTON = 19
TYPE_VOUDON = 20
TYPE_SUPERREAL = 21
TYPE_TERNARY = 22
TYPE_HYPERCOMPLEX = 23

TYPE_NAMES = {
    1: "Positive Real",
    2: "Negative Real",
    3: "Complex",
    4: "Float",
    5: "Rational",
    6: "Quaternion",
    7: "Neutrosophic",
    8: "Neutrosophic Complex",
    9: "Hyperreal",
    10: "Bicomplex",
    11: "Neutrosophic Bicomplex",
    12: "Octonion",
    13: "Sedenion",
    14: "Clifford",
    15: "Dual",
    16: "Split Complex",
    17: "Pathion",
    18: "Chingon",
    19: "Routon",
    20: "Voudon",
    21: "Super Real",
    22: "Ternary",
    23: "Hypercomplex",
}
"""
TYPE_NAMES = {
    1: 'POSITIVE_REAL', 2: 'NEGATIVE_REAL', 3: 'COMPLEX', 4: 'FLOAT', 5: 'RATIONAL',
    6: 'QUATERNION', 7: 'NEUTROSOPHIC', 8: 'NEUTROSOPHIC_COMPLEX', 9: 'HYPERREAL',
    10: 'BICOMPLEX', 11: 'NEUTROSOPHIC_BICOMPLEX', 12: 'OCTONION', 13: 'SEDENION',
    14: 'CLIFFORD', 15: 'DUAL', 16: 'SPLIT_COMPLEX', 17: 'PATHION', 18: 'CHINGON',
    19: 'ROUTON', 20: 'VOUDON', 21: 'SUPERREAL', 22: 'TERNARY', 23: 'HYPERCOMPLEX'
}
"""

# ==================== VARSAYILAN PARAMETRELER ====================
default_starts = {
    1: "0",
    2: "-5.0",
    3: "1+1j",
    4: "3.14",
    5: "7/8",  # 3.5:
    6: "1.0,0.0,0.0,0.0",
    7: "0.6,0.2,0.1",
    8: "1+1j",
    9: "9.64",  # 1.0
    10: "1.34,2.55,0.25,4.61",
    11: "2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    12: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    13: "1.0" + ",0.0" * 15,
    14: "1.0+2.0e1+3.0e12",
    15: "1.0,0.1",
    16: "1.0,0.5",
    17: "1.0" + ",0.0" * 31,
    18: "1.0" + ",0.0" * 63,
    19: "1.0" + ",0.0" * 127,
    20: "1.0" + ",0.0" * 255,
    21: "2",  # "12.85,0.08",
    22: "11",
    23: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
}
default_adds = {
    1: "9",
    2: "-0.5",
    3: "0.1+0.1j",
    4: "0.1",
    5: "4/5",  # 0.1
    6: "0.1,0.0,0.0,0.0",
    7: "0.1,0.0,0.0",
    8: "0.1+0.1j",
    9: "0.57",  # 2.0
    10: "0.08,0.0,0.0,0.0",
    11: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    12: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    13: "0.1" + ",0.0" * 15,
    14: "0.1+0.2e1",
    15: "0.1,0.0",
    16: "0.1,0.0",
    17: "1.0" + ",0.0" * 31,
    18: "1.0" + ",0.0" * 63,
    19: "1.0" + ",0.0" * 127,
    20: "1.0" + ",0.0" * 255,
    21: "2",  # "0.56,1.7",
    22: "22",
    23: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
}
"""
default_starts = {
    1: "0", 2: "-5.0", 3: "1+1j", 4: "2.5", 5: "3.5", # 1: "2.5"
    6: "1.0,0.0,0.0,0.0", 7: "0.6,0.2,0.1", 8: "1+1j",
    9: "1.0", 10: "1.34,2.55,0.25,4.61",
    11: "2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    12: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    13: "1.0" + ",0.0" * 15,
    14: "1.0+2.0e1+3.0e12",
    15: "1.0,0.1", 16: "1.0,0.5",
    17: "1.0" + ",0.0" * 31, 18: "1.0" + ",0.0" * 63,
    19: "1.0" + ",0.0" * 127, 20: "1.0" + ",0.0" * 255,
    21: "12.85,0.08", 22: "11", 23: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
}

default_adds = {
    1: "9", 2: "-3", 3: "0.1+0.1j", 4: "4.5", 5: "0.1", # 1: "0.5"
    6: "0.1,0.0,0.0,0.0", 7: "0.1,0.0,0.0", 8: "0.1+0.1j",
    9: "2.0", 10: "0.08,0.0,0.0,0.0",
    11: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    12: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    13: "0.1" + ",0.0" * 15,
    14: "0.1+0.2e1", 15: "0.1,0.0", 16: "0.1,0.0",
    17: "1.0" + ",0.0" * 31, 18: "1.0" + ",0.0" * 63,
    19: "1.0" + ",0.0" * 127, 20: "1.0" + ",0.0" * 255,
    21: "0.56,1.7", 22: "22", 23: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
}
"""
type_class_map = {
    6: "QuaternionNumber",
    7: "NeutrosophicNumber",
    8: "NeutrosophicComplexNumber",
    10: "BicomplexNumber",
    11: "NeutrosophicBicomplexNumber",
    12: "OctonionNumber",
    13: "SedenionNumber",
    14: "CliffordNumber",
    15: "DualNumber",
    16: "SplitcomplexNumber",
    17: "PathionNumber",
    18: "ChingonNumber",
    19: "RoutonNumber",
    20: "VoudonNumber",
    21: "SuperrealNumber",
    22: "TernaryNumber",
    23: "HypercomplexNumber",
}
"""
ALL_CLASSES = {
    'Routon': Routon,
    'Voudon': Voudon,
    'Pathion': Pathion,
    'Chingon': Chingon,
    'HypercomplexNumber': HypercomplexNumber,
    'Octonion': Octonion,
    'Sedenion': Sedenion,
    'NeutrosophicNumber': NeutrosophicNumber,
    'NeutrosophicComplexNumber': NeutrosophicComplexNumber,
    'HyperrealNumber': HyperrealNumber,
    'CliffordNumber': CliffordNumber,
    'BicomplexNumber': BicomplexNumber,
    'DualNumber': DualNumber,
}

for cls_name in ALL_CLASSES:
    cls = ALL_CLASSES[cls_name]
    _make_property(cls, 'components')
    _make_property(cls, 'coeffs')
    _make_property(cls, 'to_list')
"""


# ========================
# components ve coeffs metodlarını property yap
# ========================
def _make_property(cls, attr_name):
    if hasattr(cls, attr_name):
        attr = getattr(cls, attr_name)
        if callable(attr) and not isinstance(attr, property):
            setattr(cls, attr_name, property(attr))


# Uygulanacak sınıfların listesi
for cls_name in [
    "Routon",
    "Voudon",
    "Pathion",
    "Chingon",
    "HypercomplexNumber",
    "Octonion",
    "Sedenion",
    "NeutrosophicNumber",
    "NeutrosophicComplexNumber",
    "HyperrealNumber",
    "CliffordNumber",
    "BicomplexNumber",
    "DualNumber",
]:
    cls = globals().get(cls_name)
    if cls is not None:
        _make_property(cls, "components")
        _make_property(cls, "coeffs")
        _make_property(cls, "to_list")


### robust_int – Evrensel Tam Sayı Çıkarıcı
def robust_int(x: Any) -> Optional[int]:
    """
    Herhangi bir Keçeci sayısından güvenli bir şekilde pozitif bir tam sayı çıkarır.
    - Önce _get_integer_representation denenir (katı kurallar).
    - Başarısız olursa daha esnek yöntemlerle (norm, ilk bileşen, string regex) tam sayı elde edilir.
    """
    # 1) Mevcut sağlam fonksiyon
    val = _get_integer_representation(x)
    if val is not None:
        return val

    # 2) Esnek yuvarlama
    try:
        if isinstance(x, (int, float)):
            return int(round(abs(x)))
    except:
        pass

    # 3) Norm/büyüklük
    for attr in ("norm", "__abs__", "magnitude"):
        if hasattr(x, attr):
            try:
                return int(
                    round(abs(x() if callable(getattr(x, attr)) else getattr(x, attr)))
                )
            except:
                pass

    # 4) İlk bileşen (coeffs, coefficients, w, real, t, a, value, x)
    for attr in ("coeffs", "coefficients"):
        if hasattr(x, attr):
            try:
                c0 = list(getattr(x, attr))[0]
                return int(round(float(c0)))
            except:
                pass

    for attr in ("w", "real", "t", "a", "value", "x"):
        if hasattr(x, attr):
            try:
                v = getattr(x, attr)
                if isinstance(v, complex):
                    return int(round(abs(v)))
                return int(round(float(v)))
            except:
                continue

    # 5) Ternary digits
    if hasattr(x, "digits"):
        try:
            dec = 0
            for i, d in enumerate(reversed(list(x.digits))):
                dec += int(d) * (3**i)
            return abs(dec)
        except:
            pass

    # 6) Liste/tuple ilk eleman
    if isinstance(x, (list, tuple)) and len(x) > 0:
        try:
            return int(round(float(x[0])))
        except:
            pass

    # 7) String temsili üzerinden sayı çıkarma
    try:
        nums = re.findall(r"[-+]?\d*\.?\d+", str(x))
        if nums:
            return int(round(abs(float(nums[0]))))
    except:
        pass

    return None


### extract_scalar – Her Türden Skaler Çıkarma
def extract_scalar(x: Any) -> float:
    """Keçeci sayısının birincil skaler değerini float olarak döndürür."""
    if hasattr(x, "real"):
        return float(x.real)
    if isinstance(x, complex):
        return x.real
    if isinstance(x, (list, tuple)) and len(x) > 0:
        return float(x[0])
    return float(x)


"""
def extract_scalar(result):
    if hasattr(result, 'real'): return result.real
    if isinstance(result, complex): return result.real
    if isinstance(result, (list,tuple)): return result[0]
    return float(result)
"""


def universal_fallback_kpn(seq: List[Any]) -> Optional[int]:
    """Tüm türler için çalışan serideki tekrarlayan ilk asal bulucu (yumuşak tamsayı çıkarma + asallık)."""
    vals = []
    for x in seq[:5000]:
        try:
            r = robust_int(x)
            if r is not None and r > 1 and sympy.isprime(r):
                vals.append(r)
        except:
            continue
    if not vals:
        return None
    cnt = Counter(vals)
    # En az iki kez görülen en sık asal
    best = max(cnt.items(), key=lambda item: item[1])
    if best[1] > 1:
        return best[0]
    return None


def find_kpn(seq, use_safe=True):
    try:
        kpn = find_kececi_prime_number(seq)
        if kpn is not None and kpn > 1:
            return kpn, "find_kececi_prime_number"
    except:
        pass
    if use_safe:
        candidates = []
        for x in seq[:5000]:
            try:
                val = robust_int(x)
                if val > 1 and isprime(val):
                    candidates.append(val)
            except:
                continue
        if candidates:
            kpn = Counter(candidates).most_common(1)[0][0]
            return kpn, "safe_find_kpn"
    return None, None


def safe_find_kpn(sequence: List[Any], type_num: Optional[int] = None) -> Optional[int]:
    """
    Keçeci asal sayısını (KPN) bulur.
    1) Güncel find_kececi_prime_number fonksiyonunu dener.
    2) Başarısız olursa universal_fallback_kpn kullanır.
    """
    # 1. Aşama: Kütüphanenin asıl bulucusu
    try:
        from kececinumbers import find_kececi_prime_number

        kpn = find_kececi_prime_number(sequence)
        if kpn is not None:
            return kpn
    except Exception:
        pass

    # 2. Aşama: Evrensel yedek
    try:
        kpn = universal_fallback_kpn(sequence)
        if kpn is not None:
            return kpn
    except Exception:
        pass

    return None


"""
def safe_find_kpn(sequence, type_num):
    # 1) Güncel fonksiyon
    try:
        kpn = find_kececi_prime_number(sequence)
        if kpn is not None:
            return kpn
    except:
        pass

    # 2) Evrensel yedek (tüm türler için)
    try:
        kpn = universal_fallback_kpn(sequence)
        if kpn is not None:
            return kpn
    except:
        pass

    return None
"""
"""
def safe_find_kpn(sequence):
    # 1) Önce güncel kütüphane fonksiyonunu dene
    kpn = find_kececi_prime_number(sequence)
    if kpn is not None:
        return kpn
    # 2) Başarısız olursa evrensel yedek bulucuyu kullan
    return universal_fallback_kpn(sequence)
"""


# ==================== ANALİZ SINIFI ====================
class KececiAnalyzer:
    def __init__(self):
        self.results = []
        self.type_stats = {}
        self.global_stats = {}
        self.failed = {}

    def run_analysis(self):
        print("=" * 80)
        print("🎯 KEÇECI CRAMÉR CONJECTURE – VARSYILAN ANALİZ")
        print("=" * 80)
        try:
            type_names = TYPE_NAMES
        except:
            type_names = {i: f"Tip{i}" for i in range(1, 24)}

        default_starts = {
            1: "0",
            2: "-9.80",  # -5.0
            3: "1+1j",
            4: "41.00",  # 3.14
            5: "7/8",  # 3.5:
            6: "1.0,0.0,0.0,0.0",
            7: "0.6,0.2,0.1",
            8: "1+1j",
            9: "9.64",  # 1.0
            10: "1.34,2.55,0.25,4.61",
            11: "2",  # 2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0 # 0.56,1.94,0.75,1.47,0.96,0.48,1.08,0.02
            12: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
            13: "1.0" + ",0.0" * 15,
            14: "1.0+2.0e1+3.0e12",
            15: "1.0,0.1",
            16: "1.0,0.5",
            17: "2",
            # "1.0" + ",0.0" * 31,
            18: "2",
            # "1.0" + ",0.0" * 63,
            19: "0.51,0.37,0.60,1.71,0.76,1.07,1.31,0.04,0.01,0.70,0.61,1.44,0.91,0.90,0.82,0.17,0.43,1.81,0.40,1.55,0.75,0.60,0.52,0.43,1.79,0.68,0.94,0.26,0.32,1.98,0.10,0.63,0.84,1.92,1.10,0.53,1.06,1.75,0.22,0.35,1.69,0.48,0.87,0.04,1.64,1.82,1.89,0.62,1.77,0.83,0.14,1.59,0.86,1.71,0.60,0.96,0.47,0.00,0.03,0.99,1.48,0.22,1.58,1.26,1.47,0.42,1.41,1.58,0.91,0.52,1.37,1.09,1.14,1.42,1.63,1.26,0.44,1.23,1.43,0.30,1.83,1.82,1.70,0.33,1.51,1.24,0.35,1.89,0.84,1.20,1.09,0.90,0.38,1.77,1.17,1.05,1.86,0.80,1.52,1.20,0.29,0.60,1.63,1.19,1.18,1.04,1.05,0.55,0.58,0.71,0.04,0.92,0.37,1.52,1.79,1.81,0.74,0.98,1.70,1.64,0.34,1.40,0.28,1.22,0.72,1.64,1.31,0.68",
            # "1.0" + ",0.0" * 127,
            20: "1.28,0.41,1.02,0.17,0.79,1.96,1.10,1.34,1.40,0.94,1.72,1.74,0.85,0.01,0.86,1.72,0.28,1.63,1.02,1.31,0.97,0.43,1.90,1.18,0.64,1.87,1.25,1.14,0.79,1.44,1.59,0.36,0.43,0.48,1.01,1.83,1.86,1.58,0.24,1.90,0.17,0.83,0.40,0.15,0.35,1.67,0.81,0.39,0.26,0.27,1.46,0.74,0.21,0.20,0.48,1.23,0.16,0.37,1.43,0.81,0.61,1.16,0.20,0.66,1.66,1.59,0.33,0.93,1.22,1.64,0.31,0.50,0.65,1.00,0.83,0.84,0.31,1.37,0.80,1.36,1.56,0.74,0.66,1.76,0.65,1.42,1.49,1.50,1.94,1.69,1.52,1.98,1.70,1.45,0.13,1.31,0.05,1.66,0.33,1.70,0.07,1.17,1.97,1.33,0.69,1.30,0.61,0.69,1.18,0.22,1.32,0.52,1.11,0.81,1.19,1.44,1.68,0.26,0.50,0.25,0.27,0.54,0.24,1.15,1.14,1.02,0.67,0.09,1.86,0.48,1.10,1.38,0.93,0.19,1.68,1.36,1.01,1.58,1.95,1.84,1.22,1.10,0.54,0.64,1.07,0.97,1.28,1.71,0.41,1.16,0.65,1.34,1.39,1.42,0.82,0.38,1.49,1.67,0.83,1.52,0.44,1.98,0.27,1.66,0.70,1.65,0.89,1.35,0.42,0.28,1.10,1.35,1.73,0.42,0.70,0.80,0.43,1.68,0.70,0.82,1.63,0.92,1.69,1.19,1.71,1.71,0.20,1.97,0.96,1.94,0.97,0.20,0.52,1.55,0.65,1.11,1.70,0.18,1.68,1.29,0.88,1.11,0.69,0.18,1.41,0.21,0.87,1.75,0.97,1.31,1.93,0.31,0.90,0.56,1.11,0.42,1.64,0.09,0.30,1.42,0.66,1.74,0.69,0.69,1.83,0.88,0.38,1.63,1.63,1.87,0.46,1.22,0.57,0.03,1.03,0.81,0.62,0.33,1.54,0.85,0.18,1.31,1.61,0.40,1.73,0.28,1.03,0.16,0.07,0.34,0.53,0.03,0.18,1.41,1.60,0.49",
            # "1.0" + ",0.0" * 255,
            21: "2",  # "12.85,0.08",
            22: "11",
            23: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
        }
        default_adds = {
            1: "9",
            2: "-6.19",  # -0.5
            3: "0.1+0.1j",
            4: "1.40",  # 0.1
            5: "4/5",  # 0.1
            6: "0.1,0.0,0.0,0.0",
            7: "0.1,0.0,0.0",
            8: "0.1+0.1j",
            9: "0.57",  # 2.0
            10: "0.08,0.0,0.0,0.0",
            11: "2",  # 0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0 # 0.1,0,0,0,0,0,0,0
            12: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
            13: "0.1" + ",0.0" * 15,
            14: "0.1+0.2e1",
            15: "0.1,0.0",
            16: "0.1,0.0",
            17: "2",
            # "1.0" + ",0.0" * 31,
            18: "2",
            # "1.0" + ",0.0" * 63,
            19: "0.21,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
            # "1.0" + ",0.0" * 127,
            20: "0.26,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
            # "1.0" + ",0.0" * 255,
            21: "2",  # "0.56,1.7",
            22: "22",
            23: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
        }

        """
        default_starts = {
            1: ["0", "2", "5"], 2: ["-5", "-3"], 3: ["9.17+2.73j"],  # : ["1+1j", "2+2j", "9.17+2.73j"]
            4: ["2.5", "3.14", "1.5"],
            5: ["3.5", "1/2"], 6: ["1.0,0.0,0.0,0.0"], 7: ["0.6,0.2,0.1"],
            8: ["1+1j"], 9: ["1.0"], 10: ["1.34,2.55,0.25,4.61"],
            11: ["2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0"], 12: ["1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
            13: ["1.0" + ",0.0" * 15], 14: ["1.0+2.0e1+3.0e12"], 15: ["1.0,0.1"],
            16: ["1.0,0.5"], 17: ["1.0" + ",0.0" * 31], 18: ["1.0" + ",0.0" * 63],
            19: ["1.0" + ",0.0" * 127], 20: ["1.0" + ",0.0" * 255], 21: ["12.85,0.08"],
            22: ["2"], 23: ["1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
        }
        default_adds = {
            1: ["9", "3"], 2: ["-3"], 3: ["1.87+1.56j"], # 3: ["0.1+0.1j", "1.87+1.56j"],
            4: ["4.5"], 
            5: ["0.1"],
            6: ["0.1,0.0,0.0,0.0"], 7: ["0.1,0.0,0.0"], 8: ["0.1+0.1j"], 9: ["2.0"],
            10: ["0.08,0.0,0.0,0.0"], 11: ["0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
            12: ["0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0"], 13: ["0.1" + ",0.0" * 15],
            14: ["0.1+0.2e1"], 15: ["0.1,0.0"], 16: ["0.1,0.0"],
            17: ["1.0" + ",0.0" * 31], 18: ["1.0" + ",0.0" * 63], 19: ["1.0" + ",0.0" * 127],
            20: ["1.0" + ",0.0" * 255], 
            21: ["0.56,1.7"], 
            22: ["1"],
            23: ["0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
        }
        """
        """
        default_starts = {
            1: ["0"], 
            2: ["-1.46"], 
            3: ["1.50+2.56j"], 
            4: ["27.59"],
            5: ["7/8"], 
            6: [".47,1.74,1.69,0.77"], 
            7: ["0.41,0.89,0.80"],
            8: ["0.22+8.60j"], 
            9: ["3.30"], 
            10: ["4.68,1.35,0.66,0.43"],
            11: ["0.85,0.38,0.72,1.82,0.07,0.75,1.11,1.95"], 
            12: ["1.93,0.11,0.16,0.54,1.47,1.79,1.05,1.10"],
            13: ["0.46"], 
            14: ["1.0+2.0e1+3.0e12"],
            15: ["8.93,0.05"],
            16: ["4.94,3.66"], 
            17: ["2.0" + ",0.0" * 31], 
            18: ["2.0" + ",0.0" * 63],
            19: ["0.68,0.59,1.89,0.26,1.86,1.99,0.48,0.88,0.91,1.74,1.76,0.82,0.83,1.41,0.79,0.75,1.57,0.44,0.66,0.81,0.63,0.94,0.55,0.96,0.40,1.22,1.94,0.42,0.08,0.54,0.51,0.69,0.11,0.58,0.58,1.59,0.45,1.77,0.44,0.70,0.39,0.46,0.03,0.45,1.35,1.29,0.25,1.75,0.78,0.94,1.92,0.20,1.66,1.19,0.63,0.61,1.42,1.26,1.90,1.48,1.04,0.82,1.01,0.13,0.19,0.43,1.20,1.14,0.25,0.97,0.91,1.19,0.49,0.11,0.05,1.09,0.54,0.88,0.06,0.51,0.39,0.52,1.84,0.17,1.50,0.66,0.23,1.13,1.10,1.53,2.00,1.97,1.26,1.37,0.73,1.42,1.94,0.09,1.58,0.23,0.31,1.90,1.17,1.71,1.93,0.68,0.60,1.56,1.01,1.02,1.05,0.48,0.79,0.36,0.23,1.17,0.22,0.15,0.73,1.63,0.31,1.70,1.42,0.89,1.76,0.84,1.67,0.93"], 
            20: ["0.01,0.81,1.35,0.45,0.69,0.94,1.20,0.82,1.20,0.14,0.59,0.25,1.99,0.10,1.11,0.87,1.98,0.58,1.36,0.62,0.65,0.06,0.51,0.67,1.00,1.23,1.28,1.71,0.36,1.44,0.97,0.98,1.53,0.44,0.36,1.59,0.39,0.73,0.41,1.10,0.70,0.90,1.88,1.23,1.36,2.00,1.51,1.55,0.51,0.96,0.63,0.05,0.64,1.32,0.00,1.84,1.15,1.20,0.47,1.23,0.90,0.45,0.67,0.78,1.50,0.37,0.47,1.08,1.93,0.48,1.73,0.06,0.13,0.51,0.61,0.75,0.56,0.43,1.29,0.87,0.51,1.23,0.32,0.24,0.40,0.89,1.73,1.78,1.45,0.33,1.41,0.49,0.49,1.12,1.77,1.54,1.97,0.61,1.88,0.13,1.40,1.87,0.81,1.17,1.20,1.97,1.02,1.35,1.47,0.39,1.01,0.14,0.57,1.66,0.04,1.19,1.94,1.54,0.72,0.03,1.89,0.89,0.24,0.61,0.61,0.81,0.35,1.44,1.76,1.10,0.21,1.35,1.49,0.12,1.04,1.30,1.15,0.61,1.10,0.44,0.10,1.87,1.39,1.49,0.96,0.19,1.11,0.14,0.46,1.61,1.54,1.24,0.50,0.06,1.79,1.04,0.90,0.32,1.36,1.05,0.18,0.44,0.85,1.95,1.79,1.31,0.97,0.73,1.76,0.05,1.80,0.75,1.83,0.58,1.56,0.38,0.77,1.61,0.86,0.91,0.25,0.73,1.69,1.06,0.82,0.32,0.01,0.45,1.66,0.33,0.68,0.39,0.37,1.45,1.69,1.02,0.12,1.17,1.55,0.14,1.90,0.34,1.37,1.61,0.01,0.79,1.41,1.88,0.04,1.69,1.85,0.16,0.59,1.08,1.89,1.11,1.18,1.04,1.42,0.96,1.87,1.05,0.27,0.21,1.32,0.65,0.43,1.31,0.52,1.30,1.59,0.79,1.20,1.38,1.82,1.28,1.65,0.36,0.02,0.03,1.71,1.57,1.94,0.77,1.65,1.53,1.06,1.43,0.58,0.47,0.79,0.28,1.69,1.36,0.01,1.24"], 
            21: ["2"],
            22: ["11"], 
            23: ["0.53,0.32,0.79,0.95,1.11,1.54,0.69,1.23"],
        }
        default_adds = {
            1: ["9"], 
            2: ["-4.42"], 
            3: ["0.13+1.06j"],
            4: ["0.28"], 
            5: ["4/5"],
            6: ["0.74,0,0,0"], 
            7: ["0.03,0,0"], 
            8: ["0.56+1.13j"], 
            9: ["0.30"],
            10: ["0.08"], 
            11: ["0.1"],
            12: ["0.03"], 
            13: ["0.46"],
            14: ["0.1+0.2e1"], 
            15: ["0.17,0"], 
            16: ["0.7672"],
            17: ["2.0" + ",0.0" * 31], 
            18: ["2.0" + ",0.0" * 63], 
            19: ["0.16"],
            20: ["0.04"], 
            21: ["2"], 
            22: ["22"],
            23: ["0.03,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
        }
        """

        print("\n📌 Varsayılan parametrelerle test...")
        for t in range(1, 24):
            name = type_names.get(t, f"Tip{t}")
            print(f"   {name:20}: ", end="", flush=True)
            res = run_test(t, default_starts[t], default_adds[t], iterations=10000)
            if res.get("success"):
                self.results.append(res)
                print(
                    f"✅ KPN={res['kpn']} Ratio={res['ratio']:.4f} (bulan: {res.get('method', '?')})"
                )
            else:
                reason = res.get("reason", "?")
                self.failed[t] = reason
                print(f"❌ ({reason})")
        self._summarize()

    def _summarize(self):
        if self.results:
            groups = {}
            for r in self.results:
                groups.setdefault(r["type"], []).append(r)
            self.type_stats = {}
            for t, lst in groups.items():
                best = min(lst, key=lambda x: x["ratio"])
                self.type_stats[t] = {
                    "type_name": best["type_name"],
                    "ratio": best["ratio"],
                    "kpn": best["kpn"],
                    "kpn_freq": best["kpn_freq"] * 100,
                    "start": best["start"],
                    "add": best["add"],
                    "method": best.get("method", "?"),
                }
        print("\n" + "=" * 80)
        print("🏁 SONUÇ")
        print("=" * 80)
        print(f"Başarılı tür: {len(self.type_stats)}/23")
        if self.failed:
            print("❌ Başarısız kalanlar:")
            for t, reason in self.failed.items():
                print(f"   • Tip {t}: {reason}")
        else:
            print("✅ TÜM TÜRLER BAŞARILI!")
        if self.type_stats:
            ratios = [v["ratio"] for v in self.type_stats.values()]
            print(f"\n📊 Ratio ort: {np.mean(ratios):.4f}")


# ==================== HAVUZLAR (10.000) ====================
def gen_ternary():
    return [
        {
            "start": "".join(
                str(random.choice([0, 1, 2])) for _ in range(random.randint(1, 4))
            ).lstrip("0")
            or "1",
            "add": str(random.randint(1, 3)),
        }
        for _ in range(10000)
    ]


def gen_bicomplex():
    return [
        {
            "start": f"{round(random.uniform(0.1, 10), 2)},{round(random.uniform(0, 5), 2)},{round(random.uniform(0, 5), 2)},{round(random.uniform(0, 5), 2)}",
            "add": f"{round(random.uniform(0.05, 0.5), 2)},0.0,0.0,0.0",
        }
        for _ in range(10000)
    ]


def gen_superreal():
    return [
        {
            "start": f"{round(random.uniform(1, 20), 2)},{round(random.uniform(0, 10), 2)}",
            "add": f"{round(random.uniform(0.5, 5), 2)},{round(random.uniform(0, 4), 2)}",
        }
        for _ in range(10000)
    ]


TERNARY_TESTS = gen_ternary()
BICOMPLEX_TESTS = gen_bicomplex()
SUPER_REAL_TESTS = gen_superreal()


# ============================================================
# Kapsamlı rastgele test (seçenek 1)
# ============================================================
def comprehensive_cramer_test(
    num_trials_per_type=1000, iterations=1000, save_to_file=False
):
    """
    Her tip için rastgele parametrelerle kapsamlı Cramér testi yapar.
    Sonuçları konsola yazdırır ve isteğe bağlı olarak dosyaya kaydeder.
    """
    import sys

    if save_to_file:
        original_stdout = sys.stdout
        f = open("cramer_test_results.txt", "w", encoding="utf-8")
        sys.stdout = f

    print("=" * 80)
    print("🎯 KEÇECI CRAMÉR – KAPSAMLI RASTGELE TEST (MODÜL İÇİ)")
    print(
        f"   Her tip için {num_trials_per_type} rastgele (start, add) çifti test edilecek."
    )
    print(f"   Her testte {iterations} ana adım kullanılacak.")
    print("=" * 80)

    successes = {}
    ratios = {}
    kpn_counter = {}
    examples = {}  # typ -> list of (start, add, kpn, ratio)

    for typ in range(1, 24):
        print(f"\n📌 Tip {typ} ({TYPE_NAMES.get(typ, '')}) test ediliyor...")
        success_count = 0
        ratio_list = []
        counter = Counter()
        ex_list = []
        for trial in range(num_trials_per_type):
            if (trial + 1) % 100 == 0:
                print(f"   {trial + 1}/{num_trials_per_type} tamamlandı...")
            start, add = random_start_add(typ)
            res = run_cramer_test(typ, start, add, iterations=iterations)
            if res.get("success"):
                success_count += 1
                ratio_list.append(res["ratio"])
                counter[res["kpn"]] += 1
                ex_list.append((start, add, res["kpn"], res["ratio"]))
        success_rate = success_count / num_trials_per_type
        avg_ratio = np.mean(ratio_list) if ratio_list else 1.0
        successes[typ] = success_rate
        ratios[typ] = avg_ratio
        kpn_counter[typ] = counter
        examples[typ] = ex_list
        print(
            f"   ✅ Başarı oranı: {success_rate * 100:.1f}% (Ort. ratio: {avg_ratio:.4f})"
        )

    # Detaylı başarılı örnekler (ilk 5)
    print("\n" + "=" * 80)
    print("📋 BAŞARILI ÖRNEK PARAMETRELER (ilk 5)")
    print("=" * 80)
    for typ in range(1, 24):
        name = TYPE_NAMES.get(typ, str(typ))
        exs = examples[typ]
        if exs:
            print(f"\nTip {typ} ({name}):")
            for i, (s, a, k, r) in enumerate(exs[:5]):
                print(f"   {i + 1}. start={s}, add={a} -> KPN={k}, ratio={r:.4f}")
        else:
            print(f"\nTip {typ} ({name}): Başarılı örnek yok.")

    # Özet tablosu
    print("\n" + "=" * 80)
    print("🏁 KAPSAMLI TEST SONUÇLARI (KPN dağılımı ile)")
    print("=" * 80)
    for typ in range(1, 24):
        name = TYPE_NAMES.get(typ, str(typ))[:20]
        success_rate = successes[typ]
        avg_ratio = ratios[typ]
        counter = kpn_counter[typ]
        if counter and success_rate > 0:
            most_common_kpn, freq = counter.most_common(1)[0]
            freq_percent = freq / (success_rate * num_trials_per_type) * 100
            print(
                f"Tip {typ:2} ({name:20}): Başarı: {success_rate * 100:5.1f}%   Ort. Ratio: {avg_ratio:.4f}   En sık KPN: {most_common_kpn} ({freq_percent:.1f}% of successes)"
            )
        else:
            print(
                f"Tip {typ:2} ({name:20}): Başarı: {success_rate * 100:5.1f}%   Ort. Ratio: {avg_ratio:.4f}   KPN bulunamadı"
            )
    print("-" * 80)
    print(
        f"Ortalama başarı oranı (tüm tipler): {np.mean(list(successes.values())) * 100:.1f}%"
    )
    print(f"Ortalama Cramér ratio: {np.mean(list(ratios.values())):.4f}")
    print("=" * 80)

    if save_to_file:
        sys.stdout = original_stdout
        f.close()
        print("Sonuçlar 'cramer_test_results.txt' dosyasına kaydedildi.")


def run_comprehensive_analysis(num_trials_per_type=1000, iterations=1000):
    """
    Her tip için rastgele parametrelerle kapsamlı Cramér testi yapar.
    Sonuçları konsola yazdırır.
    """
    print("=" * 80)
    print("🎯 KEÇECI CRAMÉR – KAPSAMLI RASTGELE TEST (MODÜL İÇİ)")
    print(
        f"   Her tip için {num_trials_per_type} rastgele (start, add) çifti test edilecek."
    )
    print(f"   Her testte {iterations} ana adım kullanılacak.")
    print("=" * 80)
    successes = {}
    ratios = {}
    kpn_counter = {}
    for typ in range(1, 24):
        print(f"\n📌 Tip {typ} ({TYPE_NAMES.get(typ, '')}) test ediliyor...")
        success_count = 0
        ratio_list = []
        counter = Counter()
        for trial in range(num_trials_per_type):
            if (trial + 1) % 100 == 0:
                print(f"   {trial + 1}/{num_trials_per_type} tamamlandı...")
            start, add = random_start_add(typ)
            res = run_cramer_test(typ, start, add, iterations=iterations)
            if res.get("success"):
                success_count += 1
                ratio_list.append(res["ratio"])
                counter[res["kpn"]] += 1
        success_rate = success_count / num_trials_per_type
        avg_ratio = np.mean(ratio_list) if ratio_list else 1.0
        successes[typ] = success_rate
        ratios[typ] = avg_ratio
        kpn_counter[typ] = counter
        print(
            f"   ✅ Başarı oranı: {success_rate * 100:.1f}% (Ort. ratio: {avg_ratio:.4f})"
        )

    print("\n" + "=" * 80)
    print("🏁 KAPSAMLI TEST SONUÇLARI (KPN dağılımı ile)")
    print("=" * 80)
    for typ in range(1, 24):
        name = TYPE_NAMES.get(typ, str(typ))[:20]
        success_rate = successes[typ]
        avg_ratio = ratios[typ]
        counter = kpn_counter[typ]
        if counter and success_rate > 0:
            most_common_kpn, freq = counter.most_common(1)[0]
            freq_percent = freq / (success_rate * num_trials_per_type) * 100
            print(
                f"Tip {typ:2} ({name:20}): Başarı: {success_rate * 100:5.1f}%   Ort. Ratio: {avg_ratio:.4f}   En sık KPN: {most_common_kpn} ({freq_percent:.1f}% of successes)"
            )
        else:
            print(
                f"Tip {typ:2} ({name:20}): Başarı: {success_rate * 100:5.1f}%   Ort. Ratio: {avg_ratio:.4f}   KPN bulunamadı"
            )
    print("-" * 80)
    print(
        f"Ortalama başarı oranı (tüm tipler): {np.mean(list(successes.values())) * 100:.1f}%"
    )
    print(f"Ortalama Cramér ratio: {np.mean(list(ratios.values())):.4f}")
    print("=" * 80)


"""
def run_comprehensive_analysis(num_trials_per_type=1000, iterations=1000):
    print("="*80)
    print("🎯 KEÇECI CRAMÉR – KAPSAMLI RASTGELE TEST")
    print(f"   Her tip için {num_trials_per_type} rastgele (start, add) çifti test edilecek.")
    print(f"   Her testte {iterations} ana adım kullanılacak.")
    print("="*80)
    type_names = TYPE_NAMES # if hasattr('TYPE_NAMES') else {i:f"Tip{i}" for i in range(1,24)}
    successes = {}
    ratios = {}
    for typ in range(1, 24):
        print(f"\n📌 Tip {typ} ({type_names.get(typ,'')}) test ediliyor...")
        success_count = 0
        ratio_list = []
        for trial in range(num_trials_per_type):
            if (trial+1) % 100 == 0:
                print(f"   {trial+1}/{num_trials_per_type} tamamlandı...")
            start, add = random_start_add(typ)
            res = run_test(typ, start, add, iterations=iterations, first_divisor=3, ask_plus_first=True)
            if res.get('success'):
                success_count += 1
                ratio_list.append(res['ratio'])
        success_rate = success_count / num_trials_per_type
        avg_ratio = np.mean(ratio_list) if ratio_list else 1.0
        successes[typ] = success_rate
        ratios[typ] = avg_ratio
        print(f"   ✅ Başarı oranı: {success_rate*100:.1f}% (Ort. ratio: {avg_ratio:.4f})")
    print("\n" + "="*80)
    print("🏁 KAPSAMLI TEST SONUÇLARI")
    print("="*80)
    for typ in range(1,24):
        print(f"Tip {typ:2} ({type_names.get(typ,'')[:20]:20}): Başarı: {successes[typ]*100:5.1f}%   Ort. Ratio: {ratios[typ]:.4f}")
    print("-"*80)
    print(f"Ortalama başarı oranı (tüm tipler): {np.mean(list(successes.values()))*100:.1f}%")
    print(f"Ortalama Cramér ratio: {np.mean(list(ratios.values())):.4f}")
    print("="*80)
"""


def random_start_add(typ):
    if typ == 1:
        return f"{random.uniform(0.1, 50):.2f}", f"{random.uniform(0.1, 10):.2f}"
    elif typ == 2:
        return f"{random.uniform(-50, -0.1):.2f}", f"{random.uniform(-10, -0.1):.2f}"
    elif typ == 3:
        return (
            f"{random.uniform(0, 10):.2f}+{random.uniform(0, 10):.2f}j",
            f"{random.uniform(0.1, 2):.2f}+{random.uniform(0, 2):.2f}j",
        )
    elif typ == 4:
        return f"{random.uniform(0.1, 50):.2f}", f"{random.uniform(0.1, 10):.2f}"
    elif typ == 5:
        return (
            f"{random.randint(1, 20)}/{random.randint(1, 20)}",
            f"{random.randint(1, 5)}/{random.randint(1, 5)}",
        )
    elif typ == 6:
        return (
            f"{random.uniform(0, 5):.2f},{random.uniform(0, 2):.2f},{random.uniform(0, 2):.2f},{random.uniform(0, 2):.2f}",
            f"{random.uniform(0.01, 1):.2f},0,0,0",
        )
    elif typ == 7:
        return (
            f"{random.uniform(0, 1):.2f},{random.uniform(0, 1):.2f},{random.uniform(0, 1):.2f}",
            f"{random.uniform(0.01, 0.2):.2f},0,0",
        )
    elif typ == 8:
        return (
            f"{random.uniform(0, 10):.2f}+{random.uniform(0, 10):.2f}j",
            f"{random.uniform(0.1, 2):.2f}+{random.uniform(0, 2):.2f}j",
        )
    elif typ == 9:
        return f"{random.uniform(0, 10):.2f}", f"{random.uniform(0.1, 2):.2f}"
    elif typ == 10:
        return (
            f"{random.uniform(0, 5):.2f},{random.uniform(0, 2):.2f},{random.uniform(0, 2):.2f},{random.uniform(0, 2):.2f}",
            f"{random.uniform(0.01, 0.5):.2f},0,0,0",
        )
    elif typ == 11:
        comps = [f"{random.uniform(0, 2):.2f}" for _ in range(8)]
        return ",".join(comps), "0.1,0,0,0,0,0,0,0"
    elif typ in (12, 13, 17, 18, 19, 20, 23):
        dim = {12: 8, 13: 16, 17: 32, 18: 64, 19: 128, 20: 256, 23: 8}[typ]
        start_comps = [f"{random.uniform(0, 2):.2f}" for _ in range(dim)]
        add_comps = [f"{random.uniform(0.01, 0.5):.2f}"] + ["0.0"] * (dim - 1)
        return ",".join(start_comps), ",".join(add_comps)
    elif typ == 14:
        return "1.0+2.0e1+3.0e12", "0.1+0.2e1"
    elif typ == 15:
        return (
            f"{random.uniform(0, 10):.2f},{random.uniform(0, 1):.2f}",
            f"{random.uniform(0.1, 1):.2f},0",
        )
    elif typ == 16:
        return (
            f"{random.uniform(0, 10):.2f},{random.uniform(0, 5):.2f}",
            f"{random.uniform(0.1, 1):.2f},0",
        )
    elif typ == 21:
        return (
            f"{random.uniform(1, 20):.2f},{random.uniform(0, 5):.2f}",
            f"{random.uniform(0.5, 2):.2f},{random.uniform(0, 2):.2f}",
        )
    elif typ == 22:
        return str(random.randint(1, 50)), str(random.randint(1, 5))
    else:
        return "1", "1"


def srandom_start_add(typ):
    # Başarılı olduğu bilinen referans değerler

    default_starts = {
        1: "0",
        2: "-5.0",
        3: "1+1j",
        4: "3.14",
        5: "7/8",  # 3.5:
        6: "1.0,0.0,0.0,0.0",
        7: "0.6,0.2,0.1",
        8: "1+1j",
        9: "9.64",  # 1.0
        10: "1.34,2.55,0.25,4.61",
        11: "2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
        12: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
        13: "1.0" + ",0.0" * 15,
        14: "1.0+2.0e1+3.0e12",
        15: "1.0,0.1",
        16: "1.0,0.5",
        17: "1.0" + ",0.0" * 31,
        18: "1.0" + ",0.0" * 63,
        19: "1.0" + ",0.0" * 127,
        20: "1.0" + ",0.0" * 255,
        21: "2",  # "12.85,0.08",
        22: "11",
        23: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    }
    default_adds = {
        1: "9",
        2: "-0.5",
        3: "0.1+0.1j",
        4: "0.1",
        5: "4/5",  # 0.1
        6: "0.1,0.0,0.0,0.0",
        7: "0.1,0.0,0.0",
        8: "0.1+0.1j",
        9: "0.57",  # 2.0
        10: "0.08,0.0,0.0,0.0",
        11: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
        12: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
        13: "0.1" + ",0.0" * 15,
        14: "0.1+0.2e1",
        15: "0.1,0.0",
        16: "0.1,0.0",
        17: "1.0" + ",0.0" * 31,
        18: "1.0" + ",0.0" * 63,
        19: "1.0" + ",0.0" * 127,
        20: "1.0" + ",0.0" * 255,
        21: "2",  # "0.56,1.7",
        22: "22",
        23: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0",
    }

    """
    default_starts = {
        1: ["0", "2", "5"], 2: ["-5", "-3"], 3: ["9.17+2.73j"],  # : ["1+1j", "2+2j", "9.17+2.73j"]
        4: ["2.5", "3.14", "1.5"],
        5: ["3.5", "1/2"], 6: ["1.0,0.0,0.0,0.0"], 7: ["0.6,0.2,0.1"],
        8: ["1+1j"], 9: ["1.0"], 10: ["1.34,2.55,0.25,4.61"],
        11: ["2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0"], 12: ["1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
        13: ["1.0" + ",0.0" * 15], 14: ["1.0+2.0e1+3.0e12"], 15: ["1.0,0.1"],
        16: ["1.0,0.5"], 17: ["1.0" + ",0.0" * 31], 18: ["1.0" + ",0.0" * 63],
        19: ["1.0" + ",0.0" * 127], 20: ["1.0" + ",0.0" * 255], 21: ["12.85,0.08"],
        22: ["2"], 23: ["1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
    }
    default_adds = {
        1: ["9", "3"], 2: ["-3"], 3: ["1.87+1.56j"], # 3: ["0.1+0.1j", "1.87+1.56j"],
        4: ["4.5"], 5: ["0.1"],
        6: ["0.1,0.0,0.0,0.0"], 7: ["0.1,0.0,0.0"], 8: ["0.1+0.1j"], 9: ["2.0"],
        10: ["0.08,0.0,0.0,0.0"], 11: ["0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
        12: ["0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0"], 13: ["0.1" + ",0.0" * 15],
        14: ["0.1+0.2e1"], 15: ["0.1,0.0"], 16: ["0.1,0.0"],
        17: ["1.0" + ",0.0" * 31], 18: ["1.0" + ",0.0" * 63], 19: ["1.0" + ",0.0" * 127],
        20: ["1.0" + ",0.0" * 255], 
        21: ["0.56,1.7"], 
        22: ["1"],
        23: ["0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
    }
    """
    """
    default_starts = {
        1: ["0", "6.58"], 2: ["-1.46"], 3: ["1.50+2.56j"], 4: ["27.59"],
        5: ["7/8"], 6: [".47,1.74,1.69,0.77"], 7: ["0.41,0.89,0.80"],
        8: ["0.22+8.60j"], 9: ["3.30"], 10: ["4.68,1.35,0.66,0.43"],
        11: ["0.85,0.38,0.72,1.82,0.07,0.75,1.11,1.95"], 12: ["1.93,0.11,0.16,0.54,1.47,1.79,1.05,1.10"],
        13: ["0.46"], 14: ["1.0+2.0e1+3.0e12"], 15: ["8.93,0.05"],
        16: ["4.94,3.66"], 
        17: ["2.0" + ",0.0" * 31], 
        18: ["2.0" + ",0.0" * 63],
        19: ["0.68,0.59,1.89,0.26,1.86,1.99,0.48,0.88,0.91,1.74,1.76,0.82,0.83,1.41,0.79,0.75,1.57,0.44,0.66,0.81,0.63,0.94,0.55,0.96,0.40,1.22,1.94,0.42,0.08,0.54,0.51,0.69,0.11,0.58,0.58,1.59,0.45,1.77,0.44,0.70,0.39,0.46,0.03,0.45,1.35,1.29,0.25,1.75,0.78,0.94,1.92,0.20,1.66,1.19,0.63,0.61,1.42,1.26,1.90,1.48,1.04,0.82,1.01,0.13,0.19,0.43,1.20,1.14,0.25,0.97,0.91,1.19,0.49,0.11,0.05,1.09,0.54,0.88,0.06,0.51,0.39,0.52,1.84,0.17,1.50,0.66,0.23,1.13,1.10,1.53,2.00,1.97,1.26,1.37,0.73,1.42,1.94,0.09,1.58,0.23,0.31,1.90,1.17,1.71,1.93,0.68,0.60,1.56,1.01,1.02,1.05,0.48,0.79,0.36,0.23,1.17,0.22,0.15,0.73,1.63,0.31,1.70,1.42,0.89,1.76,0.84,1.67,0.93"], 
        20: ["0.01,0.81,1.35,0.45,0.69,0.94,1.20,0.82,1.20,0.14,0.59,0.25,1.99,0.10,1.11,0.87,1.98,0.58,1.36,0.62,0.65,0.06,0.51,0.67,1.00,1.23,1.28,1.71,0.36,1.44,0.97,0.98,1.53,0.44,0.36,1.59,0.39,0.73,0.41,1.10,0.70,0.90,1.88,1.23,1.36,2.00,1.51,1.55,0.51,0.96,0.63,0.05,0.64,1.32,0.00,1.84,1.15,1.20,0.47,1.23,0.90,0.45,0.67,0.78,1.50,0.37,0.47,1.08,1.93,0.48,1.73,0.06,0.13,0.51,0.61,0.75,0.56,0.43,1.29,0.87,0.51,1.23,0.32,0.24,0.40,0.89,1.73,1.78,1.45,0.33,1.41,0.49,0.49,1.12,1.77,1.54,1.97,0.61,1.88,0.13,1.40,1.87,0.81,1.17,1.20,1.97,1.02,1.35,1.47,0.39,1.01,0.14,0.57,1.66,0.04,1.19,1.94,1.54,0.72,0.03,1.89,0.89,0.24,0.61,0.61,0.81,0.35,1.44,1.76,1.10,0.21,1.35,1.49,0.12,1.04,1.30,1.15,0.61,1.10,0.44,0.10,1.87,1.39,1.49,0.96,0.19,1.11,0.14,0.46,1.61,1.54,1.24,0.50,0.06,1.79,1.04,0.90,0.32,1.36,1.05,0.18,0.44,0.85,1.95,1.79,1.31,0.97,0.73,1.76,0.05,1.80,0.75,1.83,0.58,1.56,0.38,0.77,1.61,0.86,0.91,0.25,0.73,1.69,1.06,0.82,0.32,0.01,0.45,1.66,0.33,0.68,0.39,0.37,1.45,1.69,1.02,0.12,1.17,1.55,0.14,1.90,0.34,1.37,1.61,0.01,0.79,1.41,1.88,0.04,1.69,1.85,0.16,0.59,1.08,1.89,1.11,1.18,1.04,1.42,0.96,1.87,1.05,0.27,0.21,1.32,0.65,0.43,1.31,0.52,1.30,1.59,0.79,1.20,1.38,1.82,1.28,1.65,0.36,0.02,0.03,1.71,1.57,1.94,0.77,1.65,1.53,1.06,1.43,0.58,0.47,0.79,0.28,1.69,1.36,0.01,1.24"], 
        21: ["2"],
        22: ["11"], 
        23: ["0.53,0.32,0.79,0.95,1.11,1.54,0.69,1.23"],
    }
    default_adds = {
        1: ["9", "6.41"], 2: ["-4.42"], 3: ["0.13+1.06j"], 4: ["0.28"], 5: ["4/5"],
        6: ["0.74,0,0,0"], 7: ["0.03,0,0"], 8: ["0.56+1.13j"], 9: ["0.30"],
        10: ["0.08"], 11: ["0.1"],
        12: ["0.03"], 13: ["0.46"],
        14: ["0.1+0.2e1"], 15: ["0.17,0"], 16: ["0.7672"],
        17: ["2.0" + ",0.0" * 31], 18: ["2.0" + ",0.0" * 63], 
        19: ["0.16"],
        20: ["0.04"], 
        21: ["2"], 
        22: ["22"],
        23: ["0.03,0.0,0.0,0.0,0.0,0.0,0.0,0.0"],
    }
    """
    # Eğer tip için bilinen değerler varsa, onlardan rastgele birini seç
    if typ in default_starts:
        start = random.choice(default_starts[typ])
        add = random.choice(default_adds[typ])
        return start, add
    else:
        # Bilinen değer yoksa, eski mantıkla devam et (başlangıç için son çare)
        return "0", "1"


# ============================================================
# 8 Varyasyon Testi (seçenek 2)
# ============================================================
def test_variations(type_num, start, add, iterations=100):
    divisors = [2, 3]
    ask_modes = [True, False]
    inter_modes = [True, False]
    print(
        f"\n🔍 8 VARYASYON TESTİ: Tip={type_num}, start={start}, add={add}, iterasyon={iterations} ana adım\n"
    )
    print(
        f"{'Bölen':<6} {'ASK':<6} {'AraAdım':<8} {'Adım':<8} {'KPN':<6} {'Ratio':<10} {'Başarılı'}"
    )
    print("-" * 75)
    for d in divisors:
        for ap in ask_modes:
            for inc in inter_modes:
                try:
                    seq = get_with_params(
                        kececi_type_choice=type_num,
                        iterations=iterations,
                        start_value_raw=str(start),
                        add_value_raw=str(add),
                        include_intermediate_steps=inc,
                        first_divisor=d,
                        ask_plus_first=ap,
                    )
                    if not seq or len(seq) < 20:
                        print(
                            f"{d:<6} {('+' if ap else '-'):<6} {('Var' if inc else 'Yok'):<8} {len(seq):<8} {'-':<6} {'-':<10} ❌ Kısa dizi"
                        )
                        continue
                    kpn, method = find_kpn(seq)
                    if kpn is None:
                        print(
                            f"{d:<6} {('+' if ap else '-'):<6} {('Var' if inc else 'Yok'):<8} {len(seq):<8} {'-':<6} {'-':<10} ❌ KPN yok"
                        )
                        continue
                    positions = [i for i, x in enumerate(seq) if robust_int(x) == kpn]
                    if len(positions) < 2:
                        print(
                            f"{d:<6} {('+' if ap else '-'):<6} {('Var' if inc else 'Yok'):<8} {len(seq):<8} {kpn:<6} {'-':<10} ❌ Az KPN"
                        )
                        continue
                    gaps = np.diff(positions)
                    max_gap = float(np.max(gaps))
                    n_total = len(seq)
                    bound = (math.log(max(n_total, 100))) ** 2 * 0.5
                    ratio = max_gap / bound if bound > 0 else float("inf")
                    success = ratio < 1
                    ratio_str = f"{ratio:.4f}" if ratio < 1e6 else ">1e6"
                    status = "✅ BAŞARILI" if success else "❌ Ratio≥1"
                    print(
                        f"{d:<6} {('+' if ap else '-'):<6} {('Var' if inc else 'Yok'):<8} {len(seq):<8} {kpn:<6} {ratio_str:<10} {status}"
                    )
                except Exception as e:
                    print(
                        f"{d:<6} {('+' if ap else '-'):<6} {('Var' if inc else 'Yok'):<8} HATA    -      -         ❌ {str(e)[:30]}"
                    )


def safe_digits(obj):
    if isinstance(obj, list):
        return obj
    return obj.digits  # Sadece TernaryNumber için


def safe_decimal(obj):
    if isinstance(obj, list):
        return sum(obj)
    return obj.to_decimal()


def safe_parse(t: int, v: Any) -> Any:
    """Tüm Keçeci tipleri için güvenli parse - %100 hatasız (düzeltilmiş modül ile)"""
    try:
        parser = get_parser(t)
        result = parser(str(v))
        # NEG_REAL (t=2) işaret düzeltmesi
        if t == 2:
            return -abs(float(result))
        # Eğer sonuç karmaşık sayı ise sadece gerçel kısmı al
        if hasattr(result, "real") and hasattr(result, "imag"):
            r = result.real
            if callable(r):
                r = r()
            return float(r)
        return result
    except Exception:
        # En son çare: float’a çevir
        return float(v)


# BULLET-PROOF robust_float - COMPLEX/QUATERNION DESTEKLI
def robust_float(x: Any) -> float:
    """Her Python objesinden float çıkarır - %100 güvenli (metot/property uyumlu)"""
    try:
        # String quaternion kontrolü
        if isinstance(x, str) and any(c in x for c in ["i+", "j+", "k+"]):
            return float(x.split("+")[0])

        # Temel tipler
        if isinstance(x, (int, float)):
            return float(x)

        # Gerçel kısım (property veya metot)
        if hasattr(x, "real"):
            r = x.real
            if callable(r):
                r = r()
            return float(r)

        # __float__ metodu
        if hasattr(x, "__float__"):
            return float(x)

        # Liste / tuple (ilk eleman)
        if isinstance(x, (list, tuple)):
            return float(x[0]) if x else 0.0

        # String ayrıştırma
        if isinstance(x, str):
            x = x.replace("[", "").replace("]", "").replace("i", "")
            return float(x.split("+")[0])

        return float(x)

    except Exception:
        return 0.0


# safe_math
def safe_math(a: Any, b: Any, op: str) -> float:
    """HER ZAMAN float döner - TÜM tipler destekler"""
    sa, sb = robust_float(a), robust_float(b)

    if op == "+":
        return sa + sb
    if op == "-":
        return sa - sb
    if op == "*":
        return sa * sb
    if op == "/":
        return sa / sb if sb != 0 else 0.0
    return 0.0


# FİNAL 23 TÜR TESTİ
print("🎯 Test of Keçeci Numbers/Keçeci Sayıları Testi")
print("T  Tip           +     ×     -     ÷    OK%")
print("-" * 50)

perfect_types = 0
test_cases = [
    (2.5, 1.5, {"+": 4.0, "-": 1.0, "*": 3.75, "/": 1.6667}),
    (3.0, 2.0, {"+": 5.0, "-": 1.0, "*": 6.0, "/": 1.5}),
]

for t in range(1, 24):
    name = TYPE_NAMES[t]
    scores = {"+": 0, "-": 0, "*": 0, "/": 0}

    for a, b, expected in test_cases:
        pa = safe_parse(t, a)
        pb = safe_parse(t, b)

        for op, exp_val in expected.items():
            result = safe_math(pa, pb, op)
            scores[op] += abs(result - exp_val) < 0.1

    total = sum(scores.values())
    rate = total / 8 * 100
    status = "✅" if rate == 100 else f"{rate:.0f}%"

    if rate == 100:
        perfect_types += 1

    print(
        f"{t:2} {name:<12} "
        f"{scores['+'] / 2:>3.1f} {scores['*'] / 2:>3.1f} "
        f"{scores['-'] / 2:>3.1f} {scores['/'] / 2:>3.1f}  {status}"
    )

_op_map = {
    "+": lambda a, b: a + b,
    "-": lambda a, b: a - b,
    "*": lambda a, b: a * b,
    "/": lambda a, b: a / b,
    "**": lambda a, b: a**b,
    "%": lambda a, b: a % b,
}


def _coerce_to_hyper(v, target_cls):
    # Eğer hedef Hypercomplex ise ve v farklı tipteyse dönüştür
    try:
        if target_cls is None:
            return v
        if isinstance(v, target_cls):
            return v
        # try constructor that accepts scalar/list
        return target_cls(v)
    except Exception:
        return v


def apply_step(current, op_str, operand, HyperClass=None):
    """
    current: mevcut değer (ör. HypercomplexNumber veya scalar)
    op_str: '+', '-', '*', '/', '**', '%'
    operand: adım değeri (çeşitli tiplerde)
    HyperClass: HypercomplexNumber sınıfı referansı (import edilip verilmeli)
    """
    logger = logging.getLogger(__name__)
    fn = _op_map.get(op_str)
    if fn is None:
        logger.warning("Bilinmeyen op %r, toplama ile devam ediliyor", op_str)
        fn = _op_map["+"]

    # Eğer current HyperClass ise operandı coerced et
    try:
        if HyperClass is not None and isinstance(current, HyperClass):
            operand_coerced = _coerce_to_hyper(operand, HyperClass)
            try:
                return fn(current, operand_coerced)
            except Exception as e1:
                logger.debug("Direct op failed: %s; trying reversed/opposite", e1)
                # try reversed order for noncommutative ops
                try:
                    return fn(operand_coerced, current)
                except Exception as e2:
                    logger.debug("Reversed op also failed: %s", e2)
                    # fallback: try elementwise numeric on components
                    try:
                        a = (
                            current.coeffs()
                            if hasattr(current, "coeffs")
                            else list(current)
                        )
                        b = (
                            operand_coerced.coeffs()
                            if hasattr(operand_coerced, "coeffs")
                            else list(operand_coerced)
                        )
                        # elementwise apply for common length
                        n = max(len(a), len(b))
                        a = list(a) + [0.0] * (n - len(a))
                        b = list(b) + [0.0] * (n - len(b))
                        res = [
                            (x + y)
                            if op_str == "+"
                            else (x - y)
                            if op_str == "-"
                            else (x * y)
                            if op_str == "*"
                            else (x / y if y != 0 else float("inf"))
                            if op_str == "/"
                            else (x**y)
                            if op_str == "**"
                            else (x % y if y != 0 else x)
                            for x, y in zip(a, b)
                        ]
                        return HyperClass(res, dimension=max(1, len(res)))
                    except Exception as e3:
                        logger.exception("Fallback elementwise failed: %s", e3)
                        return current + operand_coerced  # son çare
        else:
            # current not hyperclass: try direct op (scalars, complex, lists)
            try:
                return fn(current, operand)
            except Exception:
                try:
                    return fn(operand, current)
                except Exception as e:
                    logging.exception("apply_step scalar op failed: %s", e)
                    return current
    except Exception as e:
        logging.exception("apply_step unexpected error: %s", e)
        return current


# Tam sayı bölünebilirlik (mevcut mantık, kesin Fraction yolu)
def is_integer_multiple(x, d, tol=1e-12):
    try:
        if d == 0:
            return False

        # Fraction üzerinden kesin kontrol (Decimal(str(...)) ile)
        def _to_frac(v):
            if isinstance(v, Fraction):
                return v
            if isinstance(v, (int,)):
                return Fraction(v)
            try:
                return Fraction(Decimal(str(v)))
            except Exception:
                return Fraction(float(v))

        q = _to_frac(x) / _to_frac(d)
        return q.denominator == 1
    except Exception:
        # float fallback
        try:
            qf = float(x) / float(d)
            return math.isfinite(qf) and math.isclose(qf, round(qf), abs_tol=tol)
        except Exception:
            return False


# Rasyonel kat kontrolü: quotient rasyonel ve payda <= max_den
def is_rational_multiple_with_maxden(x, d, max_den=20):
    try:
        if d == 0:
            return False
        # Fraction via Decimal to avoid float binary artifacts
        fx = Fraction(Decimal(str(x)))
        fd = Fraction(Decimal(str(d)))
        q = fx / fd
        # normalize sign
        q = Fraction(q.numerator, q.denominator)
        return q.denominator <= max_den
    except Exception:
        # fallback: try float approx then rational_approx
        try:
            qf = float(x) / float(d)
            if not math.isfinite(qf):
                return False
            # try to approximate qf as Fraction with limited denominator
            q_approx = Fraction(qf).limit_denominator(max_den)
            return math.isclose(float(q_approx), qf, rel_tol=1e-12, abs_tol=1e-12)
        except Exception:
            return False


# Yakınlık toleranslı çoklama (x ≈ k * d) — k integer veya rasyonel (opsiyonel)
def is_multiple_with_tolerance(x, d, tol=1e-9, allow_rational=False, max_den=20):
    try:
        if d == 0:
            return False
        qf = float(x) / float(d)
        if not math.isfinite(qf):
            return False
        # integer check
        if math.isclose(qf, round(qf), abs_tol=tol):
            return True
        if allow_rational:
            # try rational approx with limited denominator
            q_approx = Fraction(qf).limit_denominator(max_den)
            return math.isclose(float(q_approx), qf, rel_tol=tol, abs_tol=tol)
        return False
    except Exception:
        return False


def _divisible_by_numeric(x, divisor, tol=1e-12):
    """
    Return True if x is divisible by divisor in numeric sense:
    i.e. q = x / divisor is finite and q is within tol of an integer.
    Works for int, float, Fraction.
    """
    try:
        # handle Fraction exactly
        if isinstance(x, Fraction) and isinstance(divisor, Fraction):
            # x/divisor is Fraction; check denominator divides numerator
            q = x / divisor
            return q.denominator == 1
        # if divisor is Fraction and x numeric
        if isinstance(divisor, Fraction):
            try:
                q = Fraction(x) / divisor
                return q.denominator == 1
            except Exception:
                pass
        # numeric fallback: compute float quotient and test near-integer
        q = float(x) / float(divisor)
        if not math.isfinite(q):
            return False
        return math.isclose(q, round(q), abs_tol=tol)
    except Exception:
        return False


def safe_divide(
    val: Any, divisor: Union[int, float, Fraction], integer_mode: bool = False
) -> Any:
    try:
        # coerce divisor
        if isinstance(divisor, Fraction):
            pass
        elif isinstance(divisor, float) and integer_mode:
            # if divisor is near-integer, use int
            if math.isclose(divisor, round(divisor), abs_tol=1e-12):
                divisor_int = int(round(divisor))
                return (
                    val // divisor_int
                    if hasattr(val, "__floordiv__")
                    else type(val)(int(val) // divisor_int)
                )
            else:
                # integer_mode requested but divisor not integer-like -> fallback to true division
                integer_mode = False

        if integer_mode:
            if hasattr(val, "__floordiv__"):
                return val // int(divisor)
            # iterable fallback...
        else:
            if hasattr(val, "__truediv__"):
                return val / divisor
            # iterable fallback...
    except Exception:
        raise


def Real(x: float) -> HypercomplexNumber:
    """Generate a real number (1D hypercomplex)."""
    return HypercomplexNumber.from_real(x)


def Complex(real: float, imag: float) -> HypercomplexNumber:
    """Generate a complex number (2D hypercomplex)."""
    return HypercomplexNumber.from_complex(real, imag)


def Quaternion(w: float, x: float, y: float, z: float) -> HypercomplexNumber:
    """Generate a quaternion (4D hypercomplex)."""
    return HypercomplexNumber.from_quaternion(w, x, y, z)


def Octonion(*coeffs: float) -> HypercomplexNumber:
    """Generate an octonion (8D hypercomplex)."""
    return HypercomplexNumber.from_octonion(*coeffs)


"""
def Bicomplex(z1_real: float, z1_imag: float, z2_real: float, z2_imag: float) -> BicomplexNumber:
    Generate a bicomplex number.
Argument 1,2 to "BicomplexNumber" has incompatible type "HypercomplexNumber"; expected "complex"  [arg-type]
    z1 = HypercomplexNumber(z1_real, z1_imag, dimension=2)
    z2 = HypercomplexNumber(z2_real, z2_imag, dimension=2)
    return BicomplexNumber(z1, z2)
"""


def Bicomplex(
    z1_real: float, z1_imag: float, z2_real: float, z2_imag: float
) -> BicomplexNumber:
    """Generate a bicomplex number from real/imag parts."""
    # Doğrudan complex sayılar oluştur
    z1 = complex(z1_real, z1_imag)
    z2 = complex(z2_real, z2_imag)
    return BicomplexNumber(z1, z2)


def Neutrosophic(determinate: float, indeterminate: float) -> NeutrosophicNumber:
    """Generate a neutrosophic number."""
    return NeutrosophicNumber(determinate, indeterminate)


def Sedenion(*coeffs) -> HypercomplexNumber:
    """Generate a sedenion."""
    coeffs_tuple = tuple(coeffs)
    if len(coeffs_tuple) != 16:
        coeffs_tuple = coeffs_tuple + (0.0,) * (16 - len(coeffs_tuple))
    return HypercomplexNumber(*coeffs_tuple, dimension=16)


def Pathion(*coeffs) -> HypercomplexNumber:
    """Generate a pathion."""
    coeffs_tuple = tuple(coeffs)
    if len(coeffs_tuple) != 32:
        coeffs_tuple = coeffs_tuple + (0.0,) * (32 - len(coeffs_tuple))
    return HypercomplexNumber(*coeffs_tuple, dimension=32)


def Chingon(*coeffs) -> HypercomplexNumber:
    """Generate a chingon."""
    coeffs_tuple = tuple(coeffs)
    if len(coeffs_tuple) != 64:
        coeffs_tuple = coeffs_tuple + (0.0,) * (64 - len(coeffs_tuple))
    return HypercomplexNumber(*coeffs_tuple, dimension=64)


def Routon(*coeffs) -> HypercomplexNumber:
    """Generate a routon."""
    coeffs_tuple = tuple(coeffs)
    if len(coeffs_tuple) != 128:
        coeffs_tuple = coeffs_tuple + (0.0,) * (128 - len(coeffs_tuple))
    return HypercomplexNumber(*coeffs_tuple, dimension=128)


def Voudon(*coeffs) -> HypercomplexNumber:
    """Generate a voudon."""
    coeffs_tuple = tuple(coeffs)
    if len(coeffs_tuple) != 256:
        coeffs_tuple = coeffs_tuple + (0.0,) * (256 - len(coeffs_tuple))
    return HypercomplexNumber(*coeffs_tuple, dimension=256)


class HCAdapter(logging.LoggerAdapter):
    def process(self, msg, kwargs):
        args = kwargs.get("args", ())
        if args:
            new_args = []
            for a in args:
                if _is_hypercomplex_like(a):
                    new_args.append(format_hypercomplex_value(a))
                else:
                    new_args.append(a)
            kwargs["args"] = tuple(new_args)
        return msg, kwargs


logger = logging.getLogger("kececi")
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler())
hc_logger = HCAdapter(logger, {})
# usage
# hc_logger.info("  %d: %s", i, val) # NameError: name 'i' is not defined


class HypercomplexFormatter(logging.Formatter):
    """
    Formatter that converts Hypercomplex-like objects in record.args to readable strings
    using format_hypercomplex_value before formatting the message.
    """

    def format(self, record):
        try:
            # If args is a tuple/dict, replace Hypercomplex-like entries
            if record.args:
                # handle tuple args
                if isinstance(record.args, tuple):
                    new_args = []
                    for a in record.args:
                        try:
                            if _is_hypercomplex_like(a):
                                new_args.append(format_hypercomplex_value(a))
                            else:
                                new_args.append(a)
                        except Exception:
                            new_args.append(a)
                    record.args = tuple(new_args)
                # handle dict-style args
                elif isinstance(record.args, dict):
                    new_args = {}
                    for k, v in record.args.items():
                        try:
                            if _is_hypercomplex_like(v):
                                new_args[k] = format_hypercomplex_value(v)
                            else:
                                new_args[k] = v
                        except Exception:
                            new_args[k] = v
                    record.args = new_args
        except Exception:
            # swallow formatter errors to avoid breaking logging
            pass
        return super().format(record)


def _is_hypercomplex_like(v):
    # minimal duck-typing: check for common helpers
    for attr in ("to_list", "to_components", "coeffs", "components", "to_summary"):
        if hasattr(v, attr):
            return True
    return False


# install formatter on root logger (or specific logger)
handler = logging.StreamHandler()
handler.setFormatter(HypercomplexFormatter("%(levelname)s: %(message)s"))
root = logging.getLogger()
root.handlers = []  # replace default handlers if desired
root.addHandler(handler)
root.setLevel(logging.INFO)


def format_hypercomplex_value(v, max_components: int = 8) -> str:
    try:
        if hasattr(v, "to_summary") and callable(getattr(v, "to_summary")):
            try:
                return v.to_summary(max_components=max_components)
            except TypeError:
                return v.to_summary()
        if hasattr(v, "to_list") and callable(getattr(v, "to_list")):
            comps = v.to_list()
            return _format_components_list(comps, max_components)
        if hasattr(v, "to_components") and callable(getattr(v, "to_components")):
            comps = v.to_components()
            return _format_components_list(comps, max_components)
        if hasattr(v, "coeffs"):
            c = v.coeffs() if callable(getattr(v, "coeffs")) else v.coeffs
            return _format_components_list(c, max_components)
        if hasattr(v, "__iter__") and not isinstance(v, (str, bytes)):
            return _format_components_list(list(v), max_components)
        if isinstance(v, complex):
            return f"{v.real:.6g}+{v.imag:.6g}j"
        if isinstance(v, (int, float)):
            return f"{v:.6g}"
        return repr(v)
    except Exception:
        try:
            return repr(v)
        except Exception:
            return "<unprintable hypercomplex>"


def _format_components_list(comps, max_components=8):
    try:
        comps = list(comps)
    except Exception:
        return "<non-iterable components>"

    def _fmt(x):
        try:
            if isinstance(x, complex):
                return f"{x.real:.6g}+{x.imag:.6g}j"
            return f"{float(x):.6g}"
        except Exception:
            return str(x)

    shown = [_fmt(c) for c in comps[:max_components]]
    s = ", ".join(shown)
    if len(comps) > max_components:
        s += ", ..."
    try:
        import math

        mag = math.sqrt(
            sum(
                (abs(complex(c)) if isinstance(c, complex) else float(c)) ** 2
                for c in comps
            )
        )
        return f"[{s}] |v|={mag:.6g}"
    except Exception:
        return f"[{s}]"


def _extract_coeffs_list(
    seq: Iterable[Any], complex_mode: str = "real"
) -> List[List[float]]:
    """
    Extract numeric coefficient lists from a sequence of Hypercomplex-like objects.
    complex_mode: 'real' -> use real part of complex components
                  'magnitude' -> use abs() of complex components
    Returns list of lists (samples x components) as floats.
    """
    out = []
    for v in seq:
        try:
            # Prefer explicit helpers
            if hasattr(v, "to_list") and callable(getattr(v, "to_list")):
                comps = v.to_list()
            elif hasattr(v, "to_components") and callable(getattr(v, "to_components")):
                comps = v.to_components()
            elif hasattr(v, "coeffs"):
                c = v.coeffs() if callable(getattr(v, "coeffs")) else v.coeffs
                comps = list(c)
            elif hasattr(v, "components"):
                c = (
                    v.components()
                    if callable(getattr(v, "components"))
                    else v.components
                )
                comps = list(c)
            elif hasattr(v, "__iter__") and not isinstance(v, (str, bytes)):
                comps = list(v)
            else:
                comps = [v]

            # Normalize to floats
            norm = []
            for c in comps:
                if isinstance(c, complex):
                    if complex_mode == "magnitude":
                        norm.append(float(abs(c)))
                    else:
                        # default: real part
                        norm.append(float(c.real))
                else:
                    try:
                        norm.append(float(c))
                    except Exception:
                        # fallback 0.0 for non-numeric entries
                        norm.append(0.0)
            out.append(norm)
        except Exception as e:
            logger.debug("extract coeffs failed for %r: %s", v, e)
            out.append([0.0])
    return out


def _pca_var_sum(pca_obj) -> float:
    """
    Safely return sum of PCA explained variance ratio.
    - Uses pca_obj.explained_variance_ratio_ when available.
    - Returns 0.0 for missing, NaN, infinite or invalid values.
    """
    try:
        arr = getattr(pca_obj, "explained_variance_ratio_", None)
        if arr is None:
            return 0.0
        arr = np.asarray(arr, dtype=float)
        s = float(np.nansum(arr))
        return s if np.isfinite(s) else 0.0
    except Exception:
        return 0.0


def get_numeric_repr(v, max_components=8):
    """
    Return a human-readable numeric representation for v.
    - If v has to_list / to_components / coeffs, use them.
    - If v is iterable, return list.
    - Else return scalar formatted string.
    """
    try:
        # HypercomplexNumber-like
        if hasattr(v, "to_summary") and callable(getattr(v, "to_summary")):
            return v.to_summary(max_components=max_components)
        if hasattr(v, "to_list") and callable(getattr(v, "to_list")):
            return str(v.to_list())
        if hasattr(v, "coeffs"):
            c = v.coeffs() if callable(getattr(v, "coeffs")) else v.coeffs
            return str(list(c))
        # iterable but not string
        if hasattr(v, "__iter__") and not isinstance(v, (str, bytes)):
            try:
                return str([float(x) for x in v])
            except Exception:
                return str(list(v))
        # scalar
        if isinstance(v, complex):
            return f"{v.real:.6g}+{v.imag:.6g}j"
        if isinstance(v, (int, float)):
            return f"{v:.6g}"
        return str(v)
    except Exception:
        return repr(v)


def _safe_float_convert(value: Any) -> float:
    """
    Güvenli float dönüşümü.

    Args:
        value: Dönüştürülecek değer

    Returns:
        Float değeri veya 0.0
    """
    if isinstance(value, (float, int)):
        return float(value)
    elif isinstance(value, complex):
        return float(value.real)  # veya abs(value) seçeneği
    elif isinstance(value, str):
        try:
            return float(value)
        except ValueError:
            # Özel semboller
            value_upper = value.upper().strip()
            if value_upper in ["", "NAN", "NULL", "NONE"]:
                return 0.0
            elif value_upper == "INF" or value_upper == "INFINITY":
                return float("inf")
            elif value_upper == "-INF" or value_upper == "-INFINITY":
                return float("-inf")
            # '+' veya '-' işaretleri
            elif value == "+":
                return 1.0
            elif value == "-":
                return -1.0
            else:
                try:
                    # Karmaşık sayı string'i olabilir
                    if "j" in value or "J" in value:
                        c = complex(value)
                        return float(c.real)
                except ValueError:
                    pass
                return 0.0
    else:
        try:
            return float(value)
        except (ValueError, TypeError):
            return 0.0


# --- Temel yardımcılar ----------------------------------------------------
def _is_numeric_scalar(x: Any) -> bool:
    return isinstance(x, (int, float))


def _coerce_first_component(x: Any) -> float:
    if isinstance(x, (list, tuple)):
        return float(x[0]) if x else 0.0
    if isinstance(x, complex):
        return float(x.real)
    try:
        return float(x)
    except Exception:
        return 0.0


def _get_array_fallback(a: Any, b: Any, op: Callable[[Any, Any], Any]):
    if isinstance(a, (list, tuple)) and _is_numeric_scalar(b):
        return type(a)([op(x, b) for x in a])
    raise TypeError("Unsupported operand types for array fallback")


def _get_operation_symbol(operation: str) -> str:
    symbols = {
        "add": "+",
        "subtract": "-",
        "multiply": "×",
        "divide": "/",
        "mod": "%",
        "power": "^",
    }
    return symbols.get(operation, "?")


# --- Sıfır kontrolü ------------------------------------------------------


def _is_zero(value: Any) -> bool:
    """Check if a value is effectively zero."""
    try:
        if isinstance(value, (int, float)):
            return abs(value) < 1e-12
        if isinstance(value, complex):
            return abs(value) < 1e-12
        if isinstance(value, tuple) or isinstance(value, list):
            return all(_is_zero(v) for v in value)
        if hasattr(value, "__abs__"):
            try:
                return abs(value) < 1e-12
            except Exception:
                pass
        return abs(float(value)) < 1e-12
    except Exception:
        return False


# --- Güvenli float dönüşümleri -------------------------------------------


def _safe_float(value: Any) -> float:
    if isinstance(value, (float, int)):
        return float(value)
    if isinstance(value, complex):
        return float(value.real)
    if isinstance(value, str):
        s = value.strip()
        try:
            return float(s)
        except ValueError:
            su = s.upper()
            if su in ("", "NAN", "NULL", "NONE"):
                return 0.0
            if su in ("INF", "INFINITY"):
                return float("inf")
            if su in ("-INF", "-INFINITY"):
                return float("-inf")
            if s == "+":
                return 1.0
            if s == "-":
                return -1.0
            # karmaşık string varsa gerçek kısmı al
            if "j" in s or "J" in s:
                try:
                    return float(complex(s).real)
                except Exception:
                    return 0.0
            return 0.0
    try:
        return float(value)
    except Exception:
        return 0.0


# --- Güvenli temel işlemler (fallback'ler) -------------------------------


def _safe_divide(a: Any, b: Any) -> Any:
    """Safe division with zero handling and array fallbacks."""
    try:
        if _is_zero(b):
            logger.warning("Division by near-zero value")
            # try to produce an 'infinite' of same shape/type if possible
            try:
                if isinstance(a, (list, tuple)):
                    return type(a)([float("inf")] * len(a))
                if hasattr(type(a), "__call__"):
                    return type(a)(float("inf"))
            except Exception:
                pass
            return float("inf")
        return a / b
    except Exception as e:
        logger.debug("Primary divide failed: %s", e)
        # elementwise for arrays when divisor is scalar
        if isinstance(a, (list, tuple)) and _is_numeric_scalar(b):
            return type(a)([x / b for x in a])
        # try alternative methods
        if hasattr(a, "__truediv__"):
            try:
                return a.__truediv__(b)
            except Exception:
                pass
        if hasattr(a, "divide"):
            try:
                return a.divide(b)
            except Exception:
                pass
        # last resort: convert to float
        try:
            return float(a) / float(b)
        except Exception:
            raise ValueError(f"Cannot divide {type(a)} by {type(b)}")


def _safe_mod(a: Any, b: Any) -> Any:
    """Safe modulo operation with fallbacks."""
    try:
        if _is_zero(b):
            logger.warning("Modulo by near-zero value")
            return a
        return a % b
    except Exception as e:
        logger.debug("Primary mod failed: %s", e)
        if isinstance(a, (list, tuple)) and _is_numeric_scalar(b):
            return type(a)([x % b for x in a])
        if hasattr(a, "__mod__"):
            try:
                return a.__mod__(b)
            except Exception:
                pass
        logger.warning(
            "Modulo operation not defined for type %s, returning original value",
            type(a),
        )
        return a


def _safe_power(a: Any, b: Any) -> Any:
    """Safe power operation with broad type support."""
    try:
        # numeric cases
        if isinstance(a, (int, float)) and isinstance(b, (int, float)):
            if a < 0 and not float(b).is_integer():
                # negative base with non-integer exponent -> complex result
                return cmath.exp(b * cmath.log(a))
            return a**b
        # complex involvement
        if isinstance(a, complex) or isinstance(b, complex):
            return complex(a) ** complex(b)
        # custom __pow__
        if hasattr(a, "__pow__"):
            try:
                return a**b
            except Exception:
                pass
        # array elementwise when exponent is scalar
        if isinstance(a, (list, tuple)) and _is_numeric_scalar(b):
            return type(a)([x**b for x in a])
        # try float conversion
        af = _safe_float(a)
        bf = _safe_float(b)
        if af < 0 and not float(bf).is_integer():
            return cmath.exp(bf * cmath.log(af))
        return af**bf
    except ValueError as e:
        logger.warning("ValueError in power: %s", e)
        try:
            return math.pow(float(a), float(b))
        except Exception:
            try:
                return cmath.exp(float(b) * cmath.log(float(a)))
            except Exception:
                raise ValueError(f"Cannot compute {a} ** {b}")
    except Exception as e:
        logger.error("Unexpected error in power: %s", e)
        # sensible fallbacks for small integer exponents
        try:
            if b == 2:
                return a * a
            if b == 1:
                return a
            if b == 0:
                try:
                    return type(a)(1)
                except Exception:
                    return 1
        except Exception:
            pass
        return a


# --- Keçeci özel güvenli işlemler (type-aware) ---------------------------


def _safe_divide_kececi(a: Any, b: Any, number_type: str = "Unknown") -> Any:
    """
    Safe division for Keçeci numbers.
    """
    if _is_zero(b):
        logger.warning(f"Division by zero in {number_type}")
        if number_type == "Complex":
            return complex(float("inf"), 0)
        if "Neutrosophic" in number_type:
            return (float("inf"), 0.0, 0.0)
        if number_type in ("Quaternion", "Octonion", "Sedenion"):
            try:
                return type(a)(float("inf"))
            except Exception:
                return float("inf")
        return float("inf")
    try:
        return _safe_divide(a, b)
    except Exception:
        # try object-specific methods
        if hasattr(a, "divide"):
            try:
                return a.divide(b)
            except Exception:
                pass
        raise


def _safe_mod_kececi(a: Any, b: Any, number_type: str = "Unknown") -> Any:
    """
    Safe modulo for Keçeci numbers.
    """
    if _is_zero(b):
        logger.warning(f"Modulo by zero in {number_type}")
        return a
    try:
        return _safe_mod(a, b)
    except Exception:
        if hasattr(a, "mod"):
            try:
                return a.mod(b)
            except Exception:
                pass
        logger.warning(
            "Modulo operation not defined for %s, returning original", number_type
        )
        return a


def _safe_power_kececi(a: Any, b: Any, number_type: str = "Unknown") -> Any:
    """
    Safe power for Keçeci numbers.
    """
    try:
        return _safe_power(a, b)
    except Exception:
        if hasattr(a, "power"):
            try:
                return a.power(b)
            except Exception:
                pass
        # common fallbacks
        if isinstance(b, (int, float)):
            if b == 2:
                return a * a
            if b == 1:
                return a
            if b == 0:
                try:
                    return type(a)(1)
                except Exception:
                    return 1
        raise ValueError(f"Power operation not supported for {number_type}")


# --- Genel uygulayıcı ----------------------------------------------------
def _apply_kececi_operation(
    a: Any, b: Any, operation: str, number_type: str = "Unknown"
) -> Any:
    """
    Apply operation to Keçeci numbers with proper type handling and fallbacks.
    Supported operations: add, subtract, multiply, divide, mod, power
    """
    try:
        if operation == "add":
            return a + b
        if operation == "subtract":
            return a - b
        if operation == "multiply":
            return a * b
        if operation == "divide":
            return _safe_divide_kececi(a, b, number_type)
        if operation == "mod":
            return _safe_mod_kececi(a, b, number_type)
        if operation == "power":
            return _safe_power_kececi(a, b, number_type)
        raise ValueError(f"Unsupported operation: {operation}")
    except Exception as e:
        logger.debug("Standard %s failed: %s, trying alternatives", operation, e)
        # try object methods
        method_map = {
            "add": ("add",),
            "subtract": ("subtract",),
            "multiply": ("multiply",),
            "divide": ("divide",),
            "mod": ("mod", "__mod__"),
            "power": ("power", "__pow__"),
        }
        for method_name in method_map.get(operation, ()):
            if hasattr(a, method_name):
                try:
                    return getattr(a, method_name)(b)
                except Exception:
                    continue
        # array elementwise fallback when b is scalar
        if isinstance(a, (list, tuple)) and _is_numeric_scalar(b):
            if operation == "add":
                return type(a)([x + b for x in a])
            if operation == "subtract":
                return type(a)([x - b for x in a])
            if operation == "multiply":
                return type(a)([x * b for x in a])
            if operation == "divide":
                return type(a)([x / b for x in a])
            if operation == "mod":
                return type(a)([x % b for x in a])
            if operation == "power":
                return type(a)([x**b for x in a])
        raise


# --- Basit sembol yardımcı fonksiyonu -----------------------------------
def get_operation_symbol(operation: str) -> str:
    return _get_operation_symbol(operation)


def _generate_sequence(
    start_value: Any,
    add_value: Any,
    iterations: int,
    operation: str,
    include_intermediate_steps: bool = True,
) -> List[Any]:
    """
    Generate a sequence based on the operation.

    Args:
        start_value: Starting value
        add_value: Value to use in operation
        iterations: Number of iterations
        operation: Operation to perform
        include_intermediate_steps: Whether to include intermediate steps

    Returns:
        List of generated values. If include_intermediate_steps=True,
        returns a list of dictionaries with step information.
    """

    if include_intermediate_steps:
        # Detaylı log için dictionary listesi
        detailed_result: List[Dict[str, Any]] = []

        # Başlangıç değerini ekle
        detailed_result.append(
            {
                "step": 0,
                "operation": "start",
                "value": start_value,
                "description": f"Start: {start_value}",
            }
        )

        current = start_value

        for i in range(1, iterations):
            try:
                previous = current

                # İşlemi gerçekleştir
                if operation == "add":
                    current = current + add_value
                    op_symbol = "+"
                elif operation == "multiply":
                    current = current * add_value
                    op_symbol = "×"
                elif operation == "subtract":
                    current = current - add_value
                    op_symbol = "-"
                elif operation == "divide":
                    current = _safe_divide(current, add_value)
                    op_symbol = "/"
                elif operation == "mod":
                    current = _safe_mod(current, add_value)
                    op_symbol = "%"
                elif operation == "power":
                    current = _safe_power(current, add_value)
                    op_symbol = "^"
                else:
                    raise ValueError(f"Unsupported operation: {operation}")

                # Detaylı log ekle
                detailed_result.append(
                    {
                        "step": i,
                        "operation": operation,
                        "previous": previous,
                        "value": current,
                        "description": f"Step {i}: {previous} {op_symbol} {add_value} = {current}",
                    }
                )

            except Exception as e:
                logger.warning(f"Error at iteration {i}: {e}")

                # Hata durumunda default değer
                default_val = _generate_default_value(current)

                detailed_result.append(
                    {
                        "step": i,
                        "operation": operation,
                        "error": str(e),
                        "value": default_val,
                        "description": f"Step {i}: ERROR - {e}",
                    }
                )

                current = default_val

        return detailed_result  # Dictionary listesi döndür

    else:
        # Basit liste (sadece değerler)
        simple_result: List[Any] = [start_value]
        current = start_value

        for i in range(1, iterations):
            try:
                # İşlemi gerçekleştir
                if operation == "add":
                    current = current + add_value
                elif operation == "multiply":
                    current = current * add_value
                elif operation == "subtract":
                    current = current - add_value
                elif operation == "divide":
                    current = _safe_divide(current, add_value)
                elif operation == "mod":
                    current = _safe_mod(current, add_value)
                elif operation == "power":
                    current = _safe_power(current, add_value)
                else:
                    raise ValueError(f"Unsupported operation: {operation}")

                simple_result.append(current)

            except Exception as e:
                logger.warning(f"Error at iteration {i}: {e}")

                # Hata durumunda default değer
                default_val = _generate_default_value(current)
                simple_result.append(default_val)
                current = default_val

        return simple_result  # Basit liste döndür


# Daha basit ve güvenli versiyon (alternatif)
def generate_sequence_safe(
    start_value: Any,
    add_value: Any,
    iterations: int,
    operation: str,
    include_intermediate_steps: bool = True,
) -> Union[List[Any], List[Dict[str, Any]]]:
    """
    Safer version with separate return types.
    """
    if include_intermediate_steps:
        return _generate_detailed_sequence(
            start_value, add_value, iterations, operation
        )
    else:
        return _generate_simple_sequence(start_value, add_value, iterations, operation)


def _generate_detailed_sequence(
    start_value: Any, add_value: Any, iterations: int, operation: str
) -> List[Dict[str, Any]]:
    """Generate detailed sequence with step information."""
    result: List[Dict[str, Any]] = []

    result.append(
        {
            "step": 0,
            "operation": "start",
            "value": start_value,
            "description": f"Start: {start_value}",
        }
    )

    current = start_value

    for i in range(1, iterations):
        try:
            previous = current

            if operation == "add":
                current = current + add_value
                op_symbol = "+"
            elif operation == "multiply":
                current = current * add_value
                op_symbol = "×"
            elif operation == "subtract":
                current = current - add_value
                op_symbol = "-"
            elif operation == "divide":
                current = _safe_divide(current, add_value)
                op_symbol = "/"
            elif operation == "mod":
                current = _safe_mod(current, add_value)
                op_symbol = "%"
            elif operation == "power":
                current = _safe_power(current, add_value)
                op_symbol = "^"
            else:
                raise ValueError(f"Unsupported operation: {operation}")

            result.append(
                {
                    "step": i,
                    "operation": operation,
                    "previous": previous,
                    "value": current,
                    "description": f"Step {i}: {previous} {op_symbol} {add_value} = {current}",
                }
            )

        except Exception as e:
            logger.warning(f"Error at iteration {i}: {e}")

            # Generate appropriate default value
            default_val = _generate_default_value(current)

            result.append(
                {
                    "step": i,
                    "operation": operation,
                    "error": str(e),
                    "value": default_val,
                    "description": f"Step {i}: ERROR - {e}",
                }
            )

            current = default_val

    return result


def _generate_simple_sequence(
    start_value: Any, add_value: Any, iterations: int, operation: str
) -> List[Any]:
    """Generate simple sequence of values."""
    result: List[Any] = [start_value]
    current = start_value

    for i in range(1, iterations):
        try:
            if operation == "add":
                current = current + add_value
            elif operation == "multiply":
                current = current * add_value
            elif operation == "subtract":
                current = current - add_value
            elif operation == "divide":
                current = _safe_divide(current, add_value)
            elif operation == "mod":
                current = _safe_mod(current, add_value)
            elif operation == "power":
                current = _safe_power(current, add_value)
            else:
                raise ValueError(f"Unsupported operation: {operation}")

            result.append(current)

        except Exception as e:
            logger.warning(f"Error at iteration {i}: {e}")

            # Generate appropriate default value
            default_val = _generate_default_value(current)
            result.append(default_val)
            current = default_val

    return result


def _generate_default_value(current_value: Any) -> Any:
    """Generate appropriate default value based on current value type."""
    try:
        if hasattr(type(current_value), "__call__"):
            return type(current_value)()
        elif isinstance(current_value, (int, float)):
            return 0
        elif isinstance(current_value, complex):
            return complex(0, 0)
        elif isinstance(current_value, str):
            return ""
        elif isinstance(current_value, (list, tuple)):
            return type(current_value)()
        else:
            # Try to get real part if exists
            try:
                if hasattr(current_value, "real"):
                    return type(current_value)(0)
            except:
                pass

            return 0
    except Exception:
        return 0


# Alternatif olarak, tüm işlemleri tek bir fonksiyonda yöneten basit versiyon
def apply_operation(a: Any, b: Any, operation: str) -> Any:
    """
    Apply an operation between two values with proper error handling.

    Args:
        a: First value
        b: Second value
        operation: Operation to apply ('add', 'subtract', 'multiply', 'divide', 'mod', 'power')

    Returns:
        Result of the operation
    """
    if operation == "add":
        return a + b
    elif operation == "subtract":
        return a - b
    elif operation == "multiply":
        return a * b
    elif operation == "divide":
        return _safe_divide(a, b)
    elif operation == "mod":
        return _safe_mod(a, b)
    elif operation == "power":
        return _safe_power(a, b)
    else:
        raise ValueError(f"Unsupported operation: {operation}")


# Grafik çizimi için yardımcı fonksiyon
def extract_values_for_plotting(sequence: List[Any]) -> List[float]:
    """
    Extract numeric values from sequence for plotting.

    Args:
        sequence: Sequence generated by _generate_sequence

    Returns:
        List of float values suitable for plotting
    """
    values: List[float] = []

    for item in sequence:
        try:
            if isinstance(item, dict):
                # Dictionary'den 'value' anahtarını al
                value = item.get("value", 0)
            else:
                value = item

            # Float'a çevirmeye çalış
            if isinstance(value, (int, float, complex)):
                if isinstance(value, complex):
                    # Complex için magnitude
                    values.append(abs(value))
                else:
                    values.append(float(value))
            elif hasattr(value, "real"):
                # real attribute'u olan nesneler için
                values.append(float(value.real))
            else:
                # String veya diğer tipler için
                try:
                    values.append(float(str(value)))
                except (ValueError, TypeError):
                    values.append(0.0)

        except Exception as e:
            logger.debug(f"Error extracting value for plotting: {e}")
            values.append(0.0)

    return values


def get_random_types_batch(
    num_types: int = 5,
    iterations_per_type: int = 5,
    start_value_raw: Union[str, float, int] = "0",
    add_value_raw: Union[str, float, int] = "1.0",
    seed: Optional[int] = None,
) -> dict:
    """
    Generate multiple random types in one batch.

    Args:
        num_types: Number of different types to generate
        iterations_per_type: Iterations per type
        start_value_raw: Starting value
        add_value_raw: Value to add
        seed: Random seed

    Returns:
        Dictionary with type names as keys and lists as values
    """
    if seed is not None:
        random.seed(seed)

    type_names_list = [
        "Positive Real",
        "Negative Real",
        "Complex",
        "Float",
        "Rational",
        "Quaternion",
        "Neutrosophic",
        "Neutrosophic Complex",
        "Hyperreal",
        "Bicomplex",
        "Neutrosophic Bicomplex",
        "Octonion",
        "Sedenion",
        "Clifford",
        "Dual",
        "Split-Complex",
        "Pathion",
        "Chingon",
        "Routon",
        "Voudon",
        "Super Real",
        "Ternary",
        "Hypercomplex",
    ]

    # Select random types without replacement
    available_types = list(range(1, len(type_names_list) + 1))
    selected_types = random.sample(
        available_types, min(num_types, len(available_types))
    )

    results = {}

    for type_choice in selected_types:
        type_name = type_names_list[type_choice - 1]
        try:
            numbers = get_with_params(
                kececi_type_choice=type_choice,
                iterations=iterations_per_type,
                start_value_raw=str(start_value_raw),
                add_value_raw=str(add_value_raw),
            )
            results[type_name] = numbers
        except Exception as e:
            logger.error(f"Failed to generate type {type_name}: {e}")
            results[type_name] = []

    return results


def _parse_complex_like_string(s: str) -> List[float]:
    """
    Karmaşık sayı benzeri string'i float listesine çevirir.
    Örnek: "1+2i-3j+4k" -> [1.0, 2.0, -3.0, 4.0, ...]
    """
    if not s:
        return [0.0]

    # Normalize et
    s = s.replace(" ", "").replace("J", "j").replace("I", "j").upper()

    # Tüm imajiner birimleri normalize et
    units = [
        "J",
        "I",
        "K",
        "E",
        "F",
        "G",
        "H",
        "L",
        "M",
        "N",
        "O",
        "P",
        "Q",
        "R",
        "S",
        "T",
    ]

    # İlk bileşen (reel kısım)
    result = [0.0] * (len(units) + 1)

    # Reel kısmı bul
    pattern = r"^([+-]?\d*\.?\d*)(?![" + "".join(units) + "])"
    match = re.match(pattern, s)
    if match and match.group(1):
        result[0] = _safe_float_convert(match.group(1))

    # Her bir imajiner birim için
    for i, unit in enumerate(units, 1):
        pattern = r"([+-]?\d*\.?\d*)" + re.escape(unit)
        matches = re.findall(pattern, s)
        if matches:
            # Son eşleşmeyi al (tekrarlanmışsa)
            last_match = matches[-1]
            result[i] = _safe_float_convert(last_match)

    return result


def _parse_engineering_notation(s: str) -> float:
    """Parse engineering notation (1.5k, 2.3m, etc.)"""
    import re

    s = s.strip().lower()

    # Mühendislik çarpanları
    multipliers = {
        "k": 1e3,
        "m": 1e-3,
        "meg": 1e6,
        "g": 1e9,
        "t": 1e12,
        "μ": 1e-6,
        "u": 1e-6,
        "n": 1e-9,
        "p": 1e-12,
        "f": 1e-15,
        "a": 1e-18,
        "mil": 1000,  # thousand
    }

    # Regex pattern
    pattern = r"^([+-]?\d*\.?\d+)\s*([a-zμ]+)?$"
    match = re.match(pattern, s)

    if match:
        try:
            value = float(match.group(1))
            unit = match.group(2) or ""

            if unit in multipliers:
                return value * multipliers[unit]
            elif unit == "":
                return value

            # Özel birimler
            if unit.startswith("e"):
                # 1.5e-3 gibi
                return float(s)
        except (ValueError, KeyError):
            pass

    # Standart float dönüşümü
    return float(s)


def _parse_fraction(s: Union[str, float, int]) -> float:
    """
    Parse fraction strings like '1353/2791' or mixed numbers like '1 1/2'
    """
    if isinstance(s, (int, float)):
        return float(s)

    s_str = str(s).strip()

    # Empty string
    if not s_str:
        return 0.0

    # Already a float string
    try:
        return float(s_str)
    except ValueError:
        pass

    # Check for mixed numbers like "1 1/2"
    if " " in s_str and "/" in s_str:
        try:
            whole_part, frac_part = s_str.split(" ", 1)
            whole = float(whole_part) if whole_part else 0.0
            num, den = frac_part.split("/")
            fraction = float(num) / float(den) if float(den) != 0 else 0.0
            return whole + fraction
        except (ValueError, ZeroDivisionError):
            pass

    # Check for simple fractions like "1353/2791"
    if "/" in s_str:
        try:
            num, den = s_str.split("/")
            # Handle both integer and float numerator/denominator
            numerator = float(num) if "." in num else int(num)
            denominator = float(den) if "." in den else int(den)
            if denominator == 0:
                logger.warning(f"Division by zero in fraction: {s_str}")
                return float("inf") if numerator >= 0 else float("-inf")
            return numerator / denominator
        except (ValueError, ZeroDivisionError):
            pass

    # Try using Fraction class for more robust parsing
    try:
        return float(Fraction(s_str))
    except (ValueError, ZeroDivisionError):
        logger.warning(f"Could not parse as fraction: {s_str}")

    # Last resort
    try:
        return float(s_str)
    except ValueError:
        logger.error(f"Failed to parse numeric value: {s_str}")
        raise ValueError(f"Invalid numeric format: {s_str}")


def _parse_super_real(s: Any) -> float:
    """
    Parse input as super real/hyperreal number with extended support.

    Supports:
    - Standard real numbers: 3.14, -2.5, etc.
    - Infinity representations: ∞, inf, infinity
    - Infinitesimals: ε, epsilon, dx, dt
    - Scientific notation: 1.23e-4, 5.67E+8
    - Engineering notation: 1.5k, 2.3M, 4.7m (k=1e3, M=1e6, m=1e-3, etc.)
    - Fractions: 1/2, 3/4, etc.
    - Mixed numbers: 1 1/2, 2 3/4
    - Percentage: 50%, 12.5%
    - Special constants: π, pi, e, φ, phi
    - Hypercomplex numbers (extract real part)

    Returns:
        float: Parsed real number (always float, never int)
    """
    import math
    import re
    import warnings

    try:
        # 1. Direkt sayısal tipler
        if isinstance(s, (int, float)):
            return float(s)

        # 2. Kompleks sayılar (reel kısmı al)
        if isinstance(s, complex):
            return float(s.real)

        # 3. HypercomplexNumber tipini kontrol et
        if hasattr(s, "__class__") and s.__class__.__name__ == "HypercomplexNumber":
            try:
                return float(s.real)
            except AttributeError:
                pass

        # 4. String'e dönüştür
        if not isinstance(s, str):
            s = str(s)

        s_original = s  # Orijinal string'i sakla
        s = s.strip().lower()

        # 5. Özel durumlar/boş giriş
        if s in ["", "nan", "null", "none", "undefined"]:
            return 0.0

        # 6. Sonsuzluk değerleri
        infinity_patterns = {
            "∞": float("inf"),
            "inf": float("inf"),
            "infinity": float("inf"),
            "+∞": float("inf"),
            "+inf": float("inf"),
            "+infinity": float("inf"),
            "-∞": float("-inf"),
            "-inf": float("-inf"),
            "-infinity": float("-inf"),
        }

        if s in infinity_patterns:
            return infinity_patterns[s]

        # 7. Bilimsel sabitler
        constants = {
            "π": math.pi,
            "pi": math.pi,
            "e": math.e,
            "φ": (1 + math.sqrt(5)) / 2,  # Altın oran
            "phi": (1 + math.sqrt(5)) / 2,
            "tau": 2 * math.pi,
            "γ": 0.5772156649015329,  # Euler-Mascheroni sabiti
        }

        if s in constants:
            return constants[s]

        # 8. Mühendislik notasyonu (k, M, G, m, μ, n, p, etc.)
        engineering_units = {
            "k": 1e3,  # kilo
            "m": 1e-3,  # milli (küçük m)
            "meg": 1e6,  # mega
            "g": 1e9,  # giga
            "t": 1e12,  # tera
            "μ": 1e-6,  # mikro
            "u": 1e-6,  # mikro (alternatif)
            "n": 1e-9,  # nano
            "p": 1e-12,  # piko
            "f": 1e-15,  # femto
            "a": 1e-18,  # atto
        }

        # Mühendislik notasyonu regex'i (case-insensitive)
        eng_match = re.match(r"^\s*([+-]?\d*\.?\d+)\s*([a-zA-Zμ]+)\s*$", s_original)
        if eng_match:
            try:
                value = float(eng_match.group(1))
                unit = eng_match.group(2).lower()

                if unit in engineering_units:
                    return value * engineering_units[unit]
                elif unit == "mil":  # bin (thousand)
                    return value * 1000
            except (ValueError, KeyError):
                pass

        # 9. Yüzde notasyonu
        if s.endswith("%"):
            try:
                # Orijinal string'den % işaretini kaldır (büyük/küçük harf fark etmez)
                value_str = s_original.rstrip("%").strip()
                value = float(value_str)
                return value / 100.0
            except ValueError:
                pass

        # 10. Kesirler ve karışık sayılar
        # Karışık sayı: "1 1/2"
        mixed_match = re.match(r"^\s*(\d+)\s+(\d+)/(\d+)\s*$", s)
        if mixed_match:
            try:
                whole = int(mixed_match.group(1))
                num = int(mixed_match.group(2))
                den = int(mixed_match.group(3))
                return float(whole) + (float(num) / float(den))
            except (ValueError, ZeroDivisionError):
                pass

        # Basit kesir: "3/4"
        if "/" in s and " " not in s:
            try:
                parts = s.split("/")
                if len(parts) == 2:
                    num = float(parts[0])
                    den = float(parts[1])
                    if den != 0:
                        result = num / den
                        return float(result)  # Açıkça float
            except (ValueError, ZeroDivisionError) as e:
                warnings.warn(
                    f"Fraction parse failed: {e}", RuntimeWarning, stacklevel=2
                )
                return 0.0

        # 11. Infinitesimal notasyonu (ε, epsilon, dx, etc.)
        infinitesimals = {
            "ε": 1e-10,
            "epsilon": 1e-10,
            "δ": 1e-10,
            "delta": 1e-10,
            "dx": 1e-10,
            "dt": 1e-10,
            "dh": 1e-10,
            "infinitesimal": 1e-15,
        }

        if s in infinitesimals:
            return infinitesimals[s]

        # 12. Parantez içindeki ifadeler
        if "(" in s and ")" in s:
            # İçeriği al ve tekrar dene
            inner_start = s.find("(") + 1
            inner_end = s.find(")")
            if inner_start < inner_end:
                inner = s[inner_start:inner_end].strip()
                if inner:
                    try:
                        return _parse_super_real(inner)
                    except:
                        pass

        # 13. Standart float dönüşümü (son çare)
        try:
            # Bilimsel notasyon desteği
            return float(s)
        except ValueError:
            # Romawi rakamları
            roman_numerals = {
                "i": 1,
                "ii": 2,
                "iii": 3,
                "iv": 4,
                "v": 5,
                "vi": 6,
                "vii": 7,
                "viii": 8,
                "ix": 9,
                "x": 10,
            }
            if s in roman_numerals:
                return float(roman_numerals[s])

    except Exception as e:
        warnings.warn(
            f"Super real parse error for '{s}': {e}", RuntimeWarning, stacklevel=2
        )

    # 14. Hiçbir şey işe yaramazsa
    return 0.0


def is_super_real_expression(expr: str) -> bool:
    """Check if string looks like a super real expression."""
    super_real_indicators = [
        "∞",
        "inf",
        "epsilon",
        "ε",
        "δ",
        "dx",
        "dt",
        "pi",
        "π",
        "e",
        "phi",
        "φ",
        "tau",
        "γ",
        "k",
        "m",
        "meg",
        "g",
        "t",
        "μ",
        "n",
        "p",
        "%",
        "/",
    ]

    expr_lower = expr.lower()
    return any(indicator in expr_lower for indicator in super_real_indicators)


def normalize_super_real(value: float) -> float:
    """Normalize super real values (e.g., replace very small numbers with 0)."""
    EPSILON = 1e-15

    if abs(value) < EPSILON:
        return 0.0
    elif math.isinf(value):
        return float("inf") if value > 0 else float("-inf")
    else:
        return value


class ComplexNumber:
    """Complex number implementation."""

    def __init__(self, real: float, imag: float = 0.0):
        self._real = float(real)
        self._imag = float(imag)

    @property
    def real(self) -> float:
        return self._real

    @property
    def imag(self) -> float:
        return self._imag

    def __add__(self, other):
        if isinstance(other, ComplexNumber):
            return ComplexNumber(self.real + other.real, self.imag + other.imag)
        elif isinstance(other, (int, float)):
            return ComplexNumber(self.real + float(other), self.imag)
        elif isinstance(other, complex):
            return ComplexNumber(self.real + other.real, self.imag + other.imag)
        return NotImplemented
        if isinstance(other, (int, float)):
            other = self.__class__(other, 0, ...)  # scalar genişlet
        return super().__add__(other)

    def __radd__(self, other):
        return self.__add__(other)

    def __sub__(self, other):
        if isinstance(other, ComplexNumber):
            return ComplexNumber(self.real - other.real, self.imag - other.imag)
        elif isinstance(other, (int, float)):
            return ComplexNumber(self.real - float(other), self.imag)
        elif isinstance(other, complex):
            return ComplexNumber(self.real - other.real, self.imag - other.imag)
        return NotImplemented

    def __rsub__(self, other):
        if isinstance(other, (int, float)):
            return ComplexNumber(float(other) - self.real, -self.imag)
        elif isinstance(other, complex):
            return ComplexNumber(other.real - self.real, other.imag - self.imag)
        return NotImplemented

    def __mul__(self, other):
        if isinstance(other, ComplexNumber):
            real = self.real * other.real - self.imag * other.imag
            imag = self.real * other.imag + self.imag * other.real
            return ComplexNumber(real, imag)
        elif isinstance(other, (int, float)):
            return ComplexNumber(self.real * float(other), self.imag * float(other))
        elif isinstance(other, complex):
            return self * ComplexNumber(other.real, other.imag)
        return NotImplemented

    def __rmul__(self, other):
        return self.__mul__(other)

    def __truediv__(self, other):

        if isinstance(other, ComplexNumber):
            denominator = other.norm() ** 2
            if denominator == 0:
                raise ZeroDivisionError("Division by zero")
            conj = other.conjugate()
            result = self * conj
            return ComplexNumber(result.real / denominator, result.imag / denominator)
        elif isinstance(other, (int, float)):
            if float(other) == 0:
                raise ZeroDivisionError("Division by zero")
            return ComplexNumber(self.real / float(other), self.imag / float(other))
        elif isinstance(other, complex):
            return self / ComplexNumber(other.real, other.imag)
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])
        return NotImplemented

    def __rtruediv__(self, other):
        if isinstance(other, (int, float)):
            return ComplexNumber(float(other), 0) / self
        elif isinstance(other, complex):
            return ComplexNumber(other.real, other.imag) / self
        return NotImplemented

    def __neg__(self):
        return ComplexNumber(-self.real, -self.imag)

    def __pos__(self):
        return self

    def __abs__(self):
        return self.norm()

    def __eq__(self, other):
        if isinstance(other, ComplexNumber):
            return math.isclose(self.real, other.real) and math.isclose(
                self.imag, other.imag
            )
        elif isinstance(other, (int, float)):
            return math.isclose(self.real, float(other)) and math.isclose(self.imag, 0)
        elif isinstance(other, complex):
            return math.isclose(self.real, other.real) and math.isclose(
                self.imag, other.imag
            )
        return False

    def __ne__(self, other):
        return not self.__eq__(other)

    def __hash__(self):
        return hash((round(self.real, 12), round(self.imag, 12)))

    def __repr__(self):
        return f"ComplexNumber({self.real}, {self.imag})"

    def __str__(self):
        if self.imag >= 0:
            return f"{self.real} + {self.imag}i"
        else:
            return f"{self.real} - {-self.imag}i"

    def norm(self) -> float:
        return math.sqrt(self.real**2 + self.imag**2)

    def conjugate(self):
        return ComplexNumber(self.real, -self.imag)

    def to_complex(self) -> complex:
        return complex(self.real, self.imag)

    def to_hypercomplex(self) -> "HypercomplexNumber":
        """Convert to HypercomplexNumber."""
        return HypercomplexNumber(self.real, self.imag, dimension=2)


# aktif kullanımı güncel kodda yok (eski kodlarda var)
def _find_kececi_prime_number(sequence: List[Any]) -> Optional[Any]:
    """
    Find a Keçeci Prime Number in the sequence.
    This is a placeholder implementation - customize based on your definition.

    Args:
        sequence: List of generated numbers

    Returns:
        The first Keçeci Prime Number found, or None
    """
    if not sequence:
        return None

    # Placeholder: Look for numbers with special properties
    # This should be customized based on your specific definition of KPN
    for num in sequence:
        try:
            # Example: Check if magnitude is prime (for complex-like numbers)
            if hasattr(num, "magnitude"):
                mag = float(num.magnitude())
                if mag > 1 and all(mag % i != 0 for i in range(2, int(mag**0.5) + 1)):
                    return num

            # Example: Check real part for floats
            elif isinstance(num, (int, float)):
                if num > 1 and all(num % i != 0 for i in range(2, int(num**0.5) + 1)):
                    return num

            # Add more checks for other number types...

        except Exception:
            continue

    return None


def _float_mod_zero(x: Any, divisor: int, tol: float = 1e-12) -> bool:
    """
    Check if float value is divisible by divisor within tolerance.

    Args:
        x: Value to check
        divisor: Divisor
        tol: Tolerance

    Returns:
        True if divisible, False otherwise
    """
    try:
        # Convert to float
        float_val = float(x)
        # Calculate remainder
        remainder = float_val % divisor
        # Check if remainder is close to 0 or close to divisor
        return math.isclose(remainder, 0.0, abs_tol=tol) or math.isclose(
            remainder, float(divisor), abs_tol=tol
        )
    except Exception:
        return False


def _safe_divide(a: Any, b: Any) -> Any:
    """Safe division with zero handling and better type support."""
    try:
        # First, check if we're dealing with zero division
        if hasattr(b, "__float__"):
            b_float = float(b)
            if abs(b_float) < 1e-12:  # Near zero threshold
                logger.warning(f"Division by near-zero value: {b}")

                # Handle infinity based on type
                if hasattr(a, "__class__") and hasattr(a.__class__, "__call__"):
                    try:
                        # Try to create infinity of the same type
                        if hasattr(a, "__mul__"):
                            # For types that support multiplication
                            try:
                                inf_val = float("inf")
                                # Check if type can handle infinity
                                if hasattr(type(a)(1), "__mul__"):
                                    return type(a)(1) * inf_val
                            except:
                                pass

                        # Try alternative: return maximum value of type
                        if hasattr(a, "max_value"):
                            return a.max_value()
                    except:
                        pass

                # Default fallback
                return (
                    type(a)(float("inf"))
                    if hasattr(type(a), "__call__")
                    else float("inf")
                )

        # Special handling for complex numbers
        if isinstance(a, complex) or isinstance(b, complex):
            try:
                return complex(a) / complex(b)
            except ZeroDivisionError:
                return complex(float("inf"), 0)

        # Special handling for Fraction type
        if "Fraction" in str(type(a)) or "Fraction" in str(type(b)):
            try:
                from fractions import Fraction

                a_frac = Fraction(str(a)) if not isinstance(a, Fraction) else a
                b_frac = Fraction(str(b)) if not isinstance(b, Fraction) else b
                return a_frac / b_frac
            except:
                pass

        # For custom number types that might have their own division
        if hasattr(a, "__truediv__"):
            try:
                return a.__truediv__(b)
            except:
                pass

        if hasattr(a, "__div__"):
            try:
                return a.__div__(b)
            except:
                pass

        # Standard division for numeric types
        return a / b

    except ZeroDivisionError:
        logger.warning(f"ZeroDivisionError: {a} / {b}")
        # Try to return appropriate infinity
        try:
            # Get sign of a
            if hasattr(a, "__float__"):
                a_float = float(a)
                inf_val = float("inf") if a_float >= 0 else float("-inf")
            else:
                inf_val = float("inf")

            # Try to convert to same type as a
            if hasattr(type(a), "__call__"):
                return type(a)(inf_val)
            return inf_val
        except:
            return float("inf")

    except TypeError as e:
        logger.warning(f"TypeError in division {a} / {b}: {e}")
        # Try to convert to compatible types
        try:
            # Convert both to float if possible
            a_float = float(a) if hasattr(a, "__float__") else a
            b_float = float(b) if hasattr(b, "__float__") else b
            return a_float / b_float
        except:
            # If conversion fails, try string-based approach for fractions
            try:
                from fractions import Fraction

                a_str = str(a)
                b_str = str(b)
                result = Fraction(a_str) / Fraction(b_str)
                # Convert back to original type if possible
                if hasattr(type(a), "__call__"):
                    try:
                        return type(a)(float(result))
                    except:
                        return type(a)(str(result))
                return float(result)
            except:
                raise ValueError(f"Cannot divide {type(a)} by {type(b)}")

    except Exception as e:
        logger.error(f"Unexpected error in division: {e}")
        return a  # Return original as fallback


def to_scalar(value):
    """Her türlü sayıyı skaler float'a çevir."""
    if isinstance(value, (int, float)):
        return float(value)
    elif isinstance(value, (list, tuple)):
        # İlk elemanı al (recursive)
        return to_scalar(value[0]) if value else 0.0
    elif hasattr(value, "real"):  # complex, quaternion vb.
        return float(value.real)
    elif hasattr(value, "a"):  # özel sınıflar
        return float(value.a)
    else:
        try:
            return float(value)
        except:
            return 0.0


# Kullanım:
# float_vals = [to_scalar(x) for x in sequence]


# Daha iyi mod fonksiyonu
def _safe_mod(a: Any, b: Any) -> Any:
    """Safe modulo operation with better type support."""
    try:
        # Check for zero
        if hasattr(b, "__float__"):
            b_float = float(b)
            if abs(b_float) < 1e-12:
                logger.warning(f"Modulo by near-zero value: {b}")
                raise ZeroDivisionError("Modulo by (near) zero")

        # Special handling for integers and floats
        if isinstance(a, (int, float)) and isinstance(b, (int, float)):
            return a % b

        # For custom types with __mod__ method
        if hasattr(a, "__mod__"):
            return a % b

        # For complex numbers, modulus returns magnitude
        if isinstance(a, complex):
            return abs(a) % abs(b) if isinstance(b, complex) else abs(a) % b

        # Try to convert to float
        a_float = float(a) if hasattr(a, "__float__") else a
        b_float = float(b) if hasattr(b, "__float__") else b

        return a_float % b_float

    except ZeroDivisionError:
        logger.warning(f"Modulo by zero: {a} % {b}")
        # For modulo by zero, return the dividend (mathematical convention in some systems)
        return a

    except TypeError as e:
        logger.warning(f"TypeError in modulo {a} % {b}: {e}")
        # Try alternative approaches
        try:
            # Convert to decimal
            from decimal import Decimal

            a_dec = Decimal(str(a))
            b_dec = Decimal(str(b))
            if b_dec == 0:
                return a_dec
            # Python Decimal doesn't have % operator, use remainder method
            return float(a_dec % b_dec)
        except:
            # Last resort: return a
            return a

    except Exception as e:
        logger.error(f"Unexpected error in modulo: {e}")
        return a


# ===== GLOBAL FONKSİYONLAR =====
def chingon_zeros() -> ChingonNumber:
    """Sıfır ChingonNumber"""
    return ChingonNumber.zeros()


def chingon_ones() -> ChingonNumber:
    """Birler ChingonNumber"""
    return ChingonNumber.ones()


def chingon_eye(index: int) -> ChingonNumber:
    """Birim vektör"""
    return ChingonNumber.eye(index)


def chingon_random(
    low: float = -1.0, high: float = 1.0, seed: Optional[int] = None
) -> ChingonNumber:
    """Rastgele ChingonNumber"""
    return ChingonNumber.random(low, high, seed)


def chingon_linspace(
    start: Union[float, ChingonNumber], end: Union[float, ChingonNumber], num: int = 64
) -> List[ChingonNumber]:
    """Doğrusal uzay oluştur"""
    if not isinstance(start, ChingonNumber):
        start = ChingonNumber.from_scalar(start)
    if not isinstance(end, ChingonNumber):
        end = ChingonNumber.from_scalar(end)

    result: List[ChingonNumber] = []
    for i in range(num):
        t = i / (num - 1) if num > 1 else 0
        result.append((1 - t) * start + t * end)

    return result


def chingon_dot(a: ChingonNumber, b: ChingonNumber) -> float:
    """İki ChingonNumber'ın iç çarpımı"""
    return a.dot(b)


def chingon_cross(a: ChingonNumber, b: ChingonNumber) -> ChingonNumber:
    """İki ChingonNumber'ın çapraz çarpımı"""
    return a.cross(b)


def chingon_norm(cn: ChingonNumber) -> float:
    """ChingonNumber'ın normu"""
    return cn.norm()


def chingon_normalize(cn: ChingonNumber) -> ChingonNumber:
    """ChingonNumber'ı normalize et"""
    return cn.normalize()


def chingon_unit_vector(index: int) -> ChingonNumber:
    """Belirtilen indekste 1, diğerlerinde 0 olan birim vektör"""
    if index < 0 or index >= 64:
        raise IndexError(f"Index {index} out of range for 64-component ChingonNumber")
    coeffs = [0.0] * 64
    coeffs[index] = 1.0
    return ChingonNumber(coeffs)


# Yardımcı fonksiyon: Sequence'i temizle
def clean_sequence_for_plotting(sequence: List[Any]) -> List[Any]:
    """
    Her türlü sequence'i plot fonksiyonu için temizler.
    """
    if not sequence:
        return []

    # Eğer dictionary listesi ise
    if isinstance(sequence[0], dict):
        cleaned = []
        for item in sequence:
            if isinstance(item, dict):
                # Önce 'value' anahtarını ara
                for key in ["value", "result", "numeric_value", "added", "modified"]:
                    if key in item:
                        cleaned.append(item[key])
                        break
                else:
                    cleaned.append(0)
            else:
                cleaned.append(item)
        sequence = cleaned

    # String, tuple, list içeriyorsa temizle
    cleaned_sequence = []
    for item in sequence:
        cleaned_sequence.append(extract_numeric_value(item))

    return cleaned_sequence


def extract_numeric_value(item: Any) -> float:
    """
    Her türlü değerden sayısal değer çıkar.
    Tüm dönüşümler float tipinde olacak.
    """
    # 1. Doğrudan sayısal tipler
    if isinstance(item, (int, float)):
        return float(item)

    # 2. Fraction tipi
    if isinstance(item, Fraction):
        return float(item)

    # 3. Decimal tipi
    if isinstance(item, Decimal):
        return float(item)

    # 4. Complex sayılar (sadece gerçek kısmı)
    if isinstance(item, complex):
        return float(item.real)

    # 5. String işleme
    if isinstance(item, str):
        item = item.strip()
        if not item:
            return 0.0

        # Kesir kontrolü
        if "/" in item:
            try:
                # Örnek: "3/4", "1 1/2"
                if " " in item:  # Karışık sayı: "1 1/2"
                    whole, fraction = item.split(" ", 1)
                    num, den = fraction.split("/")
                    return float(whole) + (float(num) / float(den))
                else:  # Basit kesir: "3/4"
                    num, den = item.split("/")
                    return float(num) / float(den)
            except (ValueError, ZeroDivisionError):
                pass

        # Normal sayısal dize
        try:
            # Bilimsel gösterim ve diğer formatları da destekle
            return float(item)
        except (ValueError, TypeError):
            return 0.0

    # 6. Dizi/Iterable tipler
    if isinstance(item, (tuple, list, set)):
        for element in item:
            value = extract_numeric_value(element)
            if value != 0:
                return value
        return 0.0

    # 7. Diğer tipler için deneme
    try:
        return float(item)
    except (ValueError, TypeError, AttributeError):
        return 0.0


def extract_numeric_values(sequence: List[Any], strict: bool = False) -> List[float]:
    """
    Her türlü değerden sayısal değerleri çıkar.

    Args:
        sequence: İşlenecek dizi
        strict: True ise, dönüştürülemeyen değerler için ValueError fırlatır

    Returns:
        Sayısal değerler listesi
    """
    result: List[float] = []

    for item in sequence:
        try:
            value = extract_numeric_value(item)
            result.append(value)
        except Exception as e:
            if strict:
                raise ValueError(
                    f"Failed to extract numeric value from {item!r}"
                ) from e
            result.append(0.0)

    return result


# Ek yardımcı fonksiyonlar
def extract_clean_numbers(
    sequence: List[Any], remove_zeros: bool = False
) -> List[float]:
    """
    Temiz sayısal değerleri çıkar ve opsiyonel olarak sıfırları kaldır.
    """
    values = extract_numeric_values(sequence)
    if remove_zeros:
        values = [v for v in values if v != 0]
    return values


def find_first_numeric(sequence: List[Any]) -> Optional[float]:
    """
    Dizideki ilk geçerli sayısal değeri bulur.
    """
    for item in sequence:
        value = extract_numeric_value(item)
        if value != 0:
            return value
    return None


def extract_fraction_values(
    sequence: List[Any],
) -> tuple[List[float], List[int], List[int]]:
    """Safely extract values from Fraction sequence."""
    float_vals: List[float] = []
    numerators: List[int] = []
    denominators: List[int] = []

    for item in sequence:
        if isinstance(item, Fraction):
            float_vals.append(float(item))
            numerators.append(item.numerator)
            denominators.append(item.denominator)
        else:
            # Diğer tipler için fallback
            try:
                float_vals.append(float(item))
                # Fraction olmadığı için pay/payda uydur
                if isinstance(item, (int, float)):
                    numerators.append(int(item))
                    denominators.append(1)
                else:
                    numerators.append(0)
                    denominators.append(1)
            except (ValueError, TypeError):
                float_vals.append(0.0)
                numerators.append(0)
                denominators.append(1)

    return float_vals, numerators, denominators


def extract_complex_values(
    sequence: List[Any],
) -> tuple[List[float], List[float], List[float]]:
    """Safely extract complex values."""
    real_parts: List[float] = []
    imag_parts: List[float] = []
    magnitudes: List[float] = []

    for item in sequence:
        if isinstance(item, complex):
            real_parts.append(float(item.real))
            imag_parts.append(float(item.imag))
            magnitudes.append(float(abs(item)))
        else:
            # Complex değilse sıfır ekle
            real_parts.append(0.0)
            imag_parts.append(0.0)
            magnitudes.append(0.0)

    return real_parts, imag_parts, magnitudes


# Fabrika fonksiyonları
def neutrosophic_zero() -> NeutrosophicNumber:
    """Sıfır Nötrosofik sayı"""
    return NeutrosophicNumber(0, 0, 0)


def neutrosophic_one() -> NeutrosophicNumber:
    """Bir Nötrosofik sayı"""
    return NeutrosophicNumber(1, 0, 0)


def neutrosophic_i() -> NeutrosophicNumber:
    """Belirsizlik birimi"""
    return NeutrosophicNumber(0, 1, 0)


def neutrosophic_f() -> NeutrosophicNumber:
    """Yanlışlık birimi"""
    return NeutrosophicNumber(0, 0, 1)


def parse_to_hyperreal(s: Any) -> "HyperrealNumber":
    """Parse to Hyperreal object directly"""

    if TYPE_CHECKING:
        from .kececinumbers import HyperrealNumber

    finite, infinitesimal, seq = _parse_hyperreal(s)
    return HyperrealNumber(sequence=seq)


# Yardımcı fonksiyonlar
def parse_to_neutrosophic(s: Any) -> "NeutrosophicNumber":
    """Parse to NeutrosophicNumber object directly"""

    if TYPE_CHECKING:
        from .kececinumbers import NeutrosophicNumber

    t, i, f = _parse_neutrosophic(s)
    return NeutrosophicNumber(t, i, f)


# ==============================================================================
# --- CUSTOM NUMBER CLASS DEFINITIONS ---
# ==============================================================================
# ---------- Cayley-Dickson tabanlı HypercomplexNumber (geliştirilmiş) ----


class HypercomplexNumber:
    """
    Unified wrapper for Cayley-Dickson hypercomplex numbers with flexible input.
    - Accepts scalar, iterable, or string inputs.
    - Supports dimensions that are powers of two up to 256 (1,2,4,8,...,256).
    - Uses project's cayley_dickson_algebra for algebraic multiplication/division when available.
    - Falls back to elementwise operations for scalar/iterable cases.
    """

    DIMENSION_NAMES = {
        1: "Real",
        2: "Complex",
        4: "Quaternion",
        8: "Octonion",
        16: "Sedenion",
        32: "Pathion",
        64: "Chingon",
        128: "Routon",
        256: "Voudon",
    }
    _cd_classes = {}

    def __init__(self, components: Any = None, *, dimension: Optional[int] = None):
        # parse components flexibly
        comps = _parse_components(components)
        # infer dimension if not provided: smallest power of two >= len(comps) or default 1
        if dimension is None:
            n = max(1, len(comps))
            dim = 1
            while dim < n:
                dim <<= 1
        else:
            dim = int(dimension)
            if dim not in self.DIMENSION_NAMES and dim not in (
                1,
                2,
                4,
                8,
                16,
                32,
                64,
                128,
                256,
            ):
                raise ValueError("Dimension must be a power of two up to 256")
        self.dimension = dim
        # pad/truncate components
        if len(comps) < dim:
            comps = comps + [0.0] * (dim - len(comps))
        elif len(comps) > dim:
            comps = comps[:dim]
        self._comps = [
            complex(c) if isinstance(c, complex) else float(c) for c in comps
        ]
        # try to create CD class and cd_number if available
        try:
            from .cd_helpers import cayley_dickson_algebra  # project helper

            level = int(math.log2(self.dimension))
            if self.dimension not in self._cd_classes:
                self._cd_classes[self.dimension] = cayley_dickson_algebra(level, float)
            cd_cls = self._cd_classes[self.dimension]
            self._cd_number = cd_cls(*self._comps)
            self._has_cd = True
        except Exception:
            # no CD algebra available; operate elementwise
            self._cd_number = None
            self._has_cd = False

    # Bunun yerine property ekleyin (eğer yoksa)
    @property
    def coeffs(self):
        return list(self._comps)

    @property
    def real(self) -> float:
        return float(self._comps[0]) if self._comps else 0.0

    @property
    def imag(self) -> List[Number]:
        return self._comps[1:]

    def __len__(self) -> int:
        return self.dimension

    def to_list(self) -> List[float]:
        """Return components as plain Python list of floats (complex -> real part)."""
        out = []
        for c in self.coeffs:  # artık property, parantez yok
            try:
                # if complex, keep complex; plotting code will decide how to handle
                out.append(float(c.real) if isinstance(c, complex) else float(c))
            except Exception:
                try:
                    out.append(float(c))
                except Exception:
                    out.append(0.0)
        return out

    def fixed_to_list(self):
        out = []
        for c in self.coeffs:  # artık property, parantez yok
            try:
                out.append(float(c.real) if isinstance(c, complex) else float(c))
            except Exception:
                try:
                    out.append(float(c))
                except Exception:
                    out.append(0.0)
        return out

    @property
    def components(self):
        """HypercomplexNumber bileşenlerini liste olarak döndürür."""
        return self.coeffs  # self.coeffs zaten liste (property)

    def to_summary(self, max_components: int = 8) -> str:
        """Human-friendly short summary: first components and magnitude."""
        comps = self.to_list()
        shown = comps[:max_components]
        comps_str = ", ".join(f"{x:.6g}" for x in shown)
        if len(comps) > max_components:
            comps_str += ", ..."
        try:
            mag = self.norm()
            return f"[{comps_str}] |v|={mag:.6g}"
        except Exception:
            return f"[{comps_str}]"

    def copy(self) -> "HypercomplexNumber":
        return HypercomplexNumber(self.coeffs(), dimension=self.dimension)

    # --- internal helpers for dimension alignment ---
    def _align_with(self, other: Any) -> Tuple[List[Number], List[Number], int]:
        if isinstance(other, HypercomplexNumber):
            dim = max(self.dimension, other.dimension)
            a = self.coeffs + [0.0] * (dim - self.dimension)  # parantez kalktı
            b = other.coeffs + [0.0] * (dim - other.dimension)  # parantez kalktı
            return a, b, dim
        other_comps = _parse_components(other)
        dim = max(self.dimension, max(1, len(other_comps)))
        a = self.coeffs + [0.0] * (dim - self.dimension)
        b = (
            (other_comps + [0.0] * (dim - len(other_comps)))
            if other_comps
            else [other] + [0.0] * (dim - 1)
        )
        return a, b, dim

    def __truediv__(self, other: Any) -> "HypercomplexNumber":
        # scalar division
        if isinstance(other, (int, float, complex)):
            if _is_zero(other):
                raise ZeroDivisionError("Division by zero")
            return HypercomplexNumber(
                [x / other for x in self.coeffs], dimension=self.dimension
            )  # parantez kalktı
        # CD division if possible
        if isinstance(other, HypercomplexNumber) and self._has_cd and other._has_cd:
            if self.dimension != other.dimension:
                common = max(self.dimension, other.dimension)
                return self.pad_to_dimension(common) / other.pad_to_dimension(common)
            res_cd = self._cd_number / other._cd_number
            return HypercomplexNumber.from_cd_number(res_cd)
        # elementwise fallback
        a, b, dim = self._align_with(other)
        res = []
        for x, y in zip(a, b):
            if _is_zero(y):
                res.append(float("inf"))
            else:
                res.append(x / y)
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])  # parantez kalktı
        return HypercomplexNumber(res, dimension=dim)

    def __mul__(self, other: Any) -> "HypercomplexNumber":
        if isinstance(other, (int, float, complex)):
            return HypercomplexNumber(
                [x * other for x in self.coeffs], dimension=self.dimension
            )

    # --- arithmetic using CD algebra when possible, else elementwise/fallback ---
    def __add__(self, other: Any) -> "HypercomplexNumber":
        if (
            self._has_cd
            and isinstance(other, HypercomplexNumber)
            and other._has_cd
            and self.dimension == other.dimension
        ):
            res_cd = self._cd_number + other._cd_number
            return HypercomplexNumber.from_cd_number(res_cd)
        a, b, dim = self._align_with(other)
        return HypercomplexNumber([x + y for x, y in zip(a, b)], dimension=dim)

    def __radd__(self, other: Any) -> "HypercomplexNumber":
        return self.__add__(other)

    def __sub__(self, other: Any) -> "HypercomplexNumber":
        if (
            self._has_cd
            and isinstance(other, HypercomplexNumber)
            and other._has_cd
            and self.dimension == other.dimension
        ):
            res_cd = self._cd_number - other._cd_number
            return HypercomplexNumber.from_cd_number(res_cd)
        a, b, dim = self._align_with(other)
        return HypercomplexNumber([x - y for x, y in zip(a, b)], dimension=dim)

    def __rsub__(self, other: Any) -> "HypercomplexNumber":
        # other - self
        if isinstance(other, HypercomplexNumber):
            return other.__sub__(self)
        a, b, dim = self._align_with(other)
        return HypercomplexNumber([y - x for x, y in zip(a, b)], dimension=dim)

    def __rmul__(self, other: Any) -> "HypercomplexNumber":
        return self.__mul__(other)

    def __rtruediv__(self, other: Any) -> "HypercomplexNumber":
        if isinstance(other, (int, float, complex)):
            other_coeffs = [other] + [0.0] * (self.dimension - 1)
            return HypercomplexNumber(other_coeffs, dimension=self.dimension) / self
        return NotImplemented

    def __mod__(self, other: Any) -> "HypercomplexNumber":
        # elementwise modulo fallback
        a, b, dim = self._align_with(other)
        res = []
        for x, y in zip(a, b):
            try:
                if _is_zero(y):
                    res.append(x)
                else:
                    res.append(x % y)
            except Exception:
                res.append(x)
        return HypercomplexNumber(res, dimension=dim)

    def __pow__(self, exponent: Any) -> "HypercomplexNumber":
        # elementwise power for scalar exponent
        if isinstance(exponent, (int, float)):
            return HypercomplexNumber(
                [x**exponent for x in self.coeffs()], dimension=self.dimension
            )
        if isinstance(exponent, HypercomplexNumber):
            a, b, dim = self._align_with(exponent)
            return HypercomplexNumber([x**y for x, y in zip(a, b)], dimension=dim)
        raise TypeError("Unsupported exponent type for HypercomplexNumber")

    def __neg__(self) -> "HypercomplexNumber":
        return HypercomplexNumber([-c for c in self.coeffs()], dimension=self.dimension)

    def __abs__(self) -> float:
        # norm: sqrt(sum(|c|^2))
        s = 0.0
        for c in self.coeffs():
            try:
                s += abs(c) ** 2
            except Exception:
                try:
                    s += float(c) ** 2
                except Exception:
                    s += 0.0
        return math.sqrt(s)

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, HypercomplexNumber):
            if self.dimension != other.dimension:
                return False
            # return all(abs(a - b) < 1e-12 for a, b in zip(self.coeffs(), other.coeffs()))
            return all(abs(a - b) < 1e-12 for a, b in zip(self.coeffs, other.coeffs))
        if isinstance(other, (int, float)):
            return abs(self.real - float(other)) < 1e-12 and all(
                abs(c) < 1e-12 for c in self.imag
            )
        return False

    # --- CD helpers and conversions ---
    @classmethod
    def _get_cd_class(cls, dimension: int):
        # lazy load handled in __init__
        return cls._cd_classes.get(dimension)

    @classmethod
    def from_cd_number(cls, cd_number) -> "HypercomplexNumber":
        # cd_number must provide coefficients() and dimensions
        try:
            dim = getattr(cd_number, "dimensions", None) or len(
                cd_number.coefficients()
            )
            comps = list(cd_number.coefficients())
            return cls(comps, dimension=dim)
        except Exception:
            # fallback: try to extract via to_list
            try:
                return cls(cd_number.to_list())
            except Exception:
                raise

    def pad_to_dimension(self, new_dimension: int) -> "HypercomplexNumber":
        if new_dimension < self.dimension:
            raise ValueError("Cannot pad to smaller dimension")
        if new_dimension == self.dimension:
            return self.copy()
        coeffs = self.coeffs() + [0.0] * (new_dimension - self.dimension)
        return HypercomplexNumber(coeffs, dimension=new_dimension)

    def truncate_to_dimension(self, new_dimension: int) -> "HypercomplexNumber":
        if new_dimension > self.dimension:
            raise ValueError("Cannot truncate to larger dimension")
        if new_dimension == self.dimension:
            return self.copy()
        coeffs = self.coeffs()[:new_dimension]
        return HypercomplexNumber(coeffs, dimension=new_dimension)

    # --- algebraic helpers ---
    def conjugate(self) -> "HypercomplexNumber":
        if self._has_cd:
            return HypercomplexNumber.from_cd_number(self._cd_number.conjugate())
        # elementwise conjugate: complex conjugate for each component
        return HypercomplexNumber(
            [
                complex(c).conjugate() if isinstance(c, complex) else c
                for c in self.coeffs()
            ],
            dimension=self.dimension,
        )

    def norm(self) -> float:
        if self._has_cd:
            try:
                return float(self._cd_number.norm())
            except Exception:
                pass
        return abs(self)

    def inverse(self) -> "HypercomplexNumber":
        if self._has_cd:
            return HypercomplexNumber.from_cd_number(self._cd_number.inverse())
        # fallback: elementwise reciprocal where possible
        comps = []
        for c in self.coeffs():
            if _is_zero(c):
                comps.append(float("inf"))
            else:
                comps.append(1.0 / c)
        return HypercomplexNumber(comps, dimension=self.dimension)

    def normalize(self) -> "HypercomplexNumber":
        n = self.norm()
        if _is_zero(n):
            raise ZeroDivisionError("Cannot normalize zero")
        return HypercomplexNumber(
            [c / n for c in self.coeffs()], dimension=self.dimension
        )

    def dot(self, other: Any) -> float:
        if not isinstance(other, HypercomplexNumber):
            other = HypercomplexNumber(other)
        a, b, dim = self._align_with(other)
        return sum((x * y) for x, y in zip(a, b))

    # --- utilities ---
    def to_tuple(self) -> Tuple[Number, ...]:
        return tuple(self.coeffs())

    def to_numpy(self):
        try:
            import numpy as np

            return np.array(self.coeffs(), dtype=float)
        except Exception:
            raise

    def summary(self) -> str:
        non_zero = sum(1 for c in self.coeffs() if abs(c) > 1e-12)
        max_coeff = max((abs(c) for c in self.coeffs()), default=0.0)
        min_non_zero = min((abs(c) for c in self.coeffs() if abs(c) > 0), default=0.0)
        return (
            f"{self.DIMENSION_NAMES.get(self.dimension, f'CD{self.dimension}')} Summary:\n"
            f"  Dimension: {self.dimension}\n"
            f"  Non-zero components: {non_zero}\n"
            f"  Real part: {self.real:.6f}\n"
            f"  Norm: {self.norm():.6f}\n"
            f"  Max component: {max_coeff:.6f}\n"
            f"  Min non-zero: {min_non_zero:.6f}"
        )

    def __str__(self):
        return self.to_summary(max_components=8)

    def __repr__(self):
        return f"HypercomplexNumber({self.to_list()[:8]}{'...' if len(self._comps) > 8 else ''})"

    @property
    def components(self):
        """
        if hasattr(self, 'coeffs'):
            return list(self.coeffs)
        elif hasattr(self, 'to_list'):
            return self.to_list()
        else:
            # Varsayılan olarak self'i liste gibi döndür (tek bileşen)
            return [self]
        """
        if hasattr(self.coeffs, "tolist"):
            return self.coeffs.tolist()
        elif isinstance(self.coeffs, list):
            return self.coeffs
        else:
            return list(self.coeffs)


# ---------- Helper zero check (genel) ------------------------------------
def _is_zero(value: Any) -> bool:
    try:
        if isinstance(value, (int, float)):
            return abs(value) < 1e-12
        if isinstance(value, complex):
            return abs(value) < 1e-12
        if isinstance(value, HypercomplexNumber):
            return all(_is_zero(c) for c in value.coeffs())
        if isinstance(value, (list, tuple)):
            return all(_is_zero(v) for v in value)
        if hasattr(value, "__abs__"):
            try:
                return abs(value) < 1e-12
            except Exception:
                pass
        return abs(float(value)) < 1e-12
    except Exception:
        return False


# --- Yardımcı fonksiyonlar ------------------------------------------------
def _safe_import(name: str):
    try:
        module = __import__(name, fromlist=["*"])
        return module
    except Exception:
        return None


# Try to import sympy if available for robust primality
_sympy = _safe_import("sympy")
if _sympy:
    _sympy_isprime = getattr(_sympy, "isprime", None)
else:
    _sympy_isprime = None


def is_near_integer(x: Any, tol: float = 1e-12) -> bool:
    """
    Bir sayının (veya sayı benzeri nesnenin) tam sayıya yeterince yakın olup olmadığını kontrol eder.
    - Karmaşık sayılar için imajiner kısmın sıfıra yakın, reel kısmın tam sayıya yakın olması gerekir.
    - Liste/demet gibi iterable'lar için False döner (doğrudan sayı değildir).
    - Sayıya çevrilebilen her tür için çalışır.
    """
    try:
        # Karmaşık sayı kontrolü
        if isinstance(x, complex):
            if abs(x.imag) > tol:
                return False
            x = x.real
        elif isinstance(x, (list, tuple)):
            return False  # Dizi tipinde tam sayı kontrolü yapılmaz, ayrıca ele alınır.

        # Genel durum: float'a çevir ve yuvarlamaya yakınlığına bak
        xf = float(x)
        return abs(xf - round(xf)) <= tol
    except Exception:
        return False


"""
def is_near_integer(x, tol=1e-12):

    #Checks if a number (or its real part) is close to an integer.
    #Useful for float-based primality and divisibility checks.

    try:
        if isinstance(x, complex):
            # Sadece gerçek kısım önemli, imajiner sıfıra yakın olmalı
            if abs(x.imag) > tol:
                return False
            x = x.real
        elif isinstance(x, (list, tuple)):
            return False  # Desteklenmeyen tip

        # Genel durum: float veya int
        x = float(x)
        return abs(x - round(x)) < tol
    except:
        return False

def _is_near_integer(x: Any, tol: float = 1e-9) -> bool:
    #Bir sayının neredeyse tam sayı olup olmadığını kontrol et.
    try:
        if isinstance(x, int):
            return True
        xf = float(x)
        return abs(xf - round(xf)) <= tol
    except Exception:
        return False
"""


def _float_mod_zero(x: Any, divisor: int = 1, tol: float = 1e-9) -> bool:
    """x % divisor yaklaşık sıfır mı? (float toleranslı)"""
    try:
        xf = float(x)
        if divisor == 0:
            return False
        return abs(xf - round(xf / divisor) * divisor) <= tol
    except Exception:
        return False


def _int_from_value(value: Any) -> int:
    """
    Değeri tamsayıya çevirmeye çalışır:
    - Eğer HypercomplexNumber veya iterable ise ilk bileşeni alır
    - Eğer string ise sayısal token'ı alır
    - Başarısızsa None döner
    """
    try:
        if value is None:
            return None
        # If object provides integer representation helper
        if hasattr(value, "to_int") and callable(getattr(value, "to_int")):
            try:
                return int(value.to_int())
            except Exception:
                pass
        # If object has coeffs or to_list
        comps = _parse_components(value)
        if comps:
            return int(round(comps[0]))
        # fallback scalar
        if isinstance(value, (int, float)):
            return int(round(float(value)))
        if isinstance(value, complex):
            return int(round(value.real))
        # try direct conversion
        return int(float(str(value)))
    except Exception:
        return None


def _simple_is_prime(n: int) -> bool:
    """Küçük/orta büyüklükte tamsayılar için basit deterministik test."""
    if n < 2:
        return False
    if n in (2, 3):
        return True
    if n % 2 == 0:
        return False
    r = int(math.isqrt(n))
    for i in range(3, r + 1, 2):
        if n % i == 0:
            return False
    return True


# --- Ana birleşik is_prime_like fonksiyonu -------------------------------
def is_prime_like(value: Any, kececi_type: int = None) -> bool:
    """
    Genişletilmiş prime-like testi.
    - Önce proje içi is_prime_like veya is_prime fonksiyonlarını dener.
    - sympy varsa onu kullanır.
    - Quaternion/Hypercomplex/Array-based/ternary/clifford gibi tipler için bileşenleri kontrol eder.
    - kececi_type belirtilirse tip-özel kurallar uygulanır.
    """
    try:
        # 1) Proje içi helper varsa kullan
        try:
            from .kececinumbers import is_prime_like as _proj_ipl

            return bool(
                _proj_ipl(value, kececi_type)
                if _proj_ipl.__code__.co_argcount >= 2
                else _proj_ipl(value)
            )
        except Exception:
            pass

        # 2) Eğer doğrudan integer temsil edilebiliyorsa onu al ve test et
        n = _int_from_value(value)
        if n is not None:
            if _sympy_isprime:
                try:
                    return bool(_sympy_isprime(int(n)))
                except Exception:
                    return _simple_is_prime(int(n))
            else:
                return _simple_is_prime(int(n))

        # 3) Tip bazlı heuristikler (kececi_type varsa)
        # Tip sabitleri proje içinde farklı isimlerde olabilir; burada sayısal kodlar kullanılıyor.
        # Kullanıcının tanımladığı TYPE_* sabitlerini kullanıyorsanız onları import edin veya
        # burada numeric karşılıklarını verin. Örnek: TYPE_HYPERCOMPLEX == 23
        TYPE_QUATERNION = 6
        TYPE_OCTONION = 12
        TYPE_SEDENION = 13
        TYPE_CLIFFORD = 14
        TYPE_PATHION = 17
        TYPE_CHINGON = 18
        TYPE_ROUTON = 19
        TYPE_VOUDON = 20
        TYPE_SUPERREAL = 21
        TYPE_TERNARY = 22
        TYPE_HYPERCOMPLEX = 23

        # Quaternion özel kontrol
        # Quaternion ve diğer tiplerde coeffs alırken:
        if kececi_type == TYPE_QUATERNION:
            try:
                # Eğer metot ise çağır
                if hasattr(value, "coeffs") and callable(value.coeffs):
                    comps = list(value.coeffs())
                elif hasattr(value, "coeffs"):
                    comps = list(value.coeffs)  # property ise direkt
                else:
                    comps = _parse_components(value)
                if not comps:
                    return False
                if not all(is_near_integer(c) for c in comps):
                    return False
                # test first (real) component
                n0 = int(round(float(comps[0])))
                if _sympy_isprime:
                    return bool(_sympy_isprime(n0))
                return _simple_is_prime(n0)
            except Exception:
                return False

        # Daha sonra comps[0]'ı int'e çevirirken:
        if comps:
            first = comps[0]
            # Liste değilse ve sayıya yakınsa
            if not isinstance(first, (list, tuple)):
                if is_near_integer(first):
                    n = int(round(float(first)))
                    # prime test
            else:
                # first bir liste ise, ilk elemanını al
                sub = first[0] if first else 0
                if is_near_integer(sub):
                    n = int(round(float(sub)))

        # Hypercomplex family (octonion, sedenion, pathion, ...)
        if kececi_type in (
            TYPE_OCTONION,
            TYPE_SEDENION,
            TYPE_PATHION,
            TYPE_CHINGON,
            TYPE_ROUTON,
            TYPE_VOUDON,
            TYPE_HYPERCOMPLEX,
        ):
            try:
                # extract coeffs
                if hasattr(value, "coeffs"):
                    coeffs = list(value.coeffs())
                elif hasattr(value, "to_list"):
                    coeffs = list(value.to_list())
                elif isinstance(value, (list, tuple)):
                    coeffs = list(value)
                else:
                    coeffs = _parse_components(value)
                if not coeffs:
                    return False
                if not all(is_near_integer(c) for c in coeffs):
                    return False
                n0 = int(round(float(coeffs[0])))
                if _sympy_isprime:
                    return bool(_sympy_isprime(n0))
                return _simple_is_prime(n0)
            except Exception:
                return False

        # Ternary
        if kececi_type == TYPE_TERNARY:
            try:
                # Ternary sayıyı integer'a çevir
                n = _get_integer_representation(value)
                if n is not None and n > 1:
                    if _sympy_isprime:
                        return bool(_sympy_isprime(n))
                    return _simple_is_prime(n)
                return False
            except Exception:
                return False

        # Clifford
        if kececi_type == TYPE_CLIFFORD:
            try:
                if hasattr(value, "basis") and isinstance(value.basis, dict):
                    scalar = value.basis.get("", 0)
                    if is_near_integer(scalar):
                        n = int(round(float(scalar)))
                        if _sympy_isprime:
                            return bool(_sympy_isprime(n))
                        return _simple_is_prime(n)
                return False
            except Exception:
                return False

        # Superreal
        if kececi_type == TYPE_SUPERREAL:
            try:
                if hasattr(value, "real"):
                    real = getattr(value, "real")
                    if is_near_integer(real):
                        n = int(round(float(real)))
                        if _sympy_isprime:
                            return bool(_sympy_isprime(n))
                        return _simple_is_prime(n)
                return False
            except Exception:
                return False

        # 4) Genel fallback: magnitude veya ilk bileşen üzerinden test et
        try:
            comps = _parse_components(value)
            if not comps:
                return False
            mag = int(abs(round(float(comps[0]))))
            if mag < 2:
                return False
            if _sympy_isprime:
                return bool(_sympy_isprime(mag))
            return _simple_is_prime(mag)
        except Exception:
            return False

    except Exception as e:
        logger.debug("is_prime_like unexpected error: %s", e)
        return False


# ---------- get_unit fonksiyonu ------------------------------
# 9, 10, 11, 14, 15, 16, 21 sayı türleri eklendi
def _get_ask_unit_for_type(number_type: int, sample_value: Any = None) -> Any:
    """
    Get appropriate Keçeci unit for a number type.
    Hypercomplex (23) returns a HypercomplexNumber.unit inferred from sample_value or default dim 8.
    """
    # simple numeric types
    if number_type in [1, 4, 5]:
        return 1.0
    if number_type == 2:
        return -1.0
    if number_type == 3:
        return complex(1, 0)
    if number_type == 6:
        try:
            from .kececinumbers import quaternion

            return quaternion(1, 0, 0, 0)
        except Exception:
            return [1.0, 0.0, 0.0, 0.0]
    if number_type == 7:
        try:
            from .kececinumbers import NeutrosophicNumber

            return NeutrosophicNumber(1, 0, 0)
        except Exception:
            return (1.0, 0.0, 0.0)
    if number_type == 8:
        try:
            from .kececinumbers import NeutrosophicComplexNumber

            return NeutrosophicComplexNumber(1, 0, 0)
        except Exception:
            return complex(1, 0)
    if number_type in [12, 13, 17, 18, 19, 20, 22]:
        sizes = {12: 8, 13: 16, 17: 32, 18: 64, 19: 128, 20: 256, 22: 3}
        size = sizes.get(number_type, 1)
        if sample_value is not None and hasattr(sample_value, "__len__"):
            try:
                size = max(1, len(sample_value))
            except Exception:
                pass
        unit = [0.0] * size
        unit[0] = 1.0
        if sample_value is not None:
            try:
                return type(sample_value)(unit)
            except Exception:
                return unit
        return unit
    if number_type == 23:
        # infer dimension from sample_value if possible, default 8
        dim = 8
        if sample_value is not None:
            try:
                if isinstance(sample_value, HypercomplexNumber):
                    dim = max(1, len(sample_value))
                elif hasattr(sample_value, "__len__"):
                    dim = max(1, len(sample_value))
                else:
                    # if sample is string, parse components
                    comps = _parse_components(sample_value)
                    if comps:
                        dim = max(1, len(comps))
            except Exception:
                pass
        try:
            return HypercomplexNumber([1.0] + [0.0] * (dim - 1), dimension=dim)
        except Exception:
            return [1.0] + [0.0] * (dim - 1)

    if number_type == 9:  # Hyperreal
        return 1.0  # veya HyperrealNumber sınıfı varsa onun birimi
    if number_type == 10:  # Bicomplex
        try:
            from .kececinumbers import BicomplexNumber

            return BicomplexNumber(1, 0, 0, 0)
        except:
            return [1.0, 0.0, 0.0, 0.0]
    if number_type == 11:  # Neutrosophic Bicomplex
        try:
            from .kececinumbers import NeutrosophicBicomplexNumber

            return NeutrosophicBicomplexNumber(1, 0, 0, 0, 0, 0)
        except:
            return [1.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    if number_type == 14:  # Clifford (örnek: 2D)
        # Varsayılan boyut: 3 (skaler, e1, e2)
        return [1.0, 0.0, 0.0]
    if number_type == 15:  # Dual
        try:
            from .kececinumbers import DualNumber

            return DualNumber(1, 0)
        except:
            return [1.0, 0.0]
    if number_type == 16:  # Split Complex
        try:
            from .kececinumbers import SplitComplexNumber

            return SplitComplexNumber(1, 0)
        except:
            return [1.0, 0.0]
    if number_type == 21:  # Super Real (genelde reel)
        return 1.0

    # default fallback
    if sample_value is not None:
        try:
            return type(sample_value)(1)
        except Exception:
            pass
    return 1.0


# Yardımcı Fonksiyonlar:
# Factory functions for specific hypercomplex types
def Real(x: float) -> HypercomplexNumber:
    """Create a real number (dimension 1)."""
    return HypercomplexNumber(x, dimension=1)


def Complex(real: float, imag: float) -> HypercomplexNumber:
    """Create a complex number (dimension 2)."""
    return HypercomplexNumber(real, imag, dimension=2)


def Quaternion(w: float, x: float, y: float, z: float) -> HypercomplexNumber:
    """Create a quaternion (dimension 4)."""
    return HypercomplexNumber(w, x, y, z, dimension=4)


def Octonion(*components) -> HypercomplexNumber:
    """Create an octonion (dimension 8)."""
    if len(components) != 8:
        components = list(components) + [0.0] * (8 - len(components))
    return HypercomplexNumber(*components, dimension=8)


def Sedenion(*components) -> HypercomplexNumber:
    """Create a sedenion (dimension 16)."""
    if len(components) != 16:
        components = list(components) + [0.0] * (16 - len(components))
    return HypercomplexNumber(*components, dimension=16)


def Pathion(*components) -> HypercomplexNumber:
    """Create a pathion (dimension 32)."""
    if len(components) != 32:
        components = list(components) + [0.0] * (32 - len(components))
    return HypercomplexNumber(*components, dimension=32)


def Chingon(*components) -> HypercomplexNumber:
    """Create a chingon (dimension 64)."""
    if len(components) != 64:
        components = list(components) + [0.0] * (64 - len(components))
    return HypercomplexNumber(*components, dimension=64)


def Routon(*components) -> HypercomplexNumber:
    """Create a routon (dimension 128)."""
    if len(components) != 128:
        components = list(components) + [0.0] * (128 - len(components))
    return HypercomplexNumber(*components, dimension=128)


def Voudon(*components) -> HypercomplexNumber:
    """Create a voudon (dimension 256)."""
    if len(components) != 256:
        components = list(components) + [0.0] * (256 - len(components))
    return HypercomplexNumber(*components, dimension=256)


class quaternion:
    """
    Kuaterniyon sınıfı: w + xi + yj + zk formatında

    Attributes:
        w: Reel kısım
        x: i bileşeni
        y: j bileşeni
        z: k bileşeni
    """

    w: float = 1.0
    x: float = 0.0
    y: float = 0.0
    z: float = 0.0

    def __init__(self, w: float = 1.0, x: float = 0.0, y: float = 0.0, z: float = 0.0):
        """
        Kuaterniyon oluşturur.

        Args:
            w: Reel kısım
            x: i bileşeni
            y: j bileşeni
            z: k bileşeni
        """
        self.w = float(w)
        self.x = float(x)
        self.y = float(y)
        self.z = float(z)

    @classmethod
    def from_axis_angle(
        cls,
        axis: Union[List[float], Tuple[float, float, float], np.ndarray],
        angle: float,
    ) -> "quaternion":
        """
        Eksen-açı gösteriminden kuaterniyon oluşturur.

        Args:
            axis: Dönme ekseni (3 boyutlu vektör)
            angle: Radyan cinsinden dönme açısı

        Returns:
            quaternion: Kuaterniyon nesnesi
        """
        axis = np.asarray(axis, dtype=float)
        axis_norm = np.linalg.norm(axis)

        if axis_norm == 0:
            raise ValueError("Eksen vektörü sıfır olamaz")

        axis = axis / axis_norm
        half_angle = angle / 2.0
        sin_half = math.sin(half_angle)

        return cls(
            w=math.cos(half_angle),
            x=axis[0] * sin_half,
            y=axis[1] * sin_half,
            z=axis[2] * sin_half,
        )

    @classmethod
    def from_euler(
        cls, roll: float, pitch: float, yaw: float, order: str = "zyx"
    ) -> "quaternion":
        """
        Euler açılarından kuaterniyon oluşturur.

        Args:
            roll: X ekseni etrafında dönme (radyan)
            pitch: Y ekseni etrafında dönme (radyan)
            yaw: Z ekseni etrafında dönme (radyan)
            order: Dönme sırası ('zyx', 'xyz', 'yxz', vb.)

        Returns:
            quaternion: Kuaterniyon nesnesi
        """
        cy = math.cos(yaw * 0.5)
        sy = math.sin(yaw * 0.5)
        cp = math.cos(pitch * 0.5)
        sp = math.sin(pitch * 0.5)
        cr = math.cos(roll * 0.5)
        sr = math.sin(roll * 0.5)

        if order == "zyx":  # Yaw, Pitch, Roll
            w = cy * cp * cr + sy * sp * sr
            x = cy * cp * sr - sy * sp * cr
            y = sy * cp * sr + cy * sp * cr
            z = sy * cp * cr - cy * sp * sr
        elif order == "xyz":  # Roll, Pitch, Yaw
            w = cr * cp * cy + sr * sp * sy
            x = sr * cp * cy - cr * sp * sy
            y = cr * sp * cy + sr * cp * sy
            z = cr * cp * sy - sr * sp * cy
        else:
            raise ValueError(f"Desteklenmeyen dönme sırası: {order}")

        return cls(w, x, y, z)

    @classmethod
    def from_rotation_matrix(cls, R: np.ndarray) -> "quaternion":
        """
        Dönüşüm matrisinden kuaterniyon oluşturur.

        Args:
            R: 3x3 dönüşüm matrisi

        Returns:
            quaternion: Kuaterniyon nesnesi
        """
        if R.shape != (3, 3):
            raise ValueError("Matris 3x3 boyutunda olmalıdır")

        trace = np.trace(R)

        if trace > 0:
            S = math.sqrt(trace + 1.0) * 2
            w = 0.25 * S
            x = (R[2, 1] - R[1, 2]) / S
            y = (R[0, 2] - R[2, 0]) / S
            z = (R[1, 0] - R[0, 1]) / S
        elif R[0, 0] > R[1, 1] and R[0, 0] > R[2, 2]:
            S = math.sqrt(1.0 + R[0, 0] - R[1, 1] - R[2, 2]) * 2
            w = (R[2, 1] - R[1, 2]) / S
            x = 0.25 * S
            y = (R[0, 1] + R[1, 0]) / S
            z = (R[0, 2] + R[2, 0]) / S
        elif R[1, 1] > R[2, 2]:
            S = math.sqrt(1.0 + R[1, 1] - R[0, 0] - R[2, 2]) * 2
            w = (R[0, 2] - R[2, 0]) / S
            x = (R[0, 1] + R[1, 0]) / S
            y = 0.25 * S
            z = (R[1, 2] + R[2, 1]) / S
        else:
            S = math.sqrt(1.0 + R[2, 2] - R[0, 0] - R[1, 1]) * 2
            w = (R[1, 0] - R[0, 1]) / S
            x = (R[0, 2] + R[2, 0]) / S
            y = (R[1, 2] + R[2, 1]) / S
            z = 0.25 * S

        return cls(w, x, y, z).normalized()

    def conjugate(self) -> "quaternion":
        """Kuaterniyonun eşleniğini döndürür."""
        return quaternion(self.w, -self.x, -self.y, -self.z)

    def norm(self) -> float:
        """Kuaterniyonun normunu döndürür."""
        return math.sqrt(self.w**2 + self.x**2 + self.y**2 + self.z**2)

    def normalized(self) -> "quaternion":
        """Normalize edilmiş kuaterniyonu döndürür."""
        n = self.norm()
        if n == 0:
            return quaternion(1, 0, 0, 0)
        return quaternion(self.w / n, self.x / n, self.y / n, self.z / n)

    def inverse(self) -> "quaternion":
        """Kuaterniyonun tersini döndürür."""
        norm_sq = self.w**2 + self.x**2 + self.y**2 + self.z**2
        if norm_sq == 0:
            return quaternion(1, 0, 0, 0)
        conj = self.conjugate()
        return quaternion(
            conj.w / norm_sq, conj.x / norm_sq, conj.y / norm_sq, conj.z / norm_sq
        )

    def to_axis_angle(self) -> Tuple[np.ndarray, float]:
        """
        Kuaterniyonu eksen-açı gösterimine dönüştürür.

        Returns:
            Tuple[np.ndarray, float]: (eksen, açı)
        """
        if abs(self.w) > 1:
            q = self.normalized()
        else:
            q = self

        angle = 2 * math.acos(q.w)

        if abs(angle) < 1e-10:
            return np.array([1.0, 0.0, 0.0]), 0.0

        s = math.sqrt(1 - q.w**2)
        if s < 1e-10:
            axis = np.array([1.0, 0.0, 0.0])
        else:
            axis = np.array([q.x / s, q.y / s, q.z / s])

        return axis, angle

    def to_euler(self, order: str = "zyx") -> Tuple[float, float, float]:
        """
        Kuaterniyonu Euler açılarına dönüştürür.

        Args:
            order: Dönme sırası

        Returns:
            Tuple[float, float, float]: (roll, pitch, yaw)
        """
        q = self.normalized()

        if order == "zyx":  # Yaw, Pitch, Roll
            # Roll (x-axis rotation)
            sinr_cosp = 2 * (q.w * q.x + q.y * q.z)
            cosr_cosp = 1 - 2 * (q.x**2 + q.y**2)
            roll = math.atan2(sinr_cosp, cosr_cosp)

            # Pitch (y-axis rotation)
            sinp = 2 * (q.w * q.y - q.z * q.x)
            if abs(sinp) >= 1:
                pitch = math.copysign(math.pi / 2, sinp)
            else:
                pitch = math.asin(sinp)

            # Yaw (z-axis rotation)
            siny_cosp = 2 * (q.w * q.z + q.x * q.y)
            cosy_cosp = 1 - 2 * (q.y**2 + q.z**2)
            yaw = math.atan2(siny_cosp, cosy_cosp)

            return roll, pitch, yaw
        else:
            raise ValueError(f"Desteklenmeyen dönme sırası: {order}")

    def to_rotation_matrix(self) -> np.ndarray:
        """
        Kuaterniyonu dönüşüm matrisine dönüştürür.

        Returns:
            np.ndarray: 3x3 dönüşüm matrisi
        """
        q = self.normalized()

        # 3x3 dönüşüm matrisi
        R = np.zeros((3, 3))

        # Matris elemanlarını hesapla
        R[0, 0] = 1 - 2 * (q.y**2 + q.z**2)
        R[0, 1] = 2 * (q.x * q.y - q.w * q.z)
        R[0, 2] = 2 * (q.x * q.z + q.w * q.y)

        R[1, 0] = 2 * (q.x * q.y + q.w * q.z)
        R[1, 1] = 1 - 2 * (q.x**2 + q.z**2)
        R[1, 2] = 2 * (q.y * q.z - q.w * q.x)

        R[2, 0] = 2 * (q.x * q.z - q.w * q.y)
        R[2, 1] = 2 * (q.y * q.z + q.w * q.x)
        R[2, 2] = 1 - 2 * (q.x**2 + q.y**2)

        return R

    def rotate_vector(
        self, v: Union[List[float], Tuple[float, float, float], np.ndarray]
    ) -> np.ndarray:
        """
        Vektörü kuaterniyon ile döndürür.

        Args:
            v: Döndürülecek 3 boyutlu vektör

        Returns:
            np.ndarray: Döndürülmüş vektör
        """
        v = np.asarray(v, dtype=float)
        if v.shape != (3,):
            raise ValueError("Vektör 3 boyutlu olmalıdır")

        q = self.normalized()
        q_vec = np.array([q.x, q.y, q.z])
        q_w = q.w

        # Kuaterniyon çarpımı ile döndürme
        v_rot = v + 2 * np.cross(q_vec, np.cross(q_vec, v) + q_w * v)
        return v_rot

    def slerp(self, other: "quaternion", t: float) -> "quaternion":
        """
        Küresel lineer interpolasyon (SLERP) yapar.

        Args:
            other: Hedef kuaterniyon
            t: İnterpolasyon parametresi [0, 1]

        Returns:
            quaternion: İnterpole edilmiş kuaterniyon
        """
        if t <= 0:
            return self.normalized()
        if t >= 1:
            return other.normalized()

        q1 = self.normalized()
        q2 = other.normalized()

        # Nokta çarpım
        cos_half_theta = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z

        # Eğer q1 ve q2 aynı yöndeyse
        if abs(cos_half_theta) >= 1.0:
            return q1

        # Eğer negatif nokta çarpım, kuaterniyonları ters çevir
        if cos_half_theta < 0:
            q2 = quaternion(-q2.w, -q2.x, -q2.y, -q2.z)
            cos_half_theta = -cos_half_theta

        half_theta = math.acos(cos_half_theta)
        sin_half_theta = math.sqrt(1.0 - cos_half_theta**2)

        if abs(sin_half_theta) < 1e-10:
            return quaternion(
                q1.w * 0.5 + q2.w * 0.5,
                q1.x * 0.5 + q2.x * 0.5,
                q1.y * 0.5 + q2.y * 0.5,
                q1.z * 0.5 + q2.z * 0.5,
            ).normalized()

        ratio_a = math.sin((1 - t) * half_theta) / sin_half_theta
        ratio_b = math.sin(t * half_theta) / sin_half_theta

        return quaternion(
            q1.w * ratio_a + q2.w * ratio_b,
            q1.x * ratio_a + q2.x * ratio_b,
            q1.y * ratio_a + q2.y * ratio_b,
            q1.z * ratio_a + q2.z * ratio_b,
        ).normalized()

    def __add__(self, other: "quaternion") -> "quaternion":
        """Kuaterniyon toplama."""
        if isinstance(other, quaternion):
            return quaternion(
                self.w + other.w, self.x + other.x, self.y + other.y, self.z + other.z
            )
        raise TypeError("Sadece quaternion ile toplanabilir")

    def __sub__(self, other: "quaternion") -> "quaternion":
        """Kuaterniyon çıkarma."""
        if isinstance(other, quaternion):
            return quaternion(
                self.w - other.w, self.x - other.x, self.y - other.y, self.z - other.z
            )
        raise TypeError("Sadece quaternion ile çıkarılabilir")

    def __mul__(self, other: Union["quaternion", float, int]) -> "quaternion":
        """Kuaterniyon çarpma veya skaler çarpma."""
        if isinstance(other, (int, float)):
            return quaternion(
                self.w * other, self.x * other, self.y * other, self.z * other
            )
        elif isinstance(other, quaternion):
            # Hamilton çarpımı
            w = (
                self.w * other.w
                - self.x * other.x
                - self.y * other.y
                - self.z * other.z
            )
            x = (
                self.w * other.x
                + self.x * other.w
                + self.y * other.z
                - self.z * other.y
            )
            y = (
                self.w * other.y
                - self.x * other.z
                + self.y * other.w
                + self.z * other.x
            )
            z = (
                self.w * other.z
                + self.x * other.y
                - self.y * other.x
                + self.z * other.w
            )
            return quaternion(w, x, y, z)
        raise TypeError("Sadece quaternion veya skaler ile çarpılabilir")

    def __rmul__(self, other: Union[float, int]) -> "quaternion":
        """Sağ taraftan skaler çarpma."""
        return self.__mul__(other)

    def __truediv__(self, other: Union[float, int]) -> "quaternion":
        """Skaler bölme."""
        if isinstance(other, (int, float)):
            if other == 0:
                raise ZeroDivisionError("Sıfıra bölme hatası")
            return quaternion(
                self.w / other, self.x / other, self.y / other, self.z / other
            )
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])
        raise TypeError("Sadece skaler ile bölünebilir")

    def __eq__(self, other: "quaternion") -> bool:
        """Eşitlik kontrolü."""
        if isinstance(other, quaternion):
            return (
                math.isclose(self.w, other.w)
                and math.isclose(self.x, other.x)
                and math.isclose(self.y, other.y)
                and math.isclose(self.z, other.z)
            )
        return False

    def __ne__(self, other: "quaternion") -> bool:
        """Eşitsizlik kontrolü."""
        return not self.__eq__(other)

    def __neg__(self) -> "quaternion":
        """Negatif kuaterniyon."""
        return quaternion(-self.w, -self.x, -self.y, -self.z)

    def __repr__(self) -> str:
        """Nesnenin temsili."""
        return f"quaternion(w={self.w:.6f}, x={self.x:.6f}, y={self.y:.6f}, z={self.z:.6f})"

    def __str__(self) -> str:
        """String temsili."""
        return f"{self.w:.6f} + {self.x:.6f}i + {self.y:.6f}j + {self.z:.6f}k"

    def to_array(self) -> np.ndarray:
        """Kuaterniyonu numpy array'e dönüştürür."""
        return np.array([self.w, self.x, self.y, self.z])

    def to_list(self) -> List[float]:
        """Kuaterniyonu listeye dönüştürür."""
        return [self.w, self.x, self.y, self.z]

    @classmethod
    def identity(cls) -> "quaternion":
        """Birim kuaterniyon döndürür."""
        return cls(1.0, 0.0, 0.0, 0.0)

    def is_identity(self, tolerance: float = 1e-10) -> bool:
        """Birim kuaterniyon olup olmadığını kontrol eder."""
        return (
            abs(self.w - 1.0) < tolerance
            and abs(self.x) < tolerance
            and abs(self.y) < tolerance
            and abs(self.z) < tolerance
        )

    @classmethod
    def parse(cls, s) -> "quaternion":
        """Çeşitli formatlardan quaternion oluşturur.

        Args:
            s: Dönüştürülecek değer

        Returns:
            quaternion: Dönüştürülmüş kuaterniyon
        """
        return _parse_quaternion_from_csv(s)

    @classmethod
    def from_csv_string(cls, s: str) -> "quaternion":
        """CSV string'inden quaternion oluşturur.

        Args:
            s: Virgülle ayrılmış string ("w,x,y,z" veya "scalar")

        Returns:
            quaternion: Dönüştürülmüş kuaterniyon
        """
        return _parse_quaternion_from_csv(s)

    @classmethod
    def from_complex(cls, c: complex) -> "quaternion":
        """Complex sayıdan quaternion oluşturur (sadece gerçek kısım kullanılır).

        Args:
            c: Complex sayı

        Returns:
            quaternion: Dönüştürülmüş kuaterniyon
        """
        return quaternion(float(c.real), 0, 0, 0)


@dataclass
class TernaryNumber:
    digits: List[int]

    def __init__(self, *args):
        """
        Esnek kurucu:
        - Tek argüman liste ise digits olarak al
        - Birden çok sayısal argüman varsa bunları digits listesi yap
        Üçlü sayıyı oluşturur. Verilen değer bir liste olmalıdır.
        :param digits: Üçlü sayının rakamlarını temsil eden liste.
        """
        if len(args) == 1 and isinstance(args[0], (list, tuple)):
            self.digits = list(args[0])
        elif len(args) >= 1:
            self.digits = [int(x) for x in args]
        else:
            self.digits = [0]
        # Rakamların 0-2 arasında olduğunu doğrula
        for d in self.digits:
            if d not in (0, 1, 2):
                raise ValueError("Ternary digits must be 0, 1, or 2")

    @classmethod
    def from_ternary_string(cls, ternary_str: str) -> "TernaryNumber":
        """Üçlü sayı sistemindeki stringi TernaryNumber'a dönüştürür."""
        ternary_str = ternary_str.strip()
        if not all(c in "012" for c in ternary_str):
            raise ValueError("Üçlü sayı sadece 0, 1 ve 2 rakamlarından oluşabilir.")
        digits = [int(c) for c in ternary_str]
        return cls(digits)

    @classmethod
    def from_decimal(cls, decimal: int) -> "TernaryNumber":
        """Ondalık sayıyı üçlü sayı sistemine dönüştürür."""
        if decimal == 0:
            return cls([0])
        digits = []
        while decimal > 0:
            digits.append(decimal % 3)
            decimal = decimal // 3
        return cls(digits[::-1] if digits else [0])

    def to_decimal(self):
        """Üçlü sayının ondalık karşılığını döndürür."""
        decimal_value = 0
        for i, digit in enumerate(reversed(self.digits)):
            decimal_value += digit * (3**i)
        return decimal_value

    def __repr__(self):
        """Nesnenin yazdırılabilir temsilini döndürür."""
        return f"TernaryNumber({self.digits})"

    def __str__(self):
        """Nesnenin string temsilini döndürür."""
        return "".join(map(str, self.digits))

    def __add__(self, other):
        """Toplama işlemini destekler."""
        if isinstance(other, TernaryNumber):
            result_decimal = self.to_decimal() + other.to_decimal()
        elif isinstance(other, (int, str)):
            result_decimal = self.to_decimal() + int(other)
        else:
            raise TypeError(
                "TernaryNumber'ın başka bir sayıya veya TernaryNumber'e eklenebilir."
            )
        return TernaryNumber.from_decimal(result_decimal)

    def __radd__(self, other):
        """Toplama işleminin sağ taraf desteklenmesini sağlar."""
        return self.__add__(other)

    def __sub__(self, other):
        """Çıkarma işlemini destekler."""
        if isinstance(other, TernaryNumber):
            result_decimal = self.to_decimal() - other.to_decimal()
        elif isinstance(other, (int, str)):
            result_decimal = self.to_decimal() - int(other)
        else:
            raise TypeError(
                "TernaryNumber'dan başka bir sayıya veya başka bir TernaryNumber çıkartılabilir."
            )
        if result_decimal < 0:
            raise ValueError("Bir üçlü sayıdan daha büyük bir sayı çıkaramazsınız.")
        return TernaryNumber.from_decimal(result_decimal)

    def __rsub__(self, other):
        """Çıkarma işleminin sağ taraf desteklenmesini sağlar."""
        if isinstance(other, (int, str)):
            result_decimal = int(other) - self.to_decimal()
        else:
            raise TypeError("TernaryNumber'dan bir sayı çıkartılabilir.")
        if result_decimal < 0:
            raise ValueError("Bir üçlü sayıdan daha büyük bir sayı çıkaramazsınız.")
        return TernaryNumber.from_decimal(result_decimal)

    def to_int(self) -> int:
        """Ondalık tam sayı değeri (to_decimal ile aynı)."""
        return self.to_decimal()

    def __mod__(self, other):
        """Mod işlemi için ondalık değere çevir."""
        if isinstance(other, (int, float)):
            return self.to_decimal() % other
        if isinstance(other, TernaryNumber):
            return self.to_decimal() % other.to_decimal()
        return NotImplemented

    # __mul__ düzeltmesi (TernaryNumber × TernaryNumber desteklensin)
    def __mul__(self, other):
        """Çarpma: skaler veya TernaryNumber ile çarpma."""
        if isinstance(other, (int, float)):
            result_decimal = self.to_decimal() * other
            return TernaryNumber.from_decimal(int(round(result_decimal)))
        elif isinstance(other, TernaryNumber):
            result_decimal = self.to_decimal() * other.to_decimal()
            return TernaryNumber.from_decimal(int(round(result_decimal)))
        raise TypeError(
            "TernaryNumber yalnızca skaler veya başka bir TernaryNumber ile çarpılabilir."
        )

    def __rmul__(self, other):
        return self.__mul__(other)

    # Üçlü sayı sisteminde bölme işlemi, ondalık karşılığa dönüştürülerek yapılmalıdır.
    def __truediv__(self, other):
        """Bölme işlemini destekler."""
        if isinstance(other, TernaryNumber):
            other_decimal = other.to_decimal()
            if other_decimal == 0:
                raise ZeroDivisionError("Bir TernaryNumber sıfırla bölünemez.")
            result_decimal = self.to_decimal() / other_decimal
            return TernaryNumber.from_decimal(int(round(result_decimal)))
        elif isinstance(other, (int, float)):
            if other == 0:
                raise ZeroDivisionError("Sıfırla bölme hatası.")
            result_decimal = self.to_decimal() / other
            return TernaryNumber.from_decimal(int(round(result_decimal)))
        else:
            raise TypeError(
                "TernaryNumber'i bir sayı veya başka bir TernaryNumber ile bölebilirsiniz."
            )
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    # üçlü sayı sisteminde bölme işlemi, ondalık karşılığa dönüştürülerek yapılmalıdır.
    def __rtruediv__(self, other):
        """Bölme işleminin sağ taraf desteklenmesini sağlar."""
        if isinstance(other, (int, float)):
            self_decimal = self.to_decimal()
            if self_decimal == 0:
                raise ZeroDivisionError("Sıfırla bölme hatası.")
            result_decimal = other / self_decimal
            return TernaryNumber.from_decimal(int(round(result_decimal)))
        else:
            raise TypeError("TernaryNumber ile bir sayı bölünebilir.")

    def __eq__(self, other):
        """Eşitlik kontrolü yapar."""
        if isinstance(other, TernaryNumber):
            return self.digits == other.digits
        elif isinstance(other, (int, str)):
            return self.to_decimal() == int(other)
        else:
            return False

    def __ne__(self, other):
        """Eşitsizlik kontrolü yapar."""
        return not self.__eq__(other)

    def to_int(self) -> int:
        """Ondalık tam sayı değeri (to_decimal ile aynı)"""
        return self.to_decimal()

    def __mod__(self, other):
        """Mod işlemi için ondalık değere çevir"""
        if isinstance(other, (int, float)):
            return self.to_decimal() % other
        return NotImplemented

    def __floordiv__(self, other):
        """Tam bölme için ondalık değere çevir"""
        if isinstance(other, (int, float)):
            return self.to_decimal() // other
        return NotImplemented


# Superreal Sayılar
@dataclass
class SuperrealNumber:
    # def __init__(self, real_part=0.0):
    def __init__(self, real: float, split: float = 0.0):
        """
        SuperrealNumber nesnesini oluşturur.

        :param real_part: Gerçek sayı bileşeni (float).
        """
        # self.real = real_part
        self.real = real
        self.split = split

    def __repr__(self):
        """Nesnenin yazdırılabilir temsilini döndürür."""
        return f"SuperrealNumber({self.real})"

    def __str__(self):
        """Nesnenin string temsilini döndürür."""
        return str(self.real)

    def __add__(self, other):
        """Toplama işlemini destekler."""
        if isinstance(other, SuperrealNumber):
            return SuperrealNumber(self.real + other.real)
        elif isinstance(other, (int, float)):
            return SuperrealNumber(self.real + other)
        else:
            raise TypeError(
                "SuperrealNumber'e bir sayı veya başka bir SuperrealNumber eklenebilir."
            )

    def __radd__(self, other):
        """Toplama işleminin sağ taraf desteklenmesini sağlar."""
        return self.__add__(other)

    def __sub__(self, other):
        """Çıkarma işlemini destekler."""
        if isinstance(other, SuperrealNumber):
            return SuperrealNumber(self.real - other.real)
        elif isinstance(other, (int, float)):
            return SuperrealNumber(self.real - other)
        else:
            raise TypeError(
                "SuperrealNumber'dan bir sayı veya başka bir SuperrealNumber çıkarılabilir."
            )

    def __rsub__(self, other):
        """Çıkarma işleminin sağ taraf desteklenmesini sağlar."""
        return self.__neg__().__add__(other)

    def __mul__(self, other):
        """Çarpma işlemini destekler."""
        if isinstance(other, SuperrealNumber):
            return SuperrealNumber(self.real * other.real)
        elif isinstance(other, (int, float)):
            return SuperrealNumber(self.real * other)
        else:
            raise TypeError(
                "SuperrealNumber ile bir sayı veya başka bir SuperrealNumber çarpılabilir."
            )

    def __rmul__(self, other):
        """Çarpma işleminin sağ taraf desteklenmesini sağlar."""
        return self.__mul__(other)

    def __truediv__(self, other):
        """Bölme işlemini destekler."""
        if isinstance(other, SuperrealNumber):
            if other.real == 0:
                raise ZeroDivisionError("Bir SuperrealNumber sıfırla bölünemez.")
            return SuperrealNumber(self.real / other.real)
        elif isinstance(other, (int, float)):
            if other == 0:
                raise ZeroDivisionError("Sıfırla bölme hatası.")
            return SuperrealNumber(self.real / other)
        else:
            raise TypeError(
                "SuperrealNumber'i bir sayı veya başka bir SuperrealNumber ile bölebilirsiniz."
            )
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __rtruediv__(self, other):
        """Bölme işleminin sağ taraf desteklenmesini sağlar."""
        if self.real == 0:
            raise ZeroDivisionError("Sıfırla bölme hatası.")
        return SuperrealNumber(other / self.real)

    def __neg__(self):
        """Negatif değeri döndürür."""
        return SuperrealNumber(-self.real)

    def __eq__(self, other):
        """Eşitlik kontrolü yapar."""
        if isinstance(other, SuperrealNumber):
            return self.real == other.real
        elif isinstance(other, (int, float)):
            return self.real == other
        else:
            return False

    def __ne__(self, other):
        """Eşitsizlik kontrolü yapar."""
        return not self.__eq__(other)

    def __lt__(self, other):
        """Küçük olma kontrolü yapar."""
        if isinstance(other, SuperrealNumber):
            return self.real < other.real
        elif isinstance(other, (int, float)):
            return self.real < other
        else:
            raise TypeError("SuperrealNumber ile karşılaştırılabilir.")

    def __le__(self, other):
        """Küçük veya eşit kontrolü yapar."""
        return self.__lt__(other) or self.__eq__(other)

    def __gt__(self, other):
        """Büyük olma kontrolü yapar."""
        return not self.__le__(other)

    def __ge__(self, other):
        """Büyük veya eşit kontrolü yapar."""
        return not self.__lt__(other)


@dataclass
class BaseNumber(ABC):
    """Tüm Keçeci sayı tipleri için ortak arayüz."""

    def __init__(self, value: Number):
        self._value = self._coerce(value)

    @staticmethod
    def _coerce(v: Number) -> Number:
        if isinstance(v, (int, float, complex)):
            return v
        raise TypeError(f"Geçersiz sayı tipi: {type(v)}")

    @property
    def value(self) -> Number:
        return self._value

    # ------------------------------------------------------------------ #
    # Matematiksel operator overload’ları (tek yönlü)
    # ------------------------------------------------------------------ #
    def __add__(self, other: Union["BaseNumber", Number]) -> "BaseNumber":
        other_val = other.value if isinstance(other, BaseNumber) else other
        return self.__class__(self._value + other_val)

    def __radd__(self, other: Number) -> "BaseNumber":
        return self.__add__(other)

    def __sub__(self, other: Union["BaseNumber", Number]) -> "BaseNumber":
        other_val = other.value if isinstance(other, BaseNumber) else other
        return self.__class__(self._value - other_val)

    def __rsub__(self, other: Number) -> "BaseNumber":
        return self.__class__(other - self._value)

    def __mul__(self, other: Union["BaseNumber", Number]) -> "BaseNumber":
        other_val = other.value if isinstance(other, BaseNumber) else other
        return self.__class__(self._value * other_val)

    def __rmul__(self, other: Number) -> "BaseNumber":
        return self.__add__(other)

    def __truediv__(self, other: Union["BaseNumber", Number]) -> "BaseNumber":
        other_val = other.value if isinstance(other, BaseNumber) else other
        if other_val == 0:
            raise ZeroDivisionError("division by zero")
        return self.__class__(self._value / other_val)
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __rtruediv__(self, other: Number) -> "BaseNumber":
        if self._value == 0:
            raise ZeroDivisionError("division by zero")
        return self.__class__(other / self._value)

    def __mod__(self, divisor: Number) -> "BaseNumber":
        return self.__class__(self._value % divisor)

    # ------------------------------------------------------------------ #
    # Karşılaştırmalar
    # ------------------------------------------------------------------ #
    def __eq__(self, other: object) -> bool:
        if not isinstance(other, BaseNumber):
            return NotImplemented
        return math.isclose(float(self._value), float(other._value), rel_tol=1e-12)

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}({self._value!r})"

    # ------------------------------------------------------------------ #
    # Alt sınıfların doldurması gereken soyut metodlar
    # ------------------------------------------------------------------ #
    def components(self):
        """Bileşen listesini (Python list) döndürür."""
        # Daha dayanıklı dönüş: coeffs bir numpy array veya python list olabilir.
        if hasattr(self, "coeffs"):
            coeffs = getattr(self, "coeffs")
            if isinstance(coeffs, np.ndarray):
                return coeffs.tolist()
            try:
                return list(coeffs)
            except Exception:
                return [coeffs]
        # Fallback: tek değer
        return [self._value]

    def magnitude(self) -> float:
        """
        Euclidean norm = √( Σ_i coeff_i² )
        NumPy’nin `linalg.norm` fonksiyonu C‑hızında hesaplar.
        """
        return float(np.linalg.norm(self.coeffs))

    def __hash__(self):
        # NaN ve -0.0 gibi durumları göz önünde bulundurun
        return hash(tuple(np.round(self.coeffs, decimals=10)))

    def phase(self):
        """
        Güvenli phase hesaplayıcı:
        - Eğer value complex ise imag/real üzerinden phase hesaplanır.
        - Eğer coeffs varsa, ilk bileşenin complex olması durumunda phase döner.
        - Diğer durumlarda 0.0 döndürür (tanımsız phase için güvenli fallback).
        """
        try:
            # If underlying value is complex
            if isinstance(self._value, complex):
                return math.atan2(self._value.imag, self._value.real)
            # If there's coeffs, use the first coefficient
            if hasattr(self, "coeffs"):
                coeffs = getattr(self, "coeffs")
                if isinstance(coeffs, (list, tuple, np.ndarray)) and len(coeffs) > 0:
                    first = coeffs[0]
                    if isinstance(first, complex):
                        return math.atan2(first.imag, first.real)
            # If value has real/imag attributes (like some custom complex types)
            if hasattr(self._value, "real") and hasattr(self._value, "imag"):
                return math.atan2(self._value.imag, self._value.real)
        except Exception:
            pass
        return 0.0


@dataclass
class PathionNumber:
    """32-bileşenli Pathion sayısı"""

    def __init__(self, *coeffs):
        if (
            len(coeffs) == 1
            and hasattr(coeffs[0], "__iter__")
            and not isinstance(coeffs[0], str)
        ):
            coeffs = coeffs[0]

        if len(coeffs) != 32:
            coeffs = list(coeffs) + [0.0] * (32 - len(coeffs))
            if len(coeffs) > 32:
                coeffs = coeffs[:32]

        self.coeffs = [float(c) for c in coeffs]

    @property
    def real(self) -> float:
        """İlk bileşen – “gerçek” kısım."""
        return float(self.coeffs[0])

    # def real(self):
    #    Gerçek kısım (ilk bileşen)
    #    return self.coeffs[0]

    def __iter__(self):
        return iter(self.coeffs)

    def __getitem__(self, index):
        return self.coeffs[index]

    def __len__(self):
        return len(self.coeffs)

    def __str__(self):
        return f"PathionNumber({', '.join(map(str, self.coeffs))})"

    def __repr__(self):
        return f"PathionNumber({', '.join(map(str, self.coeffs))})"
        # return f"PathionNumber({self.coeffs})"

    def __add__(self, other):
        if isinstance(other, PathionNumber):
            return PathionNumber([a + b for a, b in zip(self.coeffs, other.coeffs)])
        else:
            # Skaler toplama
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] += float(other)
            return PathionNumber(new_coeffs)

    def __sub__(self, other):
        if isinstance(other, PathionNumber):
            return PathionNumber([a - b for a, b in zip(self.coeffs, other.coeffs)])
        else:
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] -= float(other)
            return PathionNumber(new_coeffs)

    def __mul__(self, other):
        if isinstance(other, PathionNumber):
            # Basitçe bileşen bazlı çarpma (gerçek Cayley-Dickson çarpımı yerine)
            return PathionNumber([a * b for a, b in zip(self.coeffs, other.coeffs)])
        else:
            # Skaler çarpma
            return PathionNumber([c * float(other) for c in self.coeffs])

    def __mod__(self, divisor):
        return PathionNumber([c % divisor for c in self.coeffs])

    def __eq__(self, other):
        if not isinstance(other, PathionNumber):
            return NotImplemented
        return np.allclose(self.coeffs, other.coeffs, atol=1e-10)
        # if isinstance(other, PathionNumber):
        #    return all(math.isclose(a, b, abs_tol=1e-10) for a, b in zip(self.coeffs, other.coeffs))
        # return False

    def __truediv__(self, other):
        """Bölme operatörü: /"""
        if isinstance(other, (int, float)):
            # Skaler bölme
            return PathionNumber([c / other for c in self.coeffs])
        else:
            raise TypeError(
                f"Unsupported operand type(s) for /: 'PathionNumber' and '{type(other).__name__}'"
            )
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __floordiv__(self, other):
        """Tam sayı bölme operatörü: //"""
        if isinstance(other, (int, float)):
            # Skaler tam sayı bölme
            return PathionNumber([c // other for c in self.coeffs])
        else:
            raise TypeError(
                f"Unsupported operand type(s) for //: 'PathionNumber' and '{type(other).__name__}'"
            )

    def __rtruediv__(self, other):
        """Sağdan bölme: other / PathionNumber"""
        if isinstance(other, (int, float)):
            # Bu daha karmaşık olabilir, basitçe bileşen bazlı bölme
            return PathionNumber(
                [other / c if c != 0 else float("inf") for c in self.coeffs]
            )
        else:
            raise TypeError(
                f"Unsupported operand type(s) for /: '{type(other).__name__}' and 'PathionNumber'"
            )

    # ------------------------------------------------------------------
    # Yeni eklenen yardımcı metodlar
    # ------------------------------------------------------------------
    def components(self):
        """Bileşen listesini (Python list) döndürür."""
        return list(self.coeffs)

    def magnitude(self) -> float:
        """
        Euclidean norm = √( Σ_i coeff_i² )
        NumPy’nin `linalg.norm` fonksiyonu C‑hızında hesaplar.
        """
        return float(np.linalg.norm(self.coeffs))

    def __hash__(self):
        # NaN ve -0.0 gibi durumları göz önünde bulundurun
        return hash(tuple(np.round(self.coeffs, decimals=10)))

    def phase(self):
        # Güvenli phase: ilk bileşene bak, eğer complex ise angle döndür, değilse 0.0
        try:
            first = self.coeffs[0] if self.coeffs else 0.0
            if isinstance(first, complex):
                return math.atan2(first.imag, first.real)
        except Exception:
            pass
        return 0.0

    def __rmul__(self, scalar):
        if isinstance(scalar, (int, float)):
            return self.__class__(*[scalar * c for c in self.components])
        return NotImplemented


@dataclass
class ChingonNumber:
    """64-bileşenli Chingon sayısı"""  # Açıklama düzeltildi

    def __init__(self, *coeffs):
        if (
            len(coeffs) == 1
            and hasattr(coeffs[0], "__iter__")
            and not isinstance(coeffs[0], str)
        ):
            coeffs = coeffs[0]

        if len(coeffs) != 64:
            coeffs = list(coeffs) + [0.0] * (64 - len(coeffs))
            if len(coeffs) > 64:
                coeffs = coeffs[:64]

        self.coeffs = [float(c) for c in coeffs]

    @property
    def real(self) -> float:
        """İlk bileşen – “gerçek” kısım."""
        return float(self.coeffs[0])

    # def real(self):
    #    Gerçek kısım (ilk bileşen)
    #    return self.coeffs[0]

    def __iter__(self):
        return iter(self.coeffs)

    def __getitem__(self, index):
        return self.coeffs[index]

    def __len__(self):
        return len(self.coeffs)

    def __str__(self):
        return f"ChingonNumber({', '.join(map(str, self.coeffs))})"

    def __repr__(self):
        return f"({', '.join(map(str, self.coeffs))})"
        # return f"ChingonNumber({self.coeffs})"

    def __add__(self, other):
        if isinstance(other, ChingonNumber):
            return ChingonNumber([a + b for a, b in zip(self.coeffs, other.coeffs)])
        else:
            # Skaler toplama
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] += float(other)
            return ChingonNumber(new_coeffs)

    def __sub__(self, other):
        if isinstance(other, ChingonNumber):
            return ChingonNumber([a - b for a, b in zip(self.coeffs, other.coeffs)])
        else:
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] -= float(other)
            return ChingonNumber(new_coeffs)

    def __mul__(self, other):
        if isinstance(other, ChingonNumber):
            # Basitçe bileşen bazlı çarpma
            return ChingonNumber(
                [a * b for a, b in zip(self.coeffs, other.coeffs)]
            )  # ChingonNumber döndür
        else:
            # Skaler çarpma
            return ChingonNumber(
                [c * float(other) for c in self.coeffs]
            )  # ChingonNumber döndür

    def __mod__(self, divisor):
        return ChingonNumber([c % divisor for c in self.coeffs])  # ChingonNumber döndür

    def __eq__(self, other):
        if not isinstance(other, ChingonNumber):
            return NotImplemented
        return np.allclose(self.coeffs, other.coeffs, atol=1e-10)
        # if isinstance(other, ChingonNumber):  # ChingonNumber ile karşılaştır
        #    return all(math.isclose(a, b, abs_tol=1e-10) for a, b in zip(self.coeffs, other.coeffs))
        # return False

    def __truediv__(self, other):
        """Bölme operatörü: /"""
        if isinstance(other, (int, float)):
            # Skaler bölme
            return ChingonNumber(
                [c / other for c in self.coeffs]
            )  # ChingonNumber döndür
        else:
            raise TypeError(
                f"Unsupported operand type(s) for /: 'ChingonNumber' and '{type(other).__name__}'"
            )  # ChingonNumber
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __floordiv__(self, other):
        """Tam sayı bölme operatörü: //"""
        if isinstance(other, (int, float)):
            # Skaler tam sayı bölme
            return ChingonNumber(
                [c // other for c in self.coeffs]
            )  # ChingonNumber döndür
        else:
            raise TypeError(
                f"Unsupported operand type(s) for //: 'ChingonNumber' and '{type(other).__name__}'"
            )  # ChingonNumber

    def __rtruediv__(self, other):
        """Sağdan bölme: other / ChingonNumber"""
        if isinstance(other, (int, float)):
            return ChingonNumber(
                [other / c if c != 0 else float("inf") for c in self.coeffs]
            )  # ChingonNumber döndür
        else:
            raise TypeError(
                f"Unsupported operand type(s) for /: '{type(other).__name__}' and 'ChingonNumber'"
            )  # ChingonNumber

    def components(self):
        """Bileşen listesini (Python list) döndürür."""
        return list(self.coeffs)

    def magnitude(self) -> float:
        """
        Euclidean norm = √( Σ_i coeff_i² )
        NumPy’nin `linalg.norm` fonksiyonu C‑hızında hesaplar.
        """
        return float(np.linalg.norm(self.coeffs))

    def __hash__(self):
        # NaN ve -0.0 gibi durumları göz önünde bulundurun
        return hash(tuple(np.round(self.coeffs, decimals=10)))

    def phase(self):
        # Güvenli phase: ilk bileşene bak, eğer complex ise angle döndür, değilse 0.0
        try:
            first = self.coeffs[0] if self.coeffs else 0.0
            if isinstance(first, complex):
                return math.atan2(first.imag, first.real)
        except Exception:
            pass
        return 0.0

    def __rmul__(self, scalar):
        if isinstance(scalar, (int, float)):
            return self.__class__(*[scalar * c for c in self.components])
        return NotImplemented


@dataclass
class RoutonNumber:
    """
    128-dimensional hypercomplex number (Routon).

    Routon numbers extend the Cayley-Dickson construction.
    They have 128 components and are high-dimensional algebraic structures.

    Note: True Routon multiplication is extremely complex (128x128 multiplication table).
    This implementation uses simplified operations for practical use.
    """

    coeffs: List[float] = field(default_factory=lambda: [0.0] * 128)

    def __post_init__(self):
        # Eğer coeffs int/float ise listeye çevir
        if isinstance(self.coeffs, (int, float)):
            self.coeffs = [float(self.coeffs)]
        elif isinstance(self.coeffs, dict):
            self.coeffs = list(self.coeffs.values())
        # Şimdi len kullanılabilir
        if len(self.coeffs) != 128:
            if len(self.coeffs) < 128:
                self.coeffs = list(self.coeffs) + [0.0] * (128 - len(self.coeffs))
            else:
                self.coeffs = self.coeffs[:128]

    @classmethod
    def from_scalar(cls, value: float) -> "RoutonNumber":
        """Create a Routon number from a scalar (real number)."""
        coeffs = [0.0] * 128
        coeffs[0] = float(value)
        return cls(coeffs)

    @classmethod
    def from_list(cls, values: List[float]) -> "RoutonNumber":
        """Create from a list of up to 128 values."""
        if len(values) > 128:
            raise ValueError(f"List too long ({len(values)}), maximum 128 elements")
        coeffs = list(values) + [0.0] * (128 - len(values))
        return cls(coeffs)

    @classmethod
    def from_iterable(cls, values: Any) -> "RoutonNumber":
        """Create from any iterable."""
        return cls.from_list(list(values))

    @classmethod
    def basis_element(cls, index: int) -> "RoutonNumber":
        """Create a basis Routon (1 at position index, 0 elsewhere)."""
        if not 0 <= index < 128:
            raise ValueError(f"Index must be between 0 and 127, got {index}")
        coeffs = [0.0] * 128
        coeffs[index] = 1.0
        return cls(coeffs)

    @property
    def real(self) -> float:
        """Get the real part (first component)."""
        return self.coeffs[0]

    @real.setter
    def real(self, value: float):
        """Set the real part."""
        self.coeffs[0] = float(value)

    @property
    def imag(self) -> List[float]:
        """Get the imaginary parts (all except real)."""
        return self.coeffs[1:]

    def __getitem__(self, index: int) -> float:
        """Get component by index."""
        if not 0 <= index < 128:
            raise IndexError(f"Index {index} out of range for Routon")
        return self.coeffs[index]

    def __setitem__(self, index: int, value: float):
        """Set component by index."""
        if not 0 <= index < 128:
            raise IndexError(f"Index {index} out of range for Routon")
        self.coeffs[index] = float(value)

    def __len__(self) -> int:
        """Return number of components (always 128)."""
        return 128

    def __iter__(self):
        """Iterate over components."""
        return iter(self.coeffs)

    def __add__(self, other: Union["RoutonNumber", float, int]) -> "RoutonNumber":
        """Add two Routon numbers or Routon and scalar."""
        if isinstance(other, RoutonNumber):
            new_coeffs = [a + b for a, b in zip(self.coeffs, other.coeffs)]
            return RoutonNumber(new_coeffs)
        elif isinstance(other, (int, float)):
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] += float(other)
            return RoutonNumber(new_coeffs)
        return NotImplemented

    def __radd__(self, other: Union[float, int]) -> "RoutonNumber":
        """Right addition: scalar + Routon."""
        return self.__add__(other)

    def __sub__(self, other: Union["RoutonNumber", float, int]) -> "RoutonNumber":
        """Subtract two Routon numbers or Routon and scalar."""
        if isinstance(other, RoutonNumber):
            new_coeffs = [a - b for a, b in zip(self.coeffs, other.coeffs)]
            return RoutonNumber(new_coeffs)
        elif isinstance(other, (int, float)):
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] -= float(other)
            return RoutonNumber(new_coeffs)
        return NotImplemented

    def __rsub__(self, other: Union[float, int]) -> "RoutonNumber":
        """Right subtraction: scalar - Routon."""
        if isinstance(other, (int, float)):
            new_coeffs = [-c for c in self.coeffs]
            new_coeffs[0] += float(other)
            return RoutonNumber(new_coeffs)
        return NotImplemented

    def __mul__(self, other: Union["RoutonNumber", float, int]) -> "RoutonNumber":
        """
        Multiply Routon by scalar or another Routon (simplified).

        Note: True Routon multiplication would require a 128x128 multiplication table.
        This implementation uses element-wise multiplication for Routon x Routon,
        which is mathematically incorrect but practical for many applications.
        """
        if isinstance(other, (int, float)):
            # Scalar multiplication
            new_coeffs = [c * float(other) for c in self.coeffs]
            return RoutonNumber(new_coeffs)
        elif isinstance(other, RoutonNumber):
            # Simplified element-wise multiplication
            # WARNING: This is NOT true Routon multiplication!
            new_coeffs = [a * b for a, b in zip(self.coeffs, other.coeffs)]
            return RoutonNumber(new_coeffs)
        return NotImplemented

    def __rmul__(self, other: Union[float, int]) -> "RoutonNumber":
        """Right multiplication: scalar * Routon."""
        return self.__mul__(other)

    def __truediv__(self, scalar: Union[float, int]) -> "RoutonNumber":
        """Divide Routon by scalar."""
        if isinstance(scalar, (int, float)):
            if scalar == 0:
                raise ZeroDivisionError("Cannot divide Routon by zero")
            new_coeffs = [c / float(scalar) for c in self.coeffs]
            return RoutonNumber(new_coeffs)
        return NotImplemented
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __floordiv__(self, scalar: Union[float, int]) -> "RoutonNumber":
        """Floor divide Routon by scalar."""
        if isinstance(scalar, (int, float)):
            if scalar == 0:
                raise ZeroDivisionError("Cannot divide Routon by zero")
            new_coeffs = [c // float(scalar) for c in self.coeffs]
            return RoutonNumber(new_coeffs)
        return NotImplemented

    def __mod__(self, divisor: Union[float, int]) -> "RoutonNumber":
        """Modulo operation on Routon components."""
        if isinstance(divisor, (int, float)):
            if divisor == 0:
                raise ZeroDivisionError("Cannot take modulo by zero")
            new_coeffs = [c % float(divisor) for c in self.coeffs]
            return RoutonNumber(new_coeffs)
        return NotImplemented

    def __neg__(self) -> "RoutonNumber":
        """Negate the Routon number."""
        return RoutonNumber([-c for c in self.coeffs])

    def __pos__(self) -> "RoutonNumber":
        """Unary plus."""
        return self

    def __abs__(self) -> float:
        """Absolute value (magnitude)."""
        return self.magnitude()

    def __eq__(self, other: object) -> bool:
        """Check equality with another Routon."""
        if not isinstance(other, RoutonNumber):
            return False
        return all(
            math.isclose(a, b, abs_tol=1e-12) for a, b in zip(self.coeffs, other.coeffs)
        )

    def __ne__(self, other: object) -> bool:
        """Check inequality."""
        return not self.__eq__(other)

    def __hash__(self) -> int:
        """Hash based on rounded components to avoid floating-point issues."""
        return hash(tuple(round(c, 12) for c in self.coeffs))

    def magnitude(self) -> float:
        """
        Calculate Euclidean norm (magnitude) of the Routon.

        Returns:
            float: sqrt(Σ_i coeff_i²)
        """
        return float(np.linalg.norm(self.coeffs))

    def norm(self) -> float:
        """Alias for magnitude."""
        return self.magnitude()

    def conjugate(self) -> "RoutonNumber":
        """Return the conjugate (negate all imaginary parts)."""
        new_coeffs = self.coeffs.copy()
        for i in range(1, 128):
            new_coeffs[i] = -new_coeffs[i]
        return RoutonNumber(new_coeffs)

    def dot(self, other: "RoutonNumber") -> float:
        """Dot product with another Routon."""
        if not isinstance(other, RoutonNumber):
            raise TypeError("Dot product requires another RoutonNumber")
        return sum(a * b for a, b in zip(self.coeffs, other.coeffs))

    def normalize(self) -> "RoutonNumber":
        """Return a normalized (unit) version."""
        mag = self.magnitude()
        if mag == 0:
            raise ZeroDivisionError("Cannot normalize zero Routon")
        return RoutonNumber([c / mag for c in self.coeffs])

    def to_list(self) -> List[float]:
        """Convert to Python list."""
        return self.coeffs.copy()

    def to_tuple(self) -> Tuple[float, ...]:
        """Convert to tuple."""
        return tuple(self.coeffs)

    def to_numpy(self) -> np.ndarray:
        """Convert to numpy array."""
        return np.array(self.coeffs, dtype=np.float64)

    def copy(self) -> "RoutonNumber":
        """Create a copy."""
        return RoutonNumber(self.coeffs.copy())

    def components(self) -> List[float]:
        """Get components as list (alias for to_list)."""
        return self.to_list()

    def phase(self) -> float:
        """
        Compute phase (angle) of the Routon number.

        For high-dimensional numbers, phase is not uniquely defined.
        This implementation returns the angle of the projection onto
        the real-imaginary plane.
        """
        if self.magnitude() == 0:
            return 0.0

        # Compute magnitude of imaginary parts
        imag_magnitude = math.sqrt(sum(i**2 for i in self.imag))
        if imag_magnitude == 0:
            return 0.0

        # Angle between real part and imaginary vector
        return math.atan2(imag_magnitude, self.real)

    def __str__(self) -> str:
        """Human-readable string representation."""
        # For 128 dimensions, show a summary
        non_zero = [(i, c) for i, c in enumerate(self.coeffs) if abs(c) > 1e-10]

        if not non_zero:
            return "Routon(0)"

        if len(non_zero) <= 5:
            # Show all non-zero components
            parts = []
            for i, c in non_zero:
                if i == 0:
                    parts.append(f"{c:.6f}")
                else:
                    sign = "+" if c >= 0 else "-"
                    parts.append(f"{sign} {abs(c):.6f}e{i}")
            return f"Routon({' '.join(parts)})"
        else:
            # Show summary
            return f"Routon[{len(non_zero)} non-zero components, real={self.real:.6f}, mag={self.magnitude():.6f}]"

    def __repr__(self) -> str:
        """Detailed representation showing first few components."""
        if len(self.coeffs) <= 8:
            return f"RoutonNumber({self.coeffs})"
        else:
            first_five = self.coeffs[:5]
            last_five = self.coeffs[-5:]
            return f"RoutonNumber({first_five} ... {last_five})"

    def summary(self) -> str:
        """Return a summary of the Routon number."""
        non_zero = sum(1 for c in self.coeffs if abs(c) > 1e-10)
        max_coeff = max(abs(c) for c in self.coeffs)
        min_coeff = min(abs(c) for c in self.coeffs if abs(c) > 0)

        return (
            f"RoutonNumber Summary:\n"
            f"  Dimensions: 128\n"
            f"  Non-zero components: {non_zero}\n"
            f"  Real part: {self.real:.6f}\n"
            f"  Magnitude: {self.magnitude():.6f}\n"
            f"  Phase: {self.phase():.6f} rad\n"
            f"  Max component: {max_coeff:.6f}\n"
            f"  Min non-zero: {min_coeff:.6f if non_zero > 0 else 0}"
        )


@dataclass
class VoudonNumber:
    """
    256-dimensional hypercomplex number (Voudon).

    Voudon numbers extend the Cayley-Dickson construction beyond sedenions.
    They have 256 components and are extremely high-dimensional algebraic structures.

    Note: True Voudon multiplication is extremely complex (256x256 multiplication table).
    This implementation uses simplified operations for practical use.
    """

    coeffs: List[float] = field(default_factory=lambda: [0.0] * 256)

    def __post_init__(self):
        # Eğer coeffs int/float ise listeye çevir
        if isinstance(self.coeffs, (int, float)):
            self.coeffs = [float(self.coeffs)]
        elif isinstance(self.coeffs, dict):
            self.coeffs = list(self.coeffs.values())
        # Şimdi len kullanılabilir
        if len(self.coeffs) != 256:
            if len(self.coeffs) < 256:
                self.coeffs = list(self.coeffs) + [0.0] * (256 - len(self.coeffs))
            else:
                self.coeffs = self.coeffs[:256]

    @classmethod
    def from_scalar(cls, value: float) -> "VoudonNumber":
        """Create a Voudon number from a scalar (real number)."""
        coeffs = [0.0] * 256
        coeffs[0] = float(value)
        return cls(coeffs)

    @classmethod
    def from_list(cls, values: List[float]) -> "VoudonNumber":
        """Create from a list of up to 256 values."""
        if len(values) > 256:
            raise ValueError(f"List too long ({len(values)}), maximum 256 elements")
        coeffs = list(values) + [0.0] * (256 - len(values))
        return cls(coeffs)

    @classmethod
    def from_iterable(cls, values: Any) -> "VoudonNumber":
        """Create from any iterable."""
        return cls.from_list(list(values))

    @classmethod
    def basis_element(cls, index: int) -> "VoudonNumber":
        """Create a basis Voudon (1 at position index, 0 elsewhere)."""
        if not 0 <= index < 256:
            raise ValueError(f"Index must be between 0 and 255, got {index}")
        coeffs = [0.0] * 256
        coeffs[index] = 1.0
        return cls(coeffs)

    @property
    def real(self) -> float:
        """Get the real part (first component)."""
        return self.coeffs[0]

    @real.setter
    def real(self, value: float):
        """Set the real part."""
        self.coeffs[0] = float(value)

    @property
    def imag(self) -> List[float]:
        """Get the imaginary parts (all except real)."""
        return self.coeffs[1:]

    def __getitem__(self, index: int) -> float:
        """Get component by index."""
        if not 0 <= index < 256:
            raise IndexError(f"Index {index} out of range for Voudon")
        return self.coeffs[index]

    def __setitem__(self, index: int, value: float):
        """Set component by index."""
        if not 0 <= index < 256:
            raise IndexError(f"Index {index} out of range for Voudon")
        self.coeffs[index] = float(value)

    def __len__(self) -> int:
        """Return number of components (always 256)."""
        return 256

    def __iter__(self):
        """Iterate over components."""
        return iter(self.coeffs)

    def __add__(self, other: Union["VoudonNumber", float, int]) -> "VoudonNumber":
        """Add two Voudon numbers or Voudon and scalar."""
        if isinstance(other, VoudonNumber):
            new_coeffs = [a + b for a, b in zip(self.coeffs, other.coeffs)]
            return VoudonNumber(new_coeffs)
        elif isinstance(other, (int, float)):
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] += float(other)
            return VoudonNumber(new_coeffs)
        return NotImplemented

    def __radd__(self, other: Union[float, int]) -> "VoudonNumber":
        """Right addition: scalar + Voudon."""
        return self.__add__(other)

    def __sub__(self, other: Union["VoudonNumber", float, int]) -> "VoudonNumber":
        """Subtract two Voudon numbers or Voudon and scalar."""
        if isinstance(other, VoudonNumber):
            new_coeffs = [a - b for a, b in zip(self.coeffs, other.coeffs)]
            return VoudonNumber(new_coeffs)
        elif isinstance(other, (int, float)):
            new_coeffs = self.coeffs.copy()
            new_coeffs[0] -= float(other)
            return VoudonNumber(new_coeffs)
        return NotImplemented

    def __rsub__(self, other: Union[float, int]) -> "VoudonNumber":
        """Right subtraction: scalar - Voudon."""
        if isinstance(other, (int, float)):
            new_coeffs = [-c for c in self.coeffs]
            new_coeffs[0] += float(other)
            return VoudonNumber(new_coeffs)
        return NotImplemented

    def __mul__(self, other: Union["VoudonNumber", float, int]) -> "VoudonNumber":
        """
        Multiply Voudon by scalar or another Voudon (simplified).

        Note: True Voudon multiplication would require a 256x256 multiplication table.
        This implementation uses element-wise multiplication for Voudon x Voudon,
        which is mathematically incorrect but practical for many applications.
        """
        if isinstance(other, (int, float)):
            # Scalar multiplication
            new_coeffs = [c * float(other) for c in self.coeffs]
            return VoudonNumber(new_coeffs)
        elif isinstance(other, VoudonNumber):
            # Simplified element-wise multiplication
            # WARNING: This is NOT true Voudon multiplication!
            new_coeffs = [a * b for a, b in zip(self.coeffs, other.coeffs)]
            return VoudonNumber(new_coeffs)
        return NotImplemented

    def __rmul__(self, other: Union[float, int]) -> "VoudonNumber":
        """Right multiplication: scalar * Voudon."""
        return self.__mul__(other)

    def __truediv__(self, scalar: Union[float, int]) -> "VoudonNumber":
        """Divide Voudon by scalar."""
        if isinstance(scalar, (int, float)):
            if scalar == 0:
                raise ZeroDivisionError("Cannot divide Voudon by zero")
            new_coeffs = [c / float(scalar) for c in self.coeffs]
            return VoudonNumber(new_coeffs)
        return NotImplemented
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __floordiv__(self, scalar: Union[float, int]) -> "VoudonNumber":
        """Floor divide Voudon by scalar."""
        if isinstance(scalar, (int, float)):
            if scalar == 0:
                raise ZeroDivisionError("Cannot divide Voudon by zero")
            new_coeffs = [c // float(scalar) for c in self.coeffs]
            return VoudonNumber(new_coeffs)
        return NotImplemented

    def __mod__(self, divisor: Union[float, int]) -> "VoudonNumber":
        """Modulo operation on Voudon components."""
        if isinstance(divisor, (int, float)):
            if divisor == 0:
                raise ZeroDivisionError("Cannot take modulo by zero")
            new_coeffs = [c % float(divisor) for c in self.coeffs]
            return VoudonNumber(new_coeffs)
        return NotImplemented

    def __neg__(self) -> "VoudonNumber":
        """Negate the Voudon number."""
        return VoudonNumber([-c for c in self.coeffs])

    def __pos__(self) -> "VoudonNumber":
        """Unary plus."""
        return self

    def __abs__(self) -> float:
        """Absolute value (magnitude)."""
        return self.magnitude()

    def __eq__(self, other: object) -> bool:
        """Check equality with another Voudon."""
        if not isinstance(other, VoudonNumber):
            return False
        return all(
            math.isclose(a, b, abs_tol=1e-12) for a, b in zip(self.coeffs, other.coeffs)
        )

    def __ne__(self, other: object) -> bool:
        """Check inequality."""
        return not self.__eq__(other)

    def __hash__(self) -> int:
        """Hash based on rounded components to avoid floating-point issues."""
        return hash(tuple(round(c, 12) for c in self.coeffs))

    def magnitude(self) -> float:
        """
        Calculate Euclidean norm (magnitude) of the Voudon.

        Returns:
            float: sqrt(Σ_i coeff_i²)
        """
        return float(np.linalg.norm(self.coeffs))

    def norm(self) -> float:
        """Alias for magnitude."""
        return self.magnitude()

    def conjugate(self) -> "VoudonNumber":
        """Return the conjugate (negate all imaginary parts)."""
        new_coeffs = self.coeffs.copy()
        for i in range(1, 256):
            new_coeffs[i] = -new_coeffs[i]
        return VoudonNumber(new_coeffs)

    def dot(self, other: "VoudonNumber") -> float:
        """Dot product with another Voudon."""
        if not isinstance(other, VoudonNumber):
            raise TypeError("Dot product requires another VoudonNumber")
        return sum(a * b for a, b in zip(self.coeffs, other.coeffs))

    def normalize(self) -> "VoudonNumber":
        """Return a normalized (unit) version."""
        mag = self.magnitude()
        if mag == 0:
            raise ZeroDivisionError("Cannot normalize zero Voudon")
        return VoudonNumber([c / mag for c in self.coeffs])

    def to_list(self) -> List[float]:
        """Convert to Python list."""
        return self.coeffs.copy()

    def to_tuple(self) -> Tuple[float, ...]:
        """Convert to tuple."""
        return tuple(self.coeffs)

    def to_numpy(self) -> np.ndarray:
        """Convert to numpy array."""
        return np.array(self.coeffs, dtype=np.float64)

    def copy(self) -> "VoudonNumber":
        """Create a copy."""
        return VoudonNumber(self.coeffs.copy())

    def components(self) -> List[float]:
        """Get components as list (alias for to_list)."""
        return self.to_list()

    def phase(self) -> float:
        """
        Compute phase (angle) of the Voudon number.

        For high-dimensional numbers, phase is not uniquely defined.
        This implementation returns the angle of the projection onto
        the real-imaginary plane.
        """
        if self.magnitude() == 0:
            return 0.0

        # Compute magnitude of imaginary parts
        imag_magnitude = math.sqrt(sum(i**2 for i in self.imag))
        if imag_magnitude == 0:
            return 0.0

        # Angle between real part and imaginary vector
        return math.atan2(imag_magnitude, self.real)

    def __str__(self) -> str:
        """Human-readable string representation."""
        # For 256 dimensions, show a summary
        non_zero = [(i, c) for i, c in enumerate(self.coeffs) if abs(c) > 1e-10]

        if not non_zero:
            return "Voudon(0)"

        if len(non_zero) <= 5:
            # Show all non-zero components
            parts = []
            for i, c in non_zero:
                if i == 0:
                    parts.append(f"{c:.6f}")
                else:
                    sign = "+" if c >= 0 else "-"
                    parts.append(f"{sign} {abs(c):.6f}e{i}")
            return f"Voudon({' '.join(parts)})"
        else:
            # Show summary
            return f"Voudon[{len(non_zero)} non-zero components, real={self.real:.6f}, mag={self.magnitude():.6f}]"

    def __repr__(self) -> str:
        """Detailed representation showing first few components."""
        if len(self.coeffs) <= 8:
            return f"VoudonNumber({self.coeffs})"
        else:
            first_five = self.coeffs[:5]
            last_five = self.coeffs[-5:]
            return f"VoudonNumber({first_five} ... {last_five})"

    def summary(self) -> str:
        """Return a summary of the Voudon number."""
        non_zero = sum(1 for c in self.coeffs if abs(c) > 1e-10)
        max_coeff = max(abs(c) for c in self.coeffs)
        min_coeff = min(abs(c) for c in self.coeffs if abs(c) > 0)

        return (
            f"VoudonNumber Summary:\n"
            f"  Dimensions: 256\n"
            f"  Non-zero components: {non_zero}\n"
            f"  Real part: {self.real:.6f}\n"
            f"  Magnitude: {self.magnitude():.6f}\n"
            f"  Phase: {self.phase():.6f} rad\n"
            f"  Max component: {max_coeff:.6f}\n"
            f"  Min non-zero: {min_coeff:.6f if non_zero > 0 else 0}"
        )


@dataclass
class OctonionNumber:
    """
    Represents an octonion number with 8 components.
    Implements octonion multiplication rules (non-commutative, non-associative).

    Octonions are 8-dimensional hypercomplex numbers that extend quaternions.
    They have applications in string theory, quantum mechanics, and geometry.

    Attributes:
    ----------
    w, x, y, z, e, f, g, h : float
        The 8 components of the octonion
    """

    w: float = 0.0
    x: float = 0.0
    y: float = 0.0
    z: float = 0.0
    e: float = 0.0
    f: float = 0.0
    g: float = 0.0
    h: float = 0.0

    # Private field for phase computation
    _phase: float = field(init=False, default=0.0)

    def __post_init__(self):
        """Initialize phase after the object is created."""
        self._compute_phase()

    @classmethod
    def from_list(cls, components: List[float]) -> "OctonionNumber":
        """
        Create OctonionNumber from a list of components.

        Args:
            components: List of 1-8 float values

        Returns:
            OctonionNumber instance
        """
        if len(components) == 8:
            return cls(*components)
        elif len(components) < 8:
            # Pad with zeros if less than 8 components
            padded = list(components) + [0.0] * (8 - len(components))
            return cls(*padded)
        else:
            # Truncate if more than 8 components
            return cls(*components[:8])

    @classmethod
    def from_scalar(cls, scalar: float) -> "OctonionNumber":
        """
        Create OctonionNumber from a scalar (real number).

        Args:
            scalar: Real number to convert to octonion

        Returns:
            OctonionNumber with scalar as real part, others zero
        """
        return cls(w=float(scalar))

    @classmethod
    def from_complex(cls, z: complex) -> "OctonionNumber":
        """
        Create OctonionNumber from a complex number.

        Args:
            z: Complex number to convert to octonion

        Returns:
            OctonionNumber with complex as first two components
        """
        return cls(w=z.real, x=z.imag)

    @property
    def coeffs(self) -> List[float]:
        """Get all components as a list."""
        return [self.w, self.x, self.y, self.z, self.e, self.f, self.g, self.h]

    @property
    def real(self) -> float:
        """Get the real part (first component)."""
        return self.w

    @real.setter
    def real(self, value: float):
        """Set the real part."""
        self.w = float(value)
        self._compute_phase()

    @property
    def imag(self) -> List[float]:
        """Get the imaginary parts (all except real)."""
        return [self.x, self.y, self.z, self.e, self.f, self.g, self.h]

    def _compute_phase(self) -> None:
        """Compute and store the phase (angle) of the octonion."""
        magnitude = self.magnitude()
        if magnitude == 0:
            self._phase = 0.0
        else:
            # For octonions, phase is not uniquely defined.
            # We use the angle of the projection onto the real-imaginary plane
            imag_magnitude = np.sqrt(sum(i**2 for i in self.imag))
            if imag_magnitude == 0:
                self._phase = 0.0
            else:
                # Angle between real part and imaginary vector
                self._phase = np.arctan2(imag_magnitude, self.real)

    def components(self) -> List[float]:
        """Get components as list (alias for coeffs)."""
        return self.coeffs

    def magnitude(self) -> float:
        """
        Calculate the Euclidean norm (magnitude) of the octonion.

        Returns:
            float: sqrt(w² + x² + y² + z² + e² + f² + g² + h²)
        """
        return float(np.linalg.norm(self.coeffs))

    def norm(self) -> float:
        """Alias for magnitude."""
        return self.magnitude()

    def conjugate(self) -> "OctonionNumber":
        """
        Return the conjugate of the octonion.

        Returns:
            OctonionNumber with signs of imaginary parts flipped
        """
        return OctonionNumber(
            self.w, -self.x, -self.y, -self.z, -self.e, -self.f, -self.g, -self.h
        )

    def inverse(self) -> "OctonionNumber":
        """
        Return the multiplicative inverse.

        Returns:
            OctonionNumber: o⁻¹ such that o * o⁻¹ = o⁻¹ * o = 1

        Raises:
            ZeroDivisionError: If magnitude is zero
        """
        mag_sq = self.magnitude() ** 2
        if mag_sq == 0:
            raise ZeroDivisionError("Cannot invert zero octonion")
        conj = self.conjugate()
        return OctonionNumber(
            conj.w / mag_sq,
            conj.x / mag_sq,
            conj.y / mag_sq,
            conj.z / mag_sq,
            conj.e / mag_sq,
            conj.f / mag_sq,
            conj.g / mag_sq,
            conj.h / mag_sq,
        )

    def dot(self, other: "OctonionNumber") -> float:
        """
        Compute the dot product with another octonion.

        Args:
            other: Another OctonionNumber

        Returns:
            float: Dot product (sum of component-wise products)
        """
        if not isinstance(other, OctonionNumber):
            raise TypeError("Dot product requires another OctonionNumber")

        return sum(a * b for a, b in zip(self.coeffs, other.coeffs))

    def normalize(self) -> "OctonionNumber":
        """
        Return a normalized (unit) version of this octonion.

        Returns:
            OctonionNumber with magnitude 1

        Raises:
            ZeroDivisionError: If magnitude is zero
        """
        mag = self.magnitude()
        if mag == 0:
            raise ZeroDivisionError("Cannot normalize zero octonion")

        return OctonionNumber(
            self.w / mag,
            self.x / mag,
            self.y / mag,
            self.z / mag,
            self.e / mag,
            self.f / mag,
            self.g / mag,
            self.h / mag,
        )

    def phase(self) -> float:
        """
        Get the phase (angle) of the octonion.

        Returns:
            float: Phase angle in radians
        """
        return self._phase

    # Operator overloads
    def __add__(self, other: Union["OctonionNumber", float, int]) -> "OctonionNumber":
        if isinstance(other, OctonionNumber):
            return OctonionNumber(
                self.w + other.w,
                self.x + other.x,
                self.y + other.y,
                self.z + other.z,
                self.e + other.e,
                self.f + other.f,
                self.g + other.g,
                self.h + other.h,
            )
        elif isinstance(other, (int, float)):
            return OctonionNumber(
                self.w + other, self.x, self.y, self.z, self.e, self.f, self.g, self.h
            )
        return NotImplemented

    def __radd__(self, other: Union[float, int]) -> "OctonionNumber":
        return self.__add__(other)

    def __sub__(self, other: Union["OctonionNumber", float, int]) -> "OctonionNumber":
        if isinstance(other, OctonionNumber):
            return OctonionNumber(
                self.w - other.w,
                self.x - other.x,
                self.y - other.y,
                self.z - other.z,
                self.e - other.e,
                self.f - other.f,
                self.g - other.g,
                self.h - other.h,
            )
        elif isinstance(other, (int, float)):
            return OctonionNumber(
                self.w - other, self.x, self.y, self.z, self.e, self.f, self.g, self.h
            )
        return NotImplemented

    def __rsub__(self, other: Union[float, int]) -> "OctonionNumber":
        if isinstance(other, (int, float)):
            return OctonionNumber(
                other - self.w,
                -self.x,
                -self.y,
                -self.z,
                -self.e,
                -self.f,
                -self.g,
                -self.h,
            )
        return NotImplemented

    def __mul__(self, other: Union["OctonionNumber", float, int]) -> "OctonionNumber":
        if isinstance(other, OctonionNumber):
            # Octonion multiplication (non-commutative, non-associative)
            w = (
                self.w * other.w
                - self.x * other.x
                - self.y * other.y
                - self.z * other.z
                - self.e * other.e
                - self.f * other.f
                - self.g * other.g
                - self.h * other.h
            )
            x = (
                self.w * other.x
                + self.x * other.w
                + self.y * other.z
                - self.z * other.y
                + self.e * other.f
                - self.f * other.e
                + self.g * other.h
                - self.h * other.g
            )
            y = (
                self.w * other.y
                - self.x * other.z
                + self.y * other.w
                + self.z * other.x
                + self.e * other.g
                - self.g * other.e
                - self.f * other.h
                + self.h * other.f
            )
            z = (
                self.w * other.z
                + self.x * other.y
                - self.y * other.x
                + self.z * other.w
                + self.e * other.h
                - self.h * other.e
                + self.f * other.g
                - self.g * other.f
            )
            e = (
                self.w * other.e
                - self.x * other.f
                - self.y * other.g
                - self.z * other.h
                + self.e * other.w
                + self.f * other.x
                + self.g * other.y
                + self.h * other.z
            )
            f = (
                self.w * other.f
                + self.x * other.e
                - self.y * other.h
                + self.z * other.g
                - self.e * other.x
                + self.f * other.w
                - self.g * other.z
                + self.h * other.y
            )
            g = (
                self.w * other.g
                + self.x * other.h
                + self.y * other.e
                - self.z * other.f
                - self.e * other.y
                + self.f * other.z
                + self.g * other.w
                - self.h * other.x
            )
            h = (
                self.w * other.h
                - self.x * other.g
                + self.y * other.f
                + self.z * other.e
                - self.e * other.z
                - self.f * other.y
                + self.g * other.x
                + self.h * other.w
            )

            return OctonionNumber(w, x, y, z, e, f, g, h)

        elif isinstance(other, (int, float)):
            # Scalar multiplication
            return OctonionNumber(
                self.w * other,
                self.x * other,
                self.y * other,
                self.z * other,
                self.e * other,
                self.f * other,
                self.g * other,
                self.h * other,
            )

        return NotImplemented

    def __rmul__(self, other: Union[float, int]) -> "OctonionNumber":
        return self.__mul__(other)

    def __truediv__(self, scalar: Union[float, int]) -> "OctonionNumber":
        if isinstance(scalar, (int, float)):
            if scalar == 0:
                raise ZeroDivisionError("Cannot divide octonion by zero")
            return OctonionNumber(
                self.w / scalar,
                self.x / scalar,
                self.y / scalar,
                self.z / scalar,
                self.e / scalar,
                self.f / scalar,
                self.g / scalar,
                self.h / scalar,
            )
        return NotImplemented
        if isinstance(other, (int, float, Fraction)):
            scalar = float(other)
            return self.__class__([c / scalar for c in self.coeffs])

    def __neg__(self) -> "OctonionNumber":
        return OctonionNumber(
            -self.w, -self.x, -self.y, -self.z, -self.e, -self.f, -self.g, -self.h
        )

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, OctonionNumber):
            return False

        tol = 1e-12
        return all(abs(a - b) < tol for a, b in zip(self.coeffs, other.coeffs))

    def __ne__(self, other: object) -> bool:
        return not self.__eq__(other)

    def __hash__(self) -> int:
        # Round to avoid floating-point precision issues
        return hash(tuple(round(c, 10) for c in self.coeffs))

    def __str__(self) -> str:
        return (
            f"Octonion({self.w:.6f}, {self.x:.6f}, {self.y:.6f}, {self.z:.6f}, "
            f"{self.e:.6f}, {self.f:.6f}, {self.g:.6f}, {self.h:.6f})"
        )

    def __repr__(self) -> str:
        return (
            f"OctonionNumber({self.w}, {self.x}, {self.y}, {self.z}, "
            f"{self.e}, {self.f}, {self.g}, {self.h})"
        )

    def to_tuple(self) -> Tuple[float, ...]:
        """Convert to tuple."""
        return tuple(self.coeffs)

    def to_numpy(self) -> np.ndarray:
        """Convert to numpy array."""
        return np.array(self.coeffs, dtype=np.float64)

    def copy(self) -> "OctonionNumber":
        """Create a copy of this octonion."""
        return OctonionNumber(*self.coeffs)


# Bazı önemli oktonyon sabitleri
ZERO = OctonionNumber(0, 0, 0, 0, 0, 0, 0, 0)
ONE = OctonionNumber(1, 0, 0, 0, 0, 0, 0, 0)
I = OctonionNumber(0, 1, 0, 0, 0, 0, 0, 0)
J = OctonionNumber(0, 0, 1, 0, 0, 0, 0, 0)
K = OctonionNumber(0, 0, 0, 1, 0, 0, 0, 0)
E = OctonionNumber(0, 0, 0, 0, 1, 0, 0, 0)
F = OctonionNumber(0, 0, 0, 0, 0, 1, 0, 0)
G = OctonionNumber(0, 0, 0, 0, 0, 0, 1, 0)
H = OctonionNumber(0, 0, 0, 0, 0, 0, 0, 1)


class Constants:
    """Oktonyon sabitleri (alias'lar)."""

    ZERO = ZERO
    ONE = ONE
    I = I
    J = J
    K = K
    E = E
    F = F
    G = G
    H = H


# ============================================================================
# NÖTROSOFİK SAYI SINIFI (Ana Sınıf)
# ============================================================================


[docs] @dataclass class NeutrosophicNumber: """ Nötrosofik sayı sınıfı: t + iI + fF formunda t = doğruluk değeri (truth) i = belirsizlik değeri (indeterminacy) f = yanlışlık değeri (falsity) """ t: float = 0.0 # truth (doğruluk) i: float = 0.0 # indeterminacy (belirsizlik) f: float = 0.0 # falsity (yanlışlık) def __post_init__(self): """Değerleri float'a çevir ve normalize et""" self.t = float(self.t) self.i = float(self.i) self.f = float(self.f) # ===== TEMEL OPERATÖRLER ===== def __add__(self, other: Any) -> "NeutrosophicNumber": """Toplama operatörü""" if isinstance(other, NeutrosophicNumber): return NeutrosophicNumber( self.t + other.t, self.i + other.i, self.f + other.f ) elif isinstance(other, (int, float)): return NeutrosophicNumber(self.t + other, self.i, self.f) return NotImplemented def __radd__(self, other: Any) -> "NeutrosophicNumber": """Sağdan toplama""" return self.__add__(other) def __sub__(self, other: Any) -> "NeutrosophicNumber": """Çıkarma operatörü""" if isinstance(other, NeutrosophicNumber): return NeutrosophicNumber( self.t - other.t, self.i - other.i, self.f - other.f ) elif isinstance(other, (int, float)): return NeutrosophicNumber(self.t - other, self.i, self.f) return NotImplemented def __rsub__(self, other: Any) -> "NeutrosophicNumber": """Sağdan çıkarma""" if isinstance(other, (int, float)): return NeutrosophicNumber(other - self.t, -self.i, -self.f) return NotImplemented def __mul__(self, other: Any) -> "NeutrosophicNumber": """Çarpma operatörü""" if isinstance(other, NeutrosophicNumber): # Nötrosofik çarpma kuralı return NeutrosophicNumber( t=self.t * other.t, i=self.t * other.i + self.i * other.t + self.i * other.i, f=self.t * other.f + self.f * other.t + self.f * other.f, ) elif isinstance(other, (int, float)): return NeutrosophicNumber(self.t * other, self.i * other, self.f * other) return NotImplemented def __rmul__(self, other: Any) -> "NeutrosophicNumber": """Sağdan çarpma""" return self.__mul__(other) def __truediv__(self, other: Any) -> "NeutrosophicNumber": """Bölme operatörü (sadece skaler bölme)""" if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError("Sıfıra bölme hatası!") return NeutrosophicNumber(self.t / other, self.i / other, self.f / other) return NotImplemented def __rtruediv__(self, other: Any) -> "NeutrosophicNumber": """Sağdan bölme""" if isinstance(other, (int, float)): return NeutrosophicNumber( other / self.t if self.t != 0 else float("inf"), other / self.i if self.i != 0 else float("inf"), other / self.f if self.f != 0 else float("inf"), ) return NotImplemented def __floordiv__(self, other: Any) -> "NeutrosophicNumber": """Tam bölme""" if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError("Sıfıra bölme hatası!") return NeutrosophicNumber(self.t // other, self.i // other, self.f // other) return NotImplemented def __mod__(self, other: Any) -> "NeutrosophicNumber": """Mod operatörü""" if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError("Sıfıra mod alma hatası!") return NeutrosophicNumber(self.t % other, self.i % other, self.f % other) return NotImplemented def __pow__(self, exponent: Any) -> "NeutrosophicNumber": """Üs alma""" if isinstance(exponent, (int, float)): return NeutrosophicNumber( self.t**exponent, self.i**exponent, self.f**exponent ) return NotImplemented def __neg__(self) -> "NeutrosophicNumber": """Negatif operatörü""" return NeutrosophicNumber(-self.t, -self.i, -self.f) def __pos__(self) -> "NeutrosophicNumber": """Pozitif operatörü""" return self def __abs__(self) -> "NeutrosophicNumber": """Mutlak değer""" return NeutrosophicNumber(abs(self.t), abs(self.i), abs(self.f)) # ===== KARŞILAŞTIRMA OPERATÖRLERİ ===== def __eq__(self, other: Any) -> bool: """Eşitlik kontrolü""" if not isinstance(other, NeutrosophicNumber): return NotImplemented return ( math.isclose(self.t, other.t, abs_tol=1e-12) and math.isclose(self.i, other.i, abs_tol=1e-12) and math.isclose(self.f, other.f, abs_tol=1e-12) ) def __ne__(self, other: Any) -> bool: """Eşitsizlik kontrolü""" return not self.__eq__(other) def __lt__(self, other: Any) -> bool: """Küçüktür (gerçek kısım üzerinden)""" if isinstance(other, NeutrosophicNumber): return self.t < other.t return NotImplemented def __le__(self, other: Any) -> bool: """Küçük eşit""" if isinstance(other, NeutrosophicNumber): return self.t <= other.t return NotImplemented def __gt__(self, other: Any) -> bool: """Büyüktür""" if isinstance(other, NeutrosophicNumber): return self.t > other.t return NotImplemented def __ge__(self, other: Any) -> bool: """Büyük eşit""" if isinstance(other, NeutrosophicNumber): return self.t >= other.t return NotImplemented # ===== STRING TEMSİLLERİ ===== def __str__(self) -> str: """String temsili: t + iI + fF""" parts = [] if abs(self.t) > 1e-12: parts.append(f"{self.t:.6g}") if abs(self.i) > 1e-12: parts.append(f"{self.i:.6g}I") if abs(self.f) > 1e-12: parts.append(f"{self.f:.6g}F") return " + ".join(parts) if parts else "0" def __repr__(self) -> str: """Repr temsili""" return f"NeutrosophicNumber(t={self.t}, i={self.i}, f={self.f})" # ===== YARDIMCI METODLAR =====
[docs] def conjugate(self) -> "NeutrosophicNumber": """Nötrosofik eşlenik (belirsizlik ve yanlışlık işaret değiştirir)""" return NeutrosophicNumber(self.t, -self.i, -self.f)
[docs] def magnitude(self) -> float: """Euclidean norm (büyüklük)""" return math.sqrt(self.t**2 + self.i**2 + self.f**2)
[docs] def normalized(self) -> "NeutrosophicNumber": """Birim büyüklüğe normalize edilmiş sayı""" mag = self.magnitude() if mag == 0: return NeutrosophicNumber(0, 0, 0) return self / mag
[docs] def score(self) -> float: """Net skor: doğruluk - yanlışlık""" return self.t - self.f
[docs] def accuracy(self) -> float: """Doğruluk değeri""" return self.t
[docs] def uncertainty(self) -> float: """Belirsizlik seviyesi""" return self.i
[docs] def to_tuple(self) -> Tuple[float, float, float]: """Tuple temsili""" return (self.t, self.i, self.f)
[docs] @classmethod def from_tuple(cls, tpl: Tuple[float, float, float]) -> "NeutrosophicNumber": """Tuple'dan oluştur""" return cls(*tpl)
[docs] @classmethod def truth(cls, value: float) -> "NeutrosophicNumber": """Sadece doğruluk değeri içeren sayı""" return cls(t=value, i=0.0, f=0.0)
[docs] @classmethod def indeterminacy(cls, value: float) -> "NeutrosophicNumber": """Sadece belirsizlik içeren sayı""" return cls(t=0.0, i=value, f=0.0)
[docs] @classmethod def falsity(cls, value: float) -> "NeutrosophicNumber": """Sadece yanlışlık içeren sayı""" return cls(t=0.0, i=0.0, f=value)
[docs] @classmethod def from_string(cls, s: str) -> "NeutrosophicNumber": """String ifadeden oluştur (örn: '3+2I+1F' veya '3+2I')""" t = i = f = 0.0 s = s.replace(" ", "") # I ve F parçalarını ayır parts = s.split("+") for part in parts: if "I" in part: i = float(part.replace("I", "")) elif "F" in part: f = float(part.replace("F", "")) else: t = float(part) if part else 0 return cls(t, i, f)
# ============================================================================ # NÖTROSOFİK KARMAŞIK SAYI SINIFI # ============================================================================
[docs] @dataclass class NeutrosophicComplexNumber: """ Nötrosofik karmaşık sayı: (a + bj) + cI formunda a = gerçel kısım, b = sanal kısım, c = belirsizlik """ real: float = 0.0 imag: float = 0.0 indeterminacy: float = 0.0 def __post_init__(self): """Değerleri float'a çevir""" self.real = float(self.real) self.imag = float(self.imag) self.indeterminacy = float(self.indeterminacy) @property def complex_part(self) -> complex: """Karmaşık kısmı döndür""" return complex(self.real, self.imag) # ===== TEMEL OPERATÖRLER ===== def __add__(self, other: Any) -> "NeutrosophicComplexNumber": """Toplama""" if isinstance(other, NeutrosophicComplexNumber): return NeutrosophicComplexNumber( self.real + other.real, self.imag + other.imag, self.indeterminacy + other.indeterminacy, ) elif isinstance(other, (int, float)): return NeutrosophicComplexNumber( self.real + other, self.imag, self.indeterminacy ) elif isinstance(other, complex): return NeutrosophicComplexNumber( self.real + other.real, self.imag + other.imag, self.indeterminacy ) return NotImplemented def __radd__(self, other: Any) -> "NeutrosophicComplexNumber": """Sağdan toplama""" return self.__add__(other) def __sub__(self, other: Any) -> "NeutrosophicComplexNumber": """Çıkarma""" if isinstance(other, NeutrosophicComplexNumber): return NeutrosophicComplexNumber( self.real - other.real, self.imag - other.imag, self.indeterminacy - other.indeterminacy, ) elif isinstance(other, (int, float)): return NeutrosophicComplexNumber( self.real - other, self.imag, self.indeterminacy ) elif isinstance(other, complex): return NeutrosophicComplexNumber( self.real - other.real, self.imag - other.imag, self.indeterminacy ) return NotImplemented def __rsub__(self, other: Any) -> "NeutrosophicComplexNumber": """Sağdan çıkarma""" if isinstance(other, (int, float)): return NeutrosophicComplexNumber( other - self.real, -self.imag, -self.indeterminacy ) elif isinstance(other, complex): return NeutrosophicComplexNumber( other.real - self.real, other.imag - self.imag, -self.indeterminacy ) return NotImplemented def __mul__(self, other: Any) -> "NeutrosophicComplexNumber": """Çarpma""" if isinstance(other, NeutrosophicComplexNumber): # Karmaşık çarpma new_real = self.real * other.real - self.imag * other.imag new_imag = self.real * other.imag + self.imag * other.real # Belirsizlik yayılımı mag_sq_self = self.real**2 + self.imag**2 mag_sq_other = other.real**2 + other.imag**2 new_indeterminacy = ( self.indeterminacy + other.indeterminacy + mag_sq_self * other.indeterminacy + mag_sq_other * self.indeterminacy ) return NeutrosophicComplexNumber(new_real, new_imag, new_indeterminacy) elif isinstance(other, complex): new_real = self.real * other.real - self.imag * other.imag new_imag = self.real * other.imag + self.imag * other.real return NeutrosophicComplexNumber(new_real, new_imag, self.indeterminacy) elif isinstance(other, (int, float)): return NeutrosophicComplexNumber( self.real * other, self.imag * other, self.indeterminacy * other ) return NotImplemented def __rmul__(self, other: Any) -> "NeutrosophicComplexNumber": """Sağdan çarpma""" return self.__mul__(other) def __truediv__(self, other: Any) -> "NeutrosophicComplexNumber": """Bölme (sadece skaler)""" if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError("Sıfıra bölme hatası!") return NeutrosophicComplexNumber( self.real / other, self.imag / other, self.indeterminacy / other ) return NotImplemented def __neg__(self) -> "NeutrosophicComplexNumber": """Negatif""" return NeutrosophicComplexNumber(-self.real, -self.imag, -self.indeterminacy) def __abs__(self) -> float: """Büyüklük""" complex_mag = math.sqrt(self.real**2 + self.imag**2) return math.sqrt(complex_mag**2 + self.indeterminacy**2) # ===== KARŞILAŞTIRMA ===== def __eq__(self, other: Any) -> bool: """Eşitlik kontrolü""" if not isinstance(other, NeutrosophicComplexNumber): return NotImplemented return ( math.isclose(self.real, other.real, abs_tol=1e-12) and math.isclose(self.imag, other.imag, abs_tol=1e-12) and math.isclose(self.indeterminacy, other.indeterminacy, abs_tol=1e-12) ) # ===== STRING TEMSİLLERİ ===== def __str__(self) -> str: """String temsili""" parts = [] if abs(self.real) > 1e-12 or abs(self.imag) > 1e-12: if abs(self.imag) < 1e-12: parts.append(f"{self.real:.6g}") else: parts.append(f"({self.real:.6g}{self.imag:+.6g}j)") if abs(self.indeterminacy) > 1e-12: parts.append(f"{self.indeterminacy:.6g}I") return " + ".join(parts) if parts else "0" def __repr__(self) -> str: """Repr temsili""" return f"NeutrosophicComplexNumber(real={self.real}, imag={self.imag}, indeterminacy={self.indeterminacy})" # ===== YARDIMCI METODLAR =====
[docs] def conjugate(self) -> "NeutrosophicComplexNumber": """Karmaşık eşlenik (belirsizlik değişmez)""" return NeutrosophicComplexNumber(self.real, -self.imag, self.indeterminacy)
[docs] def magnitude_sq(self) -> float: """Karmaşık kısmın büyüklük karesi""" return self.real**2 + self.imag**2
[docs] def phase(self) -> float: """Faz açısı""" if abs(self.real) < 1e-12 and abs(self.imag) < 1e-12: return 0.0 return math.atan2(self.imag, self.real)
[docs] def to_polar(self) -> Tuple[float, float, float]: """Kutupsal koordinatlara dönüşüm""" r = math.sqrt(self.real**2 + self.imag**2) theta = self.phase() return (r, theta, self.indeterminacy)
[docs] @classmethod def from_polar( cls, r: float, theta: float, indeterminacy: float = 0.0 ) -> "NeutrosophicComplexNumber": """Kutupsal koordinatlardan oluştur""" return cls(r * math.cos(theta), r * math.sin(theta), indeterminacy)
[docs] @classmethod def from_complex( cls, z: complex, indeterminacy: float = 0.0 ) -> "NeutrosophicComplexNumber": """Karmaşık sayıdan oluştur""" return cls(z.real, z.imag, indeterminacy)
@dataclass class HyperrealNumber: """Represents a hyperreal number as a sequence of real numbers.""" sequence: List[float] def __init__(self, *args): if len(args) == 1 and isinstance(args[0], list): self.sequence = args[0] else: self.sequence = list(args) def __add__(self, other: Any) -> "HyperrealNumber": if isinstance(other, HyperrealNumber): # Sequence'leri eşit uzunluğa getir max_len = max(len(self.sequence), len(other.sequence)) seq1 = self.sequence + [0.0] * (max_len - len(self.sequence)) seq2 = other.sequence + [0.0] * (max_len - len(other.sequence)) return HyperrealNumber([a + b for a, b in zip(seq1, seq2)]) elif isinstance(other, (int, float)): new_seq = self.sequence.copy() new_seq[0] += other # Sadece finite part'a ekle return HyperrealNumber(new_seq) return NotImplemented def __sub__(self, other: Any) -> "HyperrealNumber": if isinstance(other, HyperrealNumber): max_len = max(len(self.sequence), len(other.sequence)) seq1 = self.sequence + [0.0] * (max_len - len(self.sequence)) seq2 = other.sequence + [0.0] * (max_len - len(other.sequence)) return HyperrealNumber([a - b for a, b in zip(seq1, seq2)]) elif isinstance(other, (int, float)): new_seq = self.sequence.copy() new_seq[0] -= other return HyperrealNumber(new_seq) return NotImplemented def __mul__(self, scalar: float) -> "HyperrealNumber": if isinstance(scalar, (int, float)): return HyperrealNumber([x * scalar for x in self.sequence]) return NotImplemented def __rmul__(self, scalar: float) -> "HyperrealNumber": return self.__mul__(scalar) def __truediv__(self, divisor: float) -> "HyperrealNumber": if isinstance(divisor, (int, float)): if divisor == 0: raise ZeroDivisionError("Scalar division by zero.") return HyperrealNumber([x / divisor for x in self.sequence]) raise TypeError("Only scalar division is supported.") if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __mod__(self, divisor: float) -> "HyperrealNumber": if isinstance(divisor, (int, float)): return HyperrealNumber([x % divisor for x in self.sequence]) raise TypeError("Modulo only supported with a scalar divisor.") def __str__(self) -> str: if len(self.sequence) <= 5: return f"Hyperreal{self.sequence}" return f"Hyperreal({self.sequence[:3]}...)" @property def finite(self): """Returns the finite part (first component)""" return self.sequence[0] if self.sequence else 0.0 @property def infinitesimal(self): """Returns the first infinitesimal part (second component)""" return self.sequence[1] if len(self.sequence) > 1 else 0.0 @dataclass class BicomplexNumber: """Represents a bicomplex number with two complex components.""" z1: complex # First complex component z2: complex # Second complex component def __add__(self, other: Any) -> "BicomplexNumber": if isinstance(other, BicomplexNumber): return BicomplexNumber(self.z1 + other.z1, self.z2 + other.z2) elif isinstance(other, (int, float, complex)): return BicomplexNumber(self.z1 + other, self.z2) else: raise TypeError( f"Unsupported operand type(s) for +: 'BicomplexNumber' and '{type(other).__name__}'" ) def __sub__(self, other: Any) -> "BicomplexNumber": if isinstance(other, BicomplexNumber): return BicomplexNumber(self.z1 - other.z1, self.z2 - other.z2) elif isinstance(other, (int, float, complex)): return BicomplexNumber(self.z1 - other, self.z2) else: raise TypeError( f"Unsupported operand type(s) for -: 'BicomplexNumber' and '{type(other).__name__}'" ) def __mul__(self, other: Any) -> "BicomplexNumber": if isinstance(other, BicomplexNumber): return BicomplexNumber( self.z1 * other.z1 - self.z2 * other.z2, self.z1 * other.z2 + self.z2 * other.z1, ) elif isinstance(other, (int, float, complex)): return BicomplexNumber(self.z1 * other, self.z2 * other) else: raise TypeError( f"Unsupported operand type(s) for *: 'BicomplexNumber' and '{type(other).__name__}'" ) def __truediv__(self, divisor: float) -> "BicomplexNumber": if isinstance(divisor, (int, float)): if divisor == 0: raise ZeroDivisionError("Division by zero") return BicomplexNumber(self.z1 / divisor, self.z2 / divisor) else: raise TypeError("Only scalar division is supported") if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __str__(self) -> str: parts = [] if self.z1 != 0j: parts.append(f"({self.z1.real}+{self.z1.imag}j)") if self.z2 != 0j: parts.append(f"({self.z2.real}+{self.z2.imag}j)e") return " + ".join(parts) if parts else "0" def _parse_bicomplex(s: Any) -> BicomplexNumber: """ Universally parse input into a BicomplexNumber. Features from both versions combined: 1. Type checking and direct returns for BicomplexNumber 2. Handles numeric types (int, float, numpy) -> z1 = num, z2 = 0 3. Handles complex numbers -> z1 = complex, z2 = 0 4. Handles iterables (list, tuple) of 1, 2, or 4 numbers 5. String parsing with multiple formats: - Comma-separated "a,b,c,d" or "a,b" or "a" - Explicit "(a+bj)+(c+dj)e" format - Complex strings like "1+2j", "3j", "4" - Fallback to complex() parsing 6. Robust error handling with logging 7. Final fallback to zero bicomplex Args: s: Input to parse (any type) Returns: Parsed BicomplexNumber or BicomplexNumber(0,0) on failure """ try: # Feature 1: Direct return if already BicomplexNumber if isinstance(s, BicomplexNumber): return s # Feature 2: Handle numeric scalars if isinstance(s, (int, float, np.floating, np.integer)): return BicomplexNumber(complex(float(s), 0.0), complex(0.0, 0.0)) # Feature 3: Handle complex numbers if isinstance(s, complex): return BicomplexNumber(s, complex(0.0, 0.0)) # Feature 4: Handle iterables (non-string) if hasattr(s, "__iter__") and not isinstance(s, str): parts = list(s) if len(parts) == 4: # Four numbers: (z1_real, z1_imag, z2_real, z2_imag) return BicomplexNumber( complex(float(parts[0]), float(parts[1])), complex(float(parts[2]), float(parts[3])), ) elif len(parts) == 2: # Two numbers: (real, imag) for z1 return BicomplexNumber( complex(float(parts[0]), float(parts[1])), complex(0.0, 0.0) ) elif len(parts) == 1: # Single number: real part of z1 return BicomplexNumber(complex(float(parts[0]), 0.0), complex(0.0, 0.0)) # Convert to string for further parsing if not isinstance(s, str): s = str(s) s_clean = s.strip().replace(" ", "") # Feature 5.1: Comma-separated numeric list if "," in s_clean: parts = [p for p in s_clean.split(",") if p != ""] try: nums = [float(p) for p in parts] if len(nums) == 4: return BicomplexNumber( complex(nums[0], nums[1]), complex(nums[2], nums[3]) ) elif len(nums) == 2: return BicomplexNumber(complex(nums[0], nums[1]), complex(0.0, 0.0)) elif len(nums) == 1: return BicomplexNumber(complex(nums[0], 0.0), complex(0.0, 0.0)) except ValueError: # Not purely numeric, continue to other formats pass # Feature 5.2: Explicit "(a+bj)+(c+dj)e" format if "e" in s_clean and "(" in s_clean: # Try both patterns from both versions patterns = [ # From first version r"\(\s*([+-]?\d*\.?\d+)\s*([+-])\s*([\d\.]*)j\s*\)\s*(?:\+)\s*\(\s*([+-]?\d*\.?\d+)\s*([+-])\s*([\d\.]*)j\s*\)e", # From second version r"\(([-\d.]+)\s*([+-]?)\s*([-\d.]*)j\)\s*\+\s*\(([-\d.]+)\s*([+-]?)\s*([-\d.]*)j\)e", ] for pattern in patterns: match = re.search(pattern, s_clean) if match: try: # Parse groups (adapt based on pattern) groups = match.groups() if len(groups) == 6: if pattern == patterns[0]: # First version pattern z1_real = float(groups[0]) z1_imag_sign = -1.0 if groups[1] == "-" else 1.0 z1_imag_val = ( float(groups[2]) if groups[2] not in ["", None] else 1.0 ) z1_imag = z1_imag_sign * z1_imag_val z2_real = float(groups[3]) z2_imag_sign = -1.0 if groups[4] == "-" else 1.0 z2_imag_val = ( float(groups[5]) if groups[5] not in ["", None] else 1.0 ) z2_imag = z2_imag_sign * z2_imag_val else: # Second version pattern z1_real = float(groups[0]) z1_imag_sign = -1 if groups[1] == "-" else 1 z1_imag_val = float(groups[2] or "1") z1_imag = z1_imag_sign * z1_imag_val z2_real = float(groups[3]) z2_imag_sign = -1 if groups[4] == "-" else 1 z2_imag_val = float(groups[5] or "1") z2_imag = z2_imag_sign * z2_imag_val return BicomplexNumber( complex(z1_real, z1_imag), complex(z2_real, z2_imag) ) except Exception: continue # Feature 5.3: Complex number parsing (common patterns) if "j" in s_clean: # If string contains 'j', try to parse as complex try: # Try direct complex() parsing first c = complex(s_clean) return BicomplexNumber(c, complex(0.0, 0.0)) except ValueError: # Try regex-based parsing for malformed complex numbers pattern = r"^([+-]?\d*\.?\d*)([+-]?\d*\.?\d*)j$" match = re.match(pattern, s_clean) if match: real_part = match.group(1) imag_part = match.group(2) # Handle edge cases if real_part in ["", "+", "-"]: real_part = real_part + "1" if real_part else "0" if imag_part in ["", "+", "-"]: imag_part = imag_part + "1" if imag_part else "0" return BicomplexNumber( complex(float(real_part or 0), float(imag_part or 0)), complex(0.0, 0.0), ) # Feature 5.4: Simple real number try: real_val = float(s_clean) return BicomplexNumber(complex(real_val, 0.0), complex(0.0, 0.0)) except ValueError: pass # Feature 6: Fallback - try to extract any numeric part try: num_token = _extract_numeric_part(s_clean) if num_token: return BicomplexNumber( complex(float(num_token), 0.0), complex(0.0, 0.0) ) except Exception: pass except Exception as e: # Feature 7: Logging on error if "logger" in globals(): logger.warning(f"Bicomplex parsing failed for {repr(s)}: {e}") else: print(f"Bicomplex parsing error for '{s}': {e}") # Final fallback: return zero bicomplex return BicomplexNumber(complex(0.0, 0.0), complex(0.0, 0.0)) def _next_power_of_two_at_least(n: int, max_dim: int = 256) -> int: if n <= 1: return 1 p = 1 while p < n and p < max_dim: p <<= 1 return p if p <= max_dim else max_dim def _parse_single_token(tok: Any): """Tek token -> float veya complex; mixed/fraction destekli.""" if tok is None: return 0.0 if isinstance(tok, (int, float, complex)): return tok s = str(tok).strip() if s == "": return 0.0 # normalize imaginary unit (i, I, j, J -> j) s = s.replace("I", "i").replace("J", "j").replace("i", "j") # complex first try: c = complex(s) if c.imag == 0: return float(c.real) return c except Exception: pass # mixed number "a b/c" if " " in s and "/" in s: try: whole, frac = s.split(" ", 1) num, den = frac.split("/") return float(whole) + float(num) / float(den) except Exception: pass # fraction "a/b" if "/" in s: try: num, den = s.split("/") return float(num) / float(den) except Exception: pass # fallback numeric token via regex m = re.search(r"[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?", s) if m: try: return float(m.group(0)) except Exception: pass return 0.0 def _parse_components(value: Any) -> List: """Flexible parsing: iterable, object with coeffs/to_list, string, scalar.""" if value is None: return [] # object helpers try: if hasattr(value, "to_list") and callable(getattr(value, "to_list")): return [_parse_single_token(x) for x in value.to_list()] if hasattr(value, "coeffs") and callable(getattr(value, "coeffs")): return [_parse_single_token(x) for x in value.coeffs()] except Exception: pass # iterable but not string if isinstance(value, (list, tuple)): return [_parse_single_token(x) for x in value] if isinstance(value, (int, float, complex)): return [value] if isinstance(value, str): s = value.strip() # strip surrounding brackets if (s.startswith("[") and s.endswith("]")) or ( s.startswith("(") and s.endswith(")") ): s = s[1:-1].strip() parts = [p.strip() for p in s.split(",")] if "," in s else s.split() # handle single mixed-number token like "1 1/2" if len(parts) == 1 and " " in parts[0] and "/" in parts[0]: parts = [parts[0]] comps = [] for p in parts: if p == "": continue comps.append(_parse_single_token(p)) return comps # fallback try float conversion try: return [float(value)] except Exception: return [0.0] def _pad_or_truncate_list(lst: Iterable, dim: int) -> List: arr = list(lst) if len(arr) < dim: return arr + [0.0] * (dim - len(arr)) return arr[:dim] def _construct_hypercomplex_from_components(HC_cls, comps: List, dimension: int): """ Try common constructor signatures for HypercomplexNumber-like classes. Returns instance or raises TypeError. """ # prefer (list, dimension=dim) try: return HC_cls(comps, dimension=dimension) except TypeError: pass except Exception as e: logger.debug("HC constructor (list, dim) failed: %s", e) # try (*comps, dimension=dim) try: return HC_cls(*comps, dimension=dimension) except TypeError: pass except Exception as e: logger.debug("HC constructor (*comps, dim) failed: %s", e) # try list only try: return HC_cls(comps) except Exception as e: logger.debug("HC constructor (list) failed: %s", e) # try *comps only try: return HC_cls(*comps) except Exception as e: logger.debug("HC constructor (*comps) failed: %s", e) raise TypeError("No compatible Hypercomplex constructor found") def _get_default_hypercomplex(dim: int): """Return a default fallback (list) for given dimension.""" return [0.0] * max(1, int(dim)) # --- Ana fonksiyon ------------------------------------------------------- def _parse_hypercomplex(s: Any, dimension: Optional[int] = None): """ Parse input to HypercomplexNumber (or fallback list) with specific dimension. - If dimension is None, infer from input length or default to 8. - Accepts HypercomplexNumber, scalars, complex, iterables, strings. - Returns HypercomplexNumber instance if class available, else a padded list. """ try: # If already HypercomplexNumber-like, try to adapt try: from .kececinumbers import ( HypercomplexNumber as HC_cls, ) # project class if present except Exception: HC_cls = None # If input is already HC instance and dimension provided, adapt if HC_cls is not None and isinstance(s, HC_cls): if dimension is None or s.dimension == dimension: return ( s if dimension is None else s.pad_to_dimension(dimension) if s.dimension < dimension else s.truncate_to_dimension(dimension) ) # If input is our local HypercomplexNumber (same name but different module), handle generically try: # duck-typing: object with .dimension and .pad_to_dimension/truncate_to_dimension if ( hasattr(s, "dimension") and hasattr(s, "pad_to_dimension") and hasattr(s, "truncate_to_dimension") ): if dimension is None or getattr(s, "dimension", None) == dimension: return ( s if dimension is None else s.pad_to_dimension(dimension) if s.dimension < dimension else s.truncate_to_dimension(dimension) ) except Exception: pass # Scalars and complex if isinstance(s, (int, float)): # infer dimension if not provided dim = int(dimension) if dimension is not None else 8 coeffs = [float(s)] + [0.0] * (dim - 1) if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs if isinstance(s, complex): dim = int(dimension) if dimension is not None else 8 coeffs = [float(s.real), float(s.imag)] + [0.0] * (dim - 2) if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs # Iterable (list, tuple, numpy array, etc.) if hasattr(s, "__iter__") and not isinstance(s, str): comps = list(s) # parse elements to numeric where possible parsed = [_parse_single_token(c) for c in comps] # infer dimension if not provided desired = max(1, len(parsed)) dim = ( int(dimension) if dimension is not None else _next_power_of_two_at_least(desired) ) coeffs = _pad_or_truncate_list(parsed, dim) if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs # String parsing if not isinstance(s, str): s = str(s) s = s.strip() # remove surrounding brackets/braces/parentheses s = s.strip("[]{}()") if s == "": dim = int(dimension) if dimension is not None else 8 coeffs = [0.0] * dim if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs # comma-separated list if "," in s: parts = [p.strip() for p in s.split(",") if p.strip()] parsed = [_parse_single_token(p) for p in parts] desired = max(1, len(parsed)) dim = ( int(dimension) if dimension is not None else _next_power_of_two_at_least(desired) ) coeffs = _pad_or_truncate_list(parsed, dim) if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception as e: logger.debug("HC construct from comma parts failed: %s", e) return coeffs return coeffs # try single numeric try: val = float(s) dim = int(dimension) if dimension is not None else 8 coeffs = [val] + [0.0] * (dim - 1) if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs except Exception: pass # try complex string try: c = complex(s) dim = int(dimension) if dimension is not None else 8 coeffs = [float(c.real), float(c.imag)] + [0.0] * (dim - 2) if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs except Exception: pass # fallback: zeros dim = int(dimension) if dimension is not None else 8 coeffs = [0.0] * dim if HC_cls: try: return _construct_hypercomplex_from_components(HC_cls, coeffs, dim) except Exception: return coeffs return coeffs except Exception as e: warnings.warn( f"Hypercomplex parse error (dim={dimension}) for input {repr(s)}: {e}", RuntimeWarning, ) logger.exception("Hypercomplex parse error") return _get_default_hypercomplex(dimension or 8) def _parse_universal(s: Union[str, Any], target_type: str) -> Any: """ Universal parser for many numeric/hypercomplex target types. Returns parsed value or a safe default on error. """ try: if target_type is None: warnings.warn("target_type is None", RuntimeWarning) return _get_default_value(target_type) key = str(target_type).strip().lower() # --- Special-case direct parsers if available --- # bicomplex if key == "bicomplex": parser = globals().get("_parse_bicomplex") if callable(parser): try: return parser(s) except Exception as e: warnings.warn(f"_parse_bicomplex failed: {e}", RuntimeWarning) return _get_default_value("bicomplex") return _get_default_value("bicomplex") # complex if key == "complex": parser = globals().get("_parse_complex") if callable(parser): try: return parser(s) except Exception as e: warnings.warn(f"_parse_complex failed: {e}", RuntimeWarning) return _get_default_value("complex") # fallback: try Python complex() try: return complex(s) except Exception: return _get_default_value("complex") # real if key == "real" or key == "float": try: if s is None: return 0.0 if isinstance(s, (int, float)): return float(s) if isinstance(s, complex): return float(s.real) # try complex parser then take real part cparser = globals().get("_parse_complex") if callable(cparser): try: c = cparser(s) return float(getattr(c, "real", float(c))) except Exception: pass # last resort return float(str(s).strip()) except Exception as e: warnings.warn(f"Real parse error: {e}", RuntimeWarning) return _get_default_value("real") # --- Hypercomplex families with explicit dimensions --- hyper_map = { "quaternion": 4, "octonion": 8, "sedenion": 16, "pathion": 32, "chingon": 64, "routon": 128, "voudon": 256, } if key in hyper_map: dim = hyper_map[key] parser = globals().get("_parse_hypercomplex") if callable(parser): try: return parser(s, dim) except Exception as e: warnings.warn( f"_parse_hypercomplex(dim={dim}) failed: {e}", RuntimeWarning ) return _get_default_value(key) # fallback: try generic _parse_hypercomplex with dimension if available return _get_default_value(key) # generic hypercomplex or hypercomplex_N pattern if key == "hypercomplex" or key.startswith("hypercomplex"): # try generic parser first parser = globals().get("_parse_hypercomplex") if callable(parser): try: # if parser expects dimension, try to infer default (4) try: return parser(s, 4) except TypeError: # parser may accept only (s) and embed dimension return parser(s) except Exception: pass # try pattern hypercomplex_<N> or hypercomplexN m = re.match(r"hypercomplex[_-]?(\d+)$", key) if m: try: dim = int(m.group(1)) parser = globals().get("_parse_hypercomplex") if callable(parser): try: return parser(s, dim) except Exception: pass # fallback to default factory return _get_default_value(f"hypercomplex_{dim}") except Exception: return _get_default_value("hypercomplex") # final fallback: try to create a small hypercomplex (dim=4) return _get_default_value("hypercomplex") or _get_default_value( "quaternion" ) # If unknown but numeric-like, try to coerce to float or complex try: if isinstance(s, (int, float)): return s if isinstance(s, complex): return s # try numeric string s_str = str(s).strip() if s_str: # try int/float then complex try: return float(s_str) except Exception: try: return complex(s_str) except Exception: pass except Exception: pass # Unknown target_type: warn and return default warnings.warn(f"Unknown target_type: {target_type}", RuntimeWarning) return _get_default_value(target_type) except Exception as e: warnings.warn(f"Universal parser error for {target_type}: {e}", RuntimeWarning) # try to return a default value if available try: return _get_default_value(target_type) except Exception: return None # Mevcut _parse_complex fonksiyonunuzu aynen koruyoruz def _parse_complex(s) -> complex: """Bir string'i veya sayıyı complex sayıya dönüştürür. "real,imag", "real+imag(i/j)", "real", "imag(i/j)" formatlarını destekler. Float ve int tiplerini de doğrudan kabul eder. """ # Eğer zaten complex sayıysa doğrudan döndür if isinstance(s, complex): return s # Eğer HypercomplexNumber ise, ilk iki bileşeni kullan if isinstance(s, HypercomplexNumber): if s.dimension >= 2: return complex(s[0], s[1]) else: return complex(s.real, 0.0) # Eğer float veya int ise doğrudan complex'e dönüştür if isinstance(s, (float, int)): return complex(s) # String işlemleri için önce string'e dönüştür if isinstance(s, str): s = s.strip().replace("J", "j").replace("i", "j") # Hem J hem i yerine j kullan else: s = str(s).strip().replace("J", "j").replace("i", "j") # 1. Eğer "real,imag" formatındaysa if "," in s: parts = s.split(",") if len(parts) == 2: try: return complex(float(parts[0]), float(parts[1])) except ValueError: pass # Devam et # 2. Python'ın kendi complex() dönüştürücüsünü kullanmayı dene (örn: "1+2j", "3j", "-5") try: return complex(s) except ValueError: # 3. Sadece real kısmı varsa (örn: "5") try: return complex(float(s), 0) except ValueError: # 4. Sadece sanal kısmı varsa (örn: "2j", "j") if s.endswith("j"): try: imag_val = float(s[:-1]) if s[:-1] else 1.0 # "j" -> 1.0j return complex(0, imag_val) except ValueError: pass # 5. Fallback: varsayılan kompleks sayı warnings.warn( f"Geçersiz kompleks sayı formatı: '{s}', 0+0j döndürülüyor", RuntimeWarning, ) return complex(0, 0) def _make_hypercomplex_zero(dim: int) -> Any: """Try to construct a hypercomplex zero value for given dimension.""" # try module-level constructors if available for name in ( "HypercomplexNumber", "HyperComplex", "HyperComplexNumber", "Quaternion", "Octonion", ): cls = globals().get(name) if cls is not None: try: # try common constructor signatures try: return cls(*([0.0] * dim), dimension=dim) except TypeError: pass try: return cls(*([0.0] * dim)) except TypeError: pass try: return cls([0.0] * dim) except TypeError: pass try: return cls(0) except Exception: pass except Exception: continue # try module-level parser parser_name = f"_parse_hypercomplex_{dim}" parser = globals().get(parser_name) or globals().get("_parse_hypercomplex") if parser is not None: try: return parser("0") except Exception: pass # try to import a local module that may provide a constructor try: from .kececinumbers import HypercomplexNumber as _HC try: return _HC(*([0.0] * dim), dimension=dim) except Exception: try: return _HC(*([0.0] * dim)) except Exception: pass except Exception: pass # fallback to numpy array of zeros if numpy available try: import numpy as _np return _np.zeros(dim, dtype=float) except Exception: pass # final fallback: plain Python list of zeros return [0.0] * dim def _get_default_value(target_type: str) -> Any: """Get default value for target type in a broad, robust way.""" # helper to try parser names def try_parser(*names): for n in names: p = globals().get(n) if p is not None: try: return p("0") except Exception: continue return None # mapping for fixed known types and dimensions mapping = { "real": lambda: 0.0, "float": lambda: 0.0, "int": lambda: 0, "complex": lambda: complex(0, 0), "bicomplex": lambda: try_parser("_parse_bicomplex", "_parse_bi_complex"), "superreal": lambda: try_parser("_parse_superreal"), "ternary": lambda: try_parser("_parse_ternary"), # named hypercomplex families with explicit dimensions "quaternion": lambda: _make_hypercomplex_zero(4), "octonion": lambda: _make_hypercomplex_zero(8), "sedenion": lambda: _make_hypercomplex_zero(16), "pathion": lambda: _make_hypercomplex_zero(32), "chingon": lambda: _make_hypercomplex_zero(64), "routon": lambda: _make_hypercomplex_zero(128), "voudon": lambda: _make_hypercomplex_zero(256), # generic hypercomplex: try parser, then try small dims, then None "hypercomplex": lambda: ( try_parser("_parse_hypercomplex") or _make_hypercomplex_zero(4) or _make_hypercomplex_zero(8) or _make_hypercomplex_zero(16) or None ), } key = (target_type or "").lower() factory = mapping.get(key) if factory is None: # try pattern like hypercomplex<N> or hypercomplex_N import re m = re.match(r"hypercomplex[_-]?(\d+)$", key) if m: try: dim = int(m.group(1)) return _make_hypercomplex_zero(dim) except Exception: return None return None try: return factory() except Exception: return None def _parse_real(s: Any) -> float: """Parse input as real number (float).""" try: if isinstance(s, (int, float)): return float(s) if isinstance(s, complex): return float(s.real) if isinstance(s, HypercomplexNumber): return float(s.real) if not isinstance(s, str): s = str(s) s = s.strip() return float(s) except Exception as e: warnings.warn(f"Real parse error: {e}", RuntimeWarning) return 0.0 def kececi_bicomplex_algorithm( start: BicomplexNumber, add_val: BicomplexNumber, iterations: int, include_intermediate: bool = True, mod_value: float = 100.0, ) -> list: """ Gerçek Keçeci algoritmasının bikompleks versiyonunu uygular. Bu algoritma orijinal Keçeci sayı üretecini bikompleks sayılara genişletir. Parametreler: ------------ start : BicomplexNumber Algoritmanın başlangıç değeri add_val : BicomplexNumber Her iterasyonda eklenen değer iterations : int İterasyon sayısı include_intermediate : bool, varsayılan=True Ara adımları dizie ekleme mod_value : float, varsayılan=100.0 Mod işlemi için kullanılacak değer Döndürür: -------- list[BicomplexNumber] Üretilen Keçeci bikompleks dizisi Özellikler: ---------- 1. Toplama işlemi 2. Mod alma işlemi (Keçeci algoritmasının karakteristik özelliği) 3. Ara adımların eklenmesi (isteğe bağlı) 4. Asal sayı kontrolü 5. Sıfır değerinde resetleme """ sequence = [start] current = start for i in range(iterations): # 1. Toplama işlemi current = current + add_val # 2. Keçeci algoritmasının özelliği: Mod alma # z1 ve z2 için mod alma (gerçek ve sanal kısımlar ayrı ayrı) current = BicomplexNumber( complex(current.z1.real % mod_value, current.z1.imag % mod_value), complex(current.z2.real % mod_value, current.z2.imag % mod_value), ) # 3. Ara adımları ekle (Keçeci algoritmasının karakteristik özelliği) if include_intermediate: # Ara değerler için özel işlemler intermediate = current * BicomplexNumber(complex(0.5, 0), complex(0, 0)) sequence.append(intermediate) sequence.append(current) # 4. Asal sayı kontrolü (Keçeci algoritmasının önemli bir parçası) # Bu kısım algoritmanın detayına göre özelleştirilebilir magnitude = abs(current.z1) + abs(current.z2) if magnitude > 1: # Basit asallık testi (büyük sayılar için verimsiz) is_prime = True sqrt_mag = int(magnitude**0.5) + 1 for j in range(2, sqrt_mag): if magnitude % j == 0: is_prime = False break if is_prime: print(f"Keçeci Prime bulundu - adım {i}: büyüklük = {magnitude:.2f}") # 5. Özel durum: Belirli değerlere ulaşıldığında resetleme if abs(current.z1) < 1e-10 and abs(current.z2) < 1e-10: current = start # Başa dön return sequence def kececi_bicomplex_advanced( start: BicomplexNumber, add_val: BicomplexNumber, iterations: int, include_intermediate: bool = True, mod_real: float = 50.0, mod_imag: float = 50.0, feedback_interval: int = 10, ) -> list: """ Gelişmiş Keçeci algoritması - daha karmaşık matematiksel işlemler içerir. Bu algoritma standart Keçeci algoritmasını daha gelişmiş matematiksel işlemlerle genişletir: doğrusal olmayan dönüşümler, modüler aritmetik, çapraz çarpımlar ve dinamik feedback mekanizmaları. Parametreler: ------------ start : BicomplexNumber Algoritmanın başlangıç değeri add_val : BicomplexNumber Her iterasyonda eklenen değer iterations : int İterasyon sayısı include_intermediate : bool, varsayılan=True Ara adımları (çapraz çarpımları) dizie ekleme mod_real : float, varsayılan=50.0 Gerçel kısımlar için mod değeri mod_imag : float, varsayılan=50.0 Sanal kısımlar için mod değeri feedback_interval : int, varsayılan=10 Feedback perturbasyonlarının uygulanma aralığı Döndürür: -------- list[BicomplexNumber] Üretilen gelişmiş Keçeci bikompleks dizisi Özellikler: ---------- 1. Temel toplama işlemi 2. Doğrusal olmayan dönüşümler (karekök) 3. Modüler aritmetik 4. Çapraz çarpım ara değerleri 5. Dinamik feedback perturbasyonları """ sequence = [start] current = start for i in range(iterations): # 1. Temel toplama current = current + add_val # 2. Doğrusal olmayan dönüşümler (Keçeci algoritmasının özelliği) # Karekök alma işlemleri - negatif değerler için güvenli hale getirildi try: z1_real_sqrt = math.sqrt(abs(current.z1.real)) * ( 1 if current.z1.real >= 0 else 1j ) z1_imag_sqrt = math.sqrt(abs(current.z1.imag)) * ( 1 if current.z1.imag >= 0 else 1j ) z2_real_sqrt = math.sqrt(abs(current.z2.real)) * ( 1 if current.z2.real >= 0 else 1j ) z2_imag_sqrt = math.sqrt(abs(current.z2.imag)) * ( 1 if current.z2.imag >= 0 else 1j ) current = BicomplexNumber( complex( z1_real_sqrt.real if isinstance(z1_real_sqrt, complex) else z1_real_sqrt, z1_imag_sqrt.real if isinstance(z1_imag_sqrt, complex) else z1_imag_sqrt, ), complex( z2_real_sqrt.real if isinstance(z2_real_sqrt, complex) else z2_real_sqrt, z2_imag_sqrt.real if isinstance(z2_imag_sqrt, complex) else z2_imag_sqrt, ), ) except (ValueError, TypeError): # Karekök hatası durumunda alternatif yaklaşım current = BicomplexNumber( complex(np.sqrt(abs(current.z1.real)), np.sqrt(abs(current.z1.imag))), complex(np.sqrt(abs(current.z2.real)), np.sqrt(abs(current.z2.imag))), ) # 3. Modüler aritmetik current = BicomplexNumber( complex(current.z1.real % mod_real, current.z1.imag % mod_imag), complex(current.z2.real % mod_real, current.z2.imag % mod_imag), ) # 4. Ara adımlar (çapraz çarpımlar) if include_intermediate: # Çapraz çarpım ara değerleri cross_product = BicomplexNumber( complex(current.z1.real * current.z2.imag, 0), complex(0, current.z1.imag * current.z2.real), ) sequence.append(cross_product) sequence.append(current) # 5. Dinamik sistem davranışı için feedback if feedback_interval > 0 and i % feedback_interval == 0 and i > 0: # Periyodik perturbasyon ekle (kaotik davranışı artırmak için) perturbation = BicomplexNumber( complex(0.1 * math.sin(i), 0.1 * math.cos(i)), complex(0.05 * math.sin(i * 0.5), 0.05 * math.cos(i * 0.5)), ) current = current + perturbation return sequence def _has_bicomplex_format(s: str) -> bool: """Checks if string has bicomplex format (comma-separated).""" return "," in s and s.count(",") in [1, 3] # 2 or 4 components
[docs] @dataclass class NeutrosophicBicomplexNumber: def __init__(self, a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0): self.a = float(a) self.b = float(b) self.c = float(c) self.d = float(d) self.e = float(e) self.f = float(f) self.g = float(g) self.h = float(h) @property def coeffs(self) -> list: """Tüm katsayıları liste olarak döndürür.""" return [self.a, self.b, self.c, self.d, self.e, self.f, self.g, self.h] @property def imag(self) -> list: """Sanal kısımları (gerçel kısım hariç) döndürür.""" return self.coeffs[1:] # b'den h'ye kadar def __add__(self, other): if isinstance(other, NeutrosophicBicomplexNumber): return NeutrosophicBicomplexNumber( self.a + other.a, self.b + other.b, self.c + other.c, self.d + other.d, self.e + other.e, self.f + other.f, self.g + other.g, self.h + other.h, ) return NotImplemented def __mul__(self, other): if isinstance(other, (int, float)): return NeutrosophicBicomplexNumber( self.a * other, self.b * other, self.c * other, self.d * other, self.e * other, self.f * other, self.g * other, self.h * other, ) # Diğer türler için çarpım (örneğin iki NeutrosophicBicomplexNumber) gerekirse eklenir return NotImplemented def __rmul__(self, other: (int, float)) -> "NeutrosophicBicomplexNumber": """Sağdan çarpma: scalar * self""" return self.__mul__(other) def __truediv__(self, scalar): if isinstance(scalar, (int, float)): if scalar == 0: raise ZeroDivisionError("Division by zero") return NeutrosophicBicomplexNumber( self.a / scalar, self.b / scalar, self.c / scalar, self.d / scalar, self.e / scalar, self.f / scalar, self.g / scalar, self.h / scalar, ) return NotImplemented def __eq__(self, other): if not isinstance(other, NeutrosophicBicomplexNumber): return False tol = 1e-12 return all( abs(getattr(self, attr) - getattr(other, attr)) < tol for attr in ["a", "b", "c", "d", "e", "f", "g", "h"] ) def __ne__(self, other): return not self.__eq__(other) def __str__(self): return f"({self.a} + {self.b}i) + ({self.c} + {self.d}i)I + ({self.e} + {self.f}i)j + ({self.g} + {self.h}i)Ij" def __repr__(self): return f"NeutrosophicBicomplexNumber({self.a}, {self.b}, {self.c}, {self.d}, {self.e}, {self.f}, {self.g}, {self.h})"
@dataclass class SedenionNumber: """ Sedenion (16-dimensional hypercomplex number) implementation. Sedenions are 16-dimensional numbers that extend octonions via the Cayley-Dickson construction. They are non-commutative, non-associative, and not even alternative. Components: e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15 where e0 is the real part. """ coeffs: List[float] = field(default_factory=lambda: [0.0] * 16) def __post_init__(self): # Eğer coeffs int/float ise listeye çevir if isinstance(self.coeffs, (int, float)): self.coeffs = [float(self.coeffs)] + [0.0] * 15 elif isinstance(self.coeffs, (list, tuple)): # Uzunluğu 16'ya tamamla if len(self.coeffs) < 16: self.coeffs = list(self.coeffs) + [0.0] * (16 - len(self.coeffs)) elif len(self.coeffs) > 16: self.coeffs = list(self.coeffs[:16]) else: self.coeffs = [0.0] * 16 # Tüm elemanları float'a çevir self.coeffs = [float(c) for c in self.coeffs] @classmethod def from_scalar(cls, value: float) -> "SedenionNumber": """Create a sedenion from a scalar (real number).""" coeffs = [0.0] * 16 coeffs[0] = float(value) return cls(coeffs) @classmethod def from_list(cls, values: List[float]) -> "SedenionNumber": """Create a sedenion from a list of up to 16 values.""" if len(values) > 16: raise ValueError(f"List too long ({len(values)}), maximum 16 elements") coeffs = list(values) + [0.0] * (16 - len(values)) return cls(coeffs) @classmethod def basis_element(cls, index: int) -> "SedenionNumber": """Create a basis sedenion (1 at position index, 0 elsewhere).""" if not 0 <= index < 16: raise ValueError(f"Index must be between 0 and 15, got {index}") coeffs = [0.0] * 16 coeffs[index] = 1.0 return cls(coeffs) @property def real(self) -> float: """Get the real part (first component).""" return self.coeffs[0] @real.setter def real(self, value: float): """Set the real part.""" self.coeffs[0] = float(value) @property def imag(self) -> List[float]: """Get the imaginary parts (all except real).""" return self.coeffs[1:] def __getitem__(self, index: int) -> float: """Get component by index.""" if not 0 <= index < 16: raise IndexError(f"Index {index} out of range for sedenion") return self.coeffs[index] def __setitem__(self, index: int, value: float): """Set component by index.""" if not 0 <= index < 16: raise IndexError(f"Index {index} out of range for sedenion") self.coeffs[index] = float(value) def __len__(self) -> int: """Return number of components (always 16).""" return 16 def __iter__(self): """Iterate over components.""" return iter(self.coeffs) def __add__(self, other: Union["SedenionNumber", float, int]) -> "SedenionNumber": """Add two sedenions or sedenion and scalar.""" if isinstance(other, SedenionNumber): new_coeffs = [a + b for a, b in zip(self.coeffs, other.coeffs)] return SedenionNumber(new_coeffs) elif isinstance(other, (int, float)): new_coeffs = self.coeffs.copy() new_coeffs[0] += float(other) return SedenionNumber(new_coeffs) return NotImplemented def __radd__(self, other: Union[float, int]) -> "SedenionNumber": """Right addition: scalar + sedenion.""" return self.__add__(other) def __sub__(self, other: Union["SedenionNumber", float, int]) -> "SedenionNumber": """Subtract two sedenions or sedenion and scalar.""" if isinstance(other, SedenionNumber): new_coeffs = [a - b for a, b in zip(self.coeffs, other.coeffs)] return SedenionNumber(new_coeffs) elif isinstance(other, (int, float)): new_coeffs = self.coeffs.copy() new_coeffs[0] -= float(other) return SedenionNumber(new_coeffs) return NotImplemented def __rsub__(self, other: Union[float, int]) -> "SedenionNumber": """Right subtraction: scalar - sedenion.""" if isinstance(other, (int, float)): new_coeffs = [-c for c in self.coeffs] new_coeffs[0] += float(other) return SedenionNumber(new_coeffs) return NotImplemented def __mul__(self, other: Union["SedenionNumber", float, int]) -> "SedenionNumber": """Multiply sedenion by scalar or another sedenion (simplified).""" if isinstance(other, (int, float)): # Scalar multiplication new_coeffs = [c * float(other) for c in self.coeffs] return SedenionNumber(new_coeffs) elif isinstance(other, SedenionNumber): # NOTE: This is NOT the true sedenion multiplication! # True sedenion multiplication requires a 16x16 multiplication table. # This is a simplified element-wise multiplication for demonstration. # For real applications, implement proper sedenion multiplication. new_coeffs = [a * b for a, b in zip(self.coeffs, other.coeffs)] return SedenionNumber(new_coeffs) return NotImplemented def __rmul__(self, other: Union[float, int]) -> "SedenionNumber": """Right multiplication: scalar * sedenion.""" return self.__mul__(other) def __truediv__(self, scalar: Union[float, int]) -> "SedenionNumber": """Divide sedenion by scalar.""" if isinstance(scalar, (int, float)): if scalar == 0: raise ZeroDivisionError("Cannot divide sedenion by zero") new_coeffs = [c / float(scalar) for c in self.coeffs] return SedenionNumber(new_coeffs) return NotImplemented # if isinstance(other, (int, float, Fraction)): # scalar = float(other) # return self.__class__([c/scalar for c in self.coeffs]) def __floordiv__(self, scalar: Union[float, int]) -> "SedenionNumber": """Floor divide sedenion by scalar.""" if isinstance(scalar, (int, float)): if scalar == 0: raise ZeroDivisionError("Cannot divide sedenion by zero") new_coeffs = [c // float(scalar) for c in self.coeffs] return SedenionNumber(new_coeffs) return NotImplemented def __mod__(self, divisor: Union[float, int]) -> "SedenionNumber": """Modulo operation on sedenion components.""" if isinstance(divisor, (int, float)): if divisor == 0: raise ZeroDivisionError("Cannot take modulo by zero") new_coeffs = [c % float(divisor) for c in self.coeffs] return SedenionNumber(new_coeffs) return NotImplemented def __neg__(self) -> "SedenionNumber": """Negate the sedenion.""" return SedenionNumber([-c for c in self.coeffs]) def __pos__(self) -> "SedenionNumber": """Unary plus.""" return self def __abs__(self) -> float: """Absolute value (magnitude).""" return self.magnitude() def __eq__(self, other: object) -> bool: """Check equality with another sedenion.""" if not isinstance(other, SedenionNumber): return False return all( math.isclose(a, b, abs_tol=1e-12) for a, b in zip(self.coeffs, other.coeffs) ) def __ne__(self, other: object) -> bool: """Check inequality.""" return not self.__eq__(other) def __hash__(self) -> int: """Hash based on rounded components to avoid floating-point issues.""" return hash(tuple(round(c, 10) for c in self.coeffs)) def magnitude(self) -> float: """ Calculate Euclidean norm (magnitude) of the sedenion. Returns: float: sqrt(Σ_i coeff_i²) """ return float(np.linalg.norm(self.coeffs)) def norm(self) -> float: """Alias for magnitude.""" return self.magnitude() def conjugate(self) -> "SedenionNumber": """Return the conjugate (negate all imaginary parts).""" new_coeffs = self.coeffs.copy() for i in range(1, 16): new_coeffs[i] = -new_coeffs[i] return SedenionNumber(new_coeffs) def dot(self, other: "SedenionNumber") -> float: """Dot product with another sedenion.""" if not isinstance(other, SedenionNumber): raise TypeError("Dot product requires another SedenionNumber") return sum(a * b for a, b in zip(self.coeffs, other.coeffs)) def normalize(self) -> "SedenionNumber": """Return a normalized (unit) version.""" mag = self.magnitude() if mag == 0: raise ZeroDivisionError("Cannot normalize zero sedenion") return SedenionNumber([c / mag for c in self.coeffs]) def to_list(self) -> List[float]: """Convert to Python list.""" return self.coeffs.copy() def to_tuple(self) -> Tuple[float, ...]: """Convert to tuple.""" return tuple(self.coeffs) def to_numpy(self) -> np.ndarray: """Convert to numpy array.""" return np.array(self.coeffs, dtype=np.float64) def copy(self) -> "SedenionNumber": """Create a copy.""" return SedenionNumber(self.coeffs.copy()) def __str__(self) -> str: """Human-readable string representation.""" # Show only non-zero components for clarity non_zero = [(i, c) for i, c in enumerate(self.coeffs) if abs(c) > 1e-10] if not non_zero: return "Sedenion(0)" parts = [] for i, c in non_zero: if i == 0: parts.append(f"{c:.6f}") else: sign = "+" if c >= 0 else "-" parts.append(f"{sign} {abs(c):.6f}e{i}") return f"Sedenion({' '.join(parts)})" def __repr__(self) -> str: """Detailed representation.""" return f"SedenionNumber({self.coeffs})" @dataclass class ChingonNumber: """64-bileşenli Chingon sayısı""" # Açıklama düzeltildi def __init__(self, *coeffs): if ( len(coeffs) == 1 and hasattr(coeffs[0], "__iter__") and not isinstance(coeffs[0], str) ): coeffs = coeffs[0] if len(coeffs) != 64: coeffs = list(coeffs) + [0.0] * (64 - len(coeffs)) if len(coeffs) > 64: coeffs = coeffs[:64] self.coeffs = [float(c) for c in coeffs] @property def real(self) -> float: """İlk bileşen – “gerçek” kısım.""" return float(self.coeffs[0]) # def real(self): # Gerçek kısım (ilk bileşen) # return self.coeffs[0] def __iter__(self): return iter(self.coeffs) def __getitem__(self, index): return self.coeffs[index] def __len__(self): return len(self.coeffs) def __str__(self): return f"ChingonNumber({', '.join(map(str, self.coeffs))})" def __repr__(self): return f"({', '.join(map(str, self.coeffs))})" # return f"ChingonNumber({self.coeffs})" def __add__(self, other): if isinstance(other, ChingonNumber): return ChingonNumber([a + b for a, b in zip(self.coeffs, other.coeffs)]) else: # Skaler toplama new_coeffs = self.coeffs.copy() new_coeffs[0] += float(other) return ChingonNumber(new_coeffs) def __sub__(self, other): if isinstance(other, ChingonNumber): return ChingonNumber([a - b for a, b in zip(self.coeffs, other.coeffs)]) else: new_coeffs = self.coeffs.copy() new_coeffs[0] -= float(other) return ChingonNumber(new_coeffs) def __mul__(self, other): if isinstance(other, ChingonNumber): # Basitçe bileşen bazlı çarpma return ChingonNumber( [a * b for a, b in zip(self.coeffs, other.coeffs)] ) # ChingonNumber döndür else: # Skaler çarpma return ChingonNumber( [c * float(other) for c in self.coeffs] ) # ChingonNumber döndür def __mod__(self, divisor): return ChingonNumber([c % divisor for c in self.coeffs]) # ChingonNumber döndür def __eq__(self, other): if not isinstance(other, ChingonNumber): return NotImplemented return np.allclose(self.coeffs, other.coeffs, atol=1e-10) # if isinstance(other, ChingonNumber): # ChingonNumber ile karşılaştır # return all(math.isclose(a, b, abs_tol=1e-10) for a, b in zip(self.coeffs, other.coeffs)) # return False def __truediv__(self, other): """Bölme operatörü: /""" if isinstance(other, (int, float)): # Skaler bölme return ChingonNumber( [c / other for c in self.coeffs] ) # ChingonNumber döndür else: raise TypeError( f"Unsupported operand type(s) for /: 'ChingonNumber' and '{type(other).__name__}'" ) # ChingonNumber if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __floordiv__(self, other): """Tam sayı bölme operatörü: //""" if isinstance(other, (int, float)): # Skaler tam sayı bölme return ChingonNumber( [c // other for c in self.coeffs] ) # ChingonNumber döndür else: raise TypeError( f"Unsupported operand type(s) for //: 'ChingonNumber' and '{type(other).__name__}'" ) # ChingonNumber def __rtruediv__(self, other): """Sağdan bölme: other / ChingonNumber""" if isinstance(other, (int, float)): return ChingonNumber( [other / c if c != 0 else float("inf") for c in self.coeffs] ) # ChingonNumber döndür else: raise TypeError( f"Unsupported operand type(s) for /: '{type(other).__name__}' and 'ChingonNumber'" ) # ChingonNumber def components(self): if hasattr(self.coeffs, "tolist"): return self.coeffs.tolist() return list(self.coeffs) # iterable ise listeye çevir def magnitude(self) -> float: """ Euclidean norm = √( Σ_i coeff_i² ) NumPy’nin `linalg.norm` fonksiyonu C‑hızında hesaplar. """ return float(np.linalg.norm(self.coeffs)) def __hash__(self): # NaN ve -0.0 gibi durumları göz önünde bulundurun return hash(tuple(np.round(self.coeffs, decimals=10))) def phase(self): # compute and return the phase value return self._phase # or whatever logic you need @property def coeffs(self): return [self.w, self.x, self.y, self.z, self.e, self.f, self.g, self.h]
[docs] @dataclass class HyperrealNumber: """Represents a hyperreal number as a sequence of real numbers.""" sequence: List[float] def __init__(self, *args): if len(args) == 1 and isinstance(args[0], list): self.sequence = args[0] else: self.sequence = list(args) def __add__(self, other: Any) -> "HyperrealNumber": if isinstance(other, HyperrealNumber): # Sequence'leri eşit uzunluğa getir max_len = max(len(self.sequence), len(other.sequence)) seq1 = self.sequence + [0.0] * (max_len - len(self.sequence)) seq2 = other.sequence + [0.0] * (max_len - len(other.sequence)) return HyperrealNumber([a + b for a, b in zip(seq1, seq2)]) elif isinstance(other, (int, float)): new_seq = self.sequence.copy() new_seq[0] += other # Sadece finite part'a ekle return HyperrealNumber(new_seq) return NotImplemented def __sub__(self, other: Any) -> "HyperrealNumber": if isinstance(other, HyperrealNumber): max_len = max(len(self.sequence), len(other.sequence)) seq1 = self.sequence + [0.0] * (max_len - len(self.sequence)) seq2 = other.sequence + [0.0] * (max_len - len(other.sequence)) return HyperrealNumber([a - b for a, b in zip(seq1, seq2)]) elif isinstance(other, (int, float)): new_seq = self.sequence.copy() new_seq[0] -= other return HyperrealNumber(new_seq) return NotImplemented def __mul__(self, scalar: float) -> "HyperrealNumber": if isinstance(scalar, (int, float)): return HyperrealNumber([x * scalar for x in self.sequence]) return NotImplemented def __rmul__(self, scalar: float) -> "HyperrealNumber": return self.__mul__(scalar) def __truediv__(self, divisor: float) -> "HyperrealNumber": if isinstance(divisor, (int, float)): if divisor == 0: raise ZeroDivisionError("Scalar division by zero.") return HyperrealNumber([x / divisor for x in self.sequence]) raise TypeError("Only scalar division is supported.") if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __mod__(self, divisor: float) -> "HyperrealNumber": if isinstance(divisor, (int, float)): return HyperrealNumber([x % divisor for x in self.sequence]) raise TypeError("Modulo only supported with a scalar divisor.") def __str__(self) -> str: if len(self.sequence) <= 5: return f"Hyperreal{self.sequence}" return f"Hyperreal({self.sequence[:3]}...)" @property def finite(self): """Returns the finite part (first component)""" return self.sequence[0] if self.sequence else 0.0 @property def infinitesimal(self): """Returns the first infinitesimal part (second component)""" return self.sequence[1] if len(self.sequence) > 1 else 0.0
[docs] @dataclass class BicomplexNumber: """Represents a bicomplex number with two complex components.""" z1: complex # First complex component z2: complex # Second complex component def __add__(self, other: Any) -> "BicomplexNumber": if isinstance(other, BicomplexNumber): return BicomplexNumber(self.z1 + other.z1, self.z2 + other.z2) elif isinstance(other, (int, float, complex)): return BicomplexNumber(self.z1 + other, self.z2) else: raise TypeError( f"Unsupported operand type(s) for +: 'BicomplexNumber' and '{type(other).__name__}'" ) def __sub__(self, other: Any) -> "BicomplexNumber": if isinstance(other, BicomplexNumber): return BicomplexNumber(self.z1 - other.z1, self.z2 - other.z2) elif isinstance(other, (int, float, complex)): return BicomplexNumber(self.z1 - other, self.z2) else: raise TypeError( f"Unsupported operand type(s) for -: 'BicomplexNumber' and '{type(other).__name__}'" ) def __mul__(self, other: Any) -> "BicomplexNumber": if isinstance(other, BicomplexNumber): return BicomplexNumber( self.z1 * other.z1 - self.z2 * other.z2, self.z1 * other.z2 + self.z2 * other.z1, ) elif isinstance(other, (int, float, complex)): return BicomplexNumber(self.z1 * other, self.z2 * other) else: raise TypeError( f"Unsupported operand type(s) for *: 'BicomplexNumber' and '{type(other).__name__}'" ) def __truediv__(self, divisor: float) -> "BicomplexNumber": if isinstance(divisor, (int, float)): if divisor == 0: raise ZeroDivisionError("Division by zero") return BicomplexNumber(self.z1 / divisor, self.z2 / divisor) else: raise TypeError("Only scalar division is supported") if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __str__(self) -> str: parts = [] if self.z1 != 0j: parts.append(f"({self.z1.real}+{self.z1.imag}j)") if self.z2 != 0j: parts.append(f"({self.z2.real}+{self.z2.imag}j)e") return " + ".join(parts) if parts else "0"
@dataclass class CliffordNumber: def __init__(self, basis_dict): if isinstance(basis_dict, (int, float)): # scalar değer self.basis = {"": float(basis_dict)} if abs(basis_dict) > 1e-10 else {} else: self.basis = { k: float(v) for k, v in basis_dict.items() if abs(float(v)) > 1e-10 } @property def dimension(self) -> int: """Vector space dimension'ını otomatik hesaplar.""" max_index = 0 for key in self.basis.keys(): if key: # scalar değilse # '12', '123' gibi string'lerden maksimum rakamı bul if key.isdigit(): max_index = max(max_index, max(int(c) for c in key)) return max_index def __add__(self, other): if isinstance(other, CliffordNumber): new_basis = self.basis.copy() for k, v in other.basis.items(): new_basis[k] = new_basis.get(k, 0.0) + v # Sıfıra yakın değerleri temizle if abs(new_basis[k]) < 1e-10: del new_basis[k] return CliffordNumber(new_basis) elif isinstance(other, (int, float)): new_basis = self.basis.copy() new_basis[""] = new_basis.get("", 0.0) + other return CliffordNumber(new_basis) return NotImplemented def __sub__(self, other): if isinstance(other, CliffordNumber): new_basis = self.basis.copy() for k, v in other.basis.items(): new_basis[k] = new_basis.get(k, 0.0) - v if abs(new_basis[k]) < 1e-10: del new_basis[k] return CliffordNumber(new_basis) elif isinstance(other, (int, float)): new_basis = self.basis.copy() new_basis[""] = new_basis.get("", 0.0) - other return CliffordNumber(new_basis) return NotImplemented def __mul__(self, other): if isinstance(other, (int, float)): return CliffordNumber({k: v * other for k, v in self.basis.items()}) elif isinstance(other, CliffordNumber): # Basit Clifford çarpımı (e_i^2 = +1 varsayımıyla) new_basis = {} for k1, v1 in self.basis.items(): for k2, v2 in other.basis.items(): # Skaler çarpım if k1 == "": product_key = k2 sign = 1.0 elif k2 == "": product_key = k1 sign = 1.0 else: # Vektör çarpımı: e_i * e_j combined = sorted(k1 + k2) product_key = "".join(combined) # Basitleştirilmiş: e_i^2 = +1, anti-commutative sign = 1.0 # Burada gerçek Clifford cebir kuralları uygulanmalı new_basis[product_key] = ( new_basis.get(product_key, 0.0) + sign * v1 * v2 ) return CliffordNumber(new_basis) return NotImplemented def __truediv__(self, other): if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError("Division by zero") return CliffordNumber({k: v / other for k, v in self.basis.items()}) return NotImplemented if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __str__(self): parts = [] if "" in self.basis and abs(self.basis[""]) > 1e-10: parts.append(f"{self.basis['']:.2f}") sorted_keys = sorted( [k for k in self.basis if k != ""], key=lambda x: (len(x), x) ) for k in sorted_keys: v = self.basis[k] if abs(v) > 1e-10: sign = "+" if v > 0 and parts else "" parts.append(f"{sign}{v:.2f}e{k}") result = "".join(parts).replace("+-", "-") return result if result else "0.0" @classmethod def parse(cls, s) -> "CliffordNumber": """Class method olarak parse metodu""" return _parse_clifford(s) def __repr__(self): return self.__str__() def __rmul__(self, other): # other * self işlemini self * other olarak yönlendir return self.__mul__(other) @dataclass class DualNumber: real: float dual: float def __init__(self, real, dual): self.real = float(real) self.dual = float(dual) def __add__(self, other): if isinstance(other, DualNumber): return DualNumber(self.real + other.real, self.dual + other.dual) elif isinstance(other, (int, float)): return DualNumber(self.real + other, self.dual) raise TypeError def __sub__(self, other): if isinstance(other, DualNumber): return DualNumber(self.real - other.real, self.dual - other.dual) elif isinstance(other, (int, float)): return DualNumber(self.real - other, self.dual) raise TypeError def __mul__(self, other): if isinstance(other, DualNumber): return DualNumber( self.real * other.real, self.real * other.dual + self.dual * other.real ) elif isinstance(other, (int, float)): return DualNumber(self.real * other, self.dual * other) raise TypeError def __rmul__(self, other): return self.__mul__(other) def __truediv__(self, other): if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError return DualNumber(self.real / other, self.dual / other) elif isinstance(other, DualNumber): if other.real == 0: raise ZeroDivisionError return DualNumber( self.real / other.real, (self.dual * other.real - self.real * other.dual) / (other.real**2), ) raise TypeError if isinstance(other, (int, float, Fraction)): scalar = float(other) return self.__class__([c / scalar for c in self.coeffs]) def __floordiv__(self, other): if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError return DualNumber(self.real // other, self.dual // other) raise TypeError def __eq__(self, other): if isinstance(other, DualNumber): return self.real == other.real and self.dual == other.dual elif isinstance(other, (int, float)): return self.real == other and self.dual == 0 return False def __str__(self): return f"{self.real} + {self.dual}ε" def __repr__(self): return self.__str__() # __repr__ eklenmiş def __int__(self): return int(self.real) # int() dönüşümü eklenmiş def __radd__(self, other): return self.__add__(other) # commutative def __rsub__(self, other): if isinstance(other, (int, float)): return DualNumber(other - self.real, -self.dual) return NotImplemented def __neg__(self): return DualNumber(-self.real, -self.dual) def __hash__(self): return hash((self.real, self.dual)) @dataclass class SplitcomplexNumber: def __init__(self, real, split, *args): # İlk iki argümanı real ve split olarak al # Diğer argümanları (varsa) yoksay self._real = float(real) self._split = float(split) # Not: *args içinde ekstra bilgi varsa onları da işleyebilirsiniz, # ancak burada yoksayılıyor. def __add__(self, other): if isinstance(other, SplitcomplexNumber): return SplitcomplexNumber(self.real + other.real, self.split + other.split) elif isinstance(other, (int, float)): return SplitcomplexNumber(self.real + other, self.split) return NotImplemented def __sub__(self, other): if isinstance(other, SplitcomplexNumber): return SplitcomplexNumber(self.real - other.real, self.split - other.split) elif isinstance(other, (int, float)): return SplitcomplexNumber(self.real - other, self.split) return NotImplemented def __mul__(self, other): if isinstance(other, SplitcomplexNumber): real = self.real * other.real + self.split * other.split split = self.real * other.split + self.split * other.real return SplitcomplexNumber(real, split) elif isinstance(other, (int, float)): return SplitcomplexNumber(self.real * other, self.split * other) return NotImplemented def __rmul__(self, other): return self.__mul__(other) def __truediv__(self, other): if isinstance(other, (int, float)): if other == 0: raise ZeroDivisionError("Division by zero") return SplitcomplexNumber(self.real / other, self.split / other) elif isinstance(other, SplitcomplexNumber): a, b = self.real, self.split c, d = other.real, other.split norm = c * c - d * d if abs(norm) < 1e-10: raise ZeroDivisionError("Split-complex division by zero (null divisor)") real = (a * c - b * d) / norm split = (b * c - a * d) / norm return SplitcomplexNumber(real, split) return NotImplemented def __str__(self): return f"{self.real:.2f} + {self.split:.2f}j'" def __repr__(self): return f"({self.real}, {self.split}j')" @property def real(self): return self._real @real.setter def real(self, value): self._real = float(value) @property def split(self): return self._split @split.setter def split(self, value): self._split = float(value) @property def imag(self): """Split-complex sayının split kısmı (sanal benzeri).""" return self._split # Yardımcı fonksiyonlar def _extract_numeric_part(s: Any) -> str: """ Return the first numeric token found in s as string (supports scientific notation). Robust for None and non-string inputs. """ if s is None: return "0" if not isinstance(s, str): s = str(s) s = s.strip() # match optional sign, digits, optional decimal, optional exponent m = re.search(r"[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?", s) return m.group(0) if m else "0" def convert_to_float(value: Any) -> float: """ Convert various Keçeci number types to a float (best-effort). Raises TypeError if conversion is not possible. Rules: - int/float -> float - complex -> real part (float) - numpy-quaternion or objects with attribute 'w' -> float(w) - objects with 'real' attribute -> float(real) - objects with 'coeffs' iterable -> float(first coeff) - objects with 'sequence' iterable -> float(first element) """ # Direct numeric types if isinstance(value, (int, float, np.floating, np.integer)): return float(value) if isinstance(value, complex): return float(value.real) # quaternion-like try: # if isinstance(value, quaternion): # return float(value.w) if quaternion is not None and isinstance(value, quaternion): comps = [value.w, value.x, value.y, value.z] if not all(is_near_integer(c) for c in comps): return False return sympy.isprime(int(round(float(comps[0])))) except Exception: pass # Generic attributes if hasattr(value, "real"): try: return float(getattr(value, "real")) except Exception: pass if hasattr(value, "w"): try: return float(getattr(value, "w")) except Exception: pass if hasattr(value, "coeffs"): try: coeffs = getattr(value, "coeffs") if isinstance(coeffs, np.ndarray): if coeffs.size > 0: return float(coeffs.flatten()[0]) else: # list/iterable it = list(coeffs) if it: return float(it[0]) except Exception: pass if hasattr(value, "sequence"): try: seq = getattr(value, "sequence") if seq and len(seq) > 0: return float(seq[0]) except Exception: pass # TernaryNumber: digits -> decimal if hasattr(value, "digits"): try: digits = list(value.digits) dec = 0 for i, d in enumerate(reversed(digits)): dec += int(d) * (3**i) return float(dec) except Exception: pass raise TypeError(f"Cannot convert {type(value).__name__} to float.") def safe_add(added_value, ask_unit, direction): """ Adds ±ask_unit to added_value using native algebraic operations. This function performs: `added_value + (ask_unit * direction)` It assumes that both operands support algebraic addition and scalar multiplication. Parameters ---------- added_value : Any The base value (e.g., DualNumber, OctonionNumber, CliffordNumber). ask_unit : Same type as added_value The unit increment to add or subtract. direction : int Either +1 or -1, determining the sign of the increment. Returns ------- Same type as added_value Result of `added_value + (ask_unit * direction)`. Raises ------ TypeError If `ask_unit` does not support multiplication by an int, or if `added_value` does not support addition with `ask_unit`. """ try: # Scale the unit: ask_unit * (+1 or -1) if not hasattr(ask_unit, "__mul__"): raise TypeError( f"Type '{type(ask_unit).__name__}' does not support scalar multiplication (missing __mul__)." ) scaled_unit = ask_unit * direction # Add to the current value if not hasattr(added_value, "__add__"): raise TypeError( f"Type '{type(added_value).__name__}' does not support addition (missing __add__)." ) result = added_value + scaled_unit return result except Exception as e: # Daha açıklayıcı hata mesajı msg = f"safe_add failed: Cannot compute {repr(added_value)} + ({direction} * {repr(ask_unit)})" raise TypeError(f"{msg}{type(e).__name__}: {e}") from e def _parse_neutrosophic(s: Any) -> Tuple[float, float, float]: """ Parses various neutrosophic representations into (t, i, f) tuple. Supports: - Tuple/list: (t, i, f) or [t, i, f] - Numeric: 5.0 -> (5.0, 0.0, 0.0) - Complex: 3+4j -> (3.0, 4.0, 0.0) # real -> t, imag -> i - String formats: * Comma-separated: "1.5,0.3,0.2" * Symbolic: "1.5 + 0.3I + 0.2F" * Mixed: "1.5I" or "0.2F" """ # Eğer zaten tuple/list ise doğrudan döndür if isinstance(s, (tuple, list)): if len(s) >= 3: try: return float(s[0]), float(s[1]), float(s[2]) except (ValueError, TypeError): pass elif len(s) == 2: try: return float(s[0]), float(s[1]), 0.0 except (ValueError, TypeError): pass elif len(s) == 1: try: return float(s[0]), 0.0, 0.0 except (ValueError, TypeError): pass return 0.0, 0.0, 0.0 # Sayısal tipler için if isinstance(s, (float, int)): return float(s), 0.0, 0.0 elif isinstance(s, complex): # Karmaşık sayı: real -> t, imag -> i return float(s.real), float(s.imag), 0.0 # Eğer NeutrosophicNumber instance ise if hasattr(s, "__class__"): class_name = s.__class__.__name__ if class_name == "NeutrosophicNumber": try: return float(s.t), float(s.i), float(s.f) except (AttributeError, ValueError, TypeError): pass # String işlemleri için önce string'e dönüştür if not isinstance(s, str): try: s = str(s) except Exception: return 0.0, 0.0, 0.0 s_clean = s.strip() if s_clean == "": return 0.0, 0.0, 0.0 # Büyük harfe çevir ve boşlukları kaldır (sembol arama için) s_upper = s_clean.upper().replace(" ", "") # Özel durumlar if s_upper in ["NAN", "NULL", "NONE"]: return 0.0, 0.0, 0.0 # 1. VİRGÜL formatı: t,i,f (3 parametre) - en basit ve güvenilir if "," in s_clean and "(" not in s_clean and ")" not in s_clean: parts = [p.strip() for p in s_clean.split(",")] try: if len(parts) >= 3: return float(parts[0]), float(parts[1]), float(parts[2]) elif len(parts) == 2: return float(parts[0]), float(parts[1]), 0.0 elif len(parts) == 1: return float(parts[0]), 0.0, 0.0 except ValueError: # Bileşenlerden biri boş olabilir try: t_val = float(parts[0]) if parts[0] else 0.0 i_val = float(parts[1]) if len(parts) > 1 and parts[1] else 0.0 f_val = float(parts[2]) if len(parts) > 2 and parts[2] else 0.0 return t_val, i_val, f_val except (ValueError, IndexError): pass # 2. Regular expression ile daha güçlü parsing # Formatlar: "1.5", "1.5I", "1.5F", "1.5 + 0.3I", "1.5 + 0.3I + 0.2F" # İşaretleri ve birimleri doğru şekilde yakalamak için daha kapsamlı regex pattern = r""" ^\s* # Başlangıç ([+-]?(?:\d+\.?\d*|\.\d+))? # t değeri (opsiyonel) ([IF]?) # t birimi (opsiyonel) (?: # İkinci terim (opsiyonel) \s*\+\s* # + işareti ([+-]?(?:\d+\.?\d*|\.\d+))? # i/f değeri ([IF]?) # i/f birimi )? (?: # Üçüncü terim (opsiyonel) \s*\+\s* # + işareti ([+-]?(?:\d+\.?\d*|\.\d+))? # i/f değeri ([IF]?) # i/f birimi )? \s*$ # Son """ match = re.match(pattern, s_clean, re.VERBOSE | re.IGNORECASE) if match: # Grupları al - bunlar string veya None olacak groups = match.groups() t_val_str, t_unit_str, i_val_str, i_unit_str, f_val_str, f_unit_str = groups # Debug için # print(f"Parsed groups: {groups}") # Başlangıç değerleri t, i, f = 0.0, 0.0, 0.0 def parse_value(value_str: Optional[str], default: float = 0.0) -> float: """String değeri float'a çevir""" if not value_str: return default try: return float(value_str) except (ValueError, TypeError): # Özel durumlar: "+", "-", boş string if value_str == "+": return 1.0 elif value_str == "-": return -1.0 return default # İlk terim if t_val_str is not None: val = parse_value(t_val_str) if t_unit_str and t_unit_str.upper() == "I": i = val elif t_unit_str and t_unit_str.upper() == "F": f = val else: t = val # İkinci terim if i_val_str is not None: val = parse_value(i_val_str) if i_unit_str and i_unit_str.upper() == "I": i = val elif i_unit_str and i_unit_str.upper() == "F": f = val else: # Birim yoksa, hangi birime ait olduğunu belirle if t_unit_str and t_unit_str.upper() == "I": i += val elif t_unit_str and t_unit_str.upper() == "F": f += val else: # t birimsizse, i'ye ekle (default I) i = val # Üçüncü terim if f_val_str is not None: val = parse_value(f_val_str) if f_unit_str and f_unit_str.upper() == "I": i = val elif f_unit_str and f_unit_str.upper() == "F": f = val else: # Birim yoksa, hangi birime ait olduğunu belirle if i_unit_str and i_unit_str.upper() == "I": i += val elif i_unit_str and i_unit_str.upper() == "F": f += val elif t_unit_str and t_unit_str.upper() == "I": i += val elif t_unit_str and t_unit_str.upper() == "F": f += val else: # Hiçbir birim yoksa, f'ye ekle (default F) f = val return t, i, f # 3. Basit manuel parsing (regex başarısız olursa) # String'i büyük harfe çevir ve sembolleri ara s_upper = s_clean.upper().replace(" ", "") # Varsayılan değerler t, i, f = 0.0, 0.0, 0.0 # "I" sembolünü ara if "I" in s_upper: parts = s_upper.split("I", 1) before_i = parts[0] after_i = parts[1] if len(parts) > 1 else "" # I'dan önceki kısmı parse et if before_i: # Sayısal kısmı ayır num_match = re.search(r"([+-]?\d*\.?\d+)$", before_i) if num_match: t = float(num_match.group(1)) elif before_i in ["+", "-"]: t = 1.0 if before_i == "+" else -1.0 elif before_i: # Sadece sayı olabilir try: t = float(before_i) except ValueError: pass # I'dan sonraki kısmı parse et (indeterminacy değeri) if after_i: try: i = float(after_i) if after_i not in ["", "+", "-"] else 1.0 if after_i == "-": i = -1.0 except ValueError: i = 1.0 # Sadece "I" varsa else: i = 1.0 # Sadece "I" varsa # "F" sembolünü ara (I'dan bağımsız) if "F" in s_upper: # I içeriyorsa, F'den önceki kısmı al if "I" in s_upper: # "I...F" formatı i_match = re.search(r"I([^F]*)F", s_upper) if i_match: i_str = i_match.group(1) if i_str: try: i = float(i_str) except ValueError: if i_str in ["+", "-"]: i = 1.0 if i_str == "+" else -1.0 else: # Sadece F içeriyor parts = s_upper.split("F", 1) before_f = parts[0] after_f = parts[1] if len(parts) > 1 else "" # F'dan önceki kısmı parse et if before_f: try: t = float(before_f) if before_f not in ["", "+", "-"] else 0.0 if before_f == "+": t = 1.0 elif before_f == "-": t = -1.0 except ValueError: pass # F'dan sonraki kısmı parse et (falsity değeri) if after_f: try: f = float(after_f) if after_f not in ["", "+", "-"] else 1.0 if after_f == "-": f = -1.0 except ValueError: f = 1.0 # Sadece "F" varsa else: f = 1.0 # Sadece "F" varsa # 4. Hiçbir sembol yoksa, sadece sayı olabilir if not ("I" in s_upper or "F" in s_upper): try: t = float(s_clean) except ValueError: # Parantez içinde olabilir if "(" in s_clean and ")" in s_clean: content = s_clean[s_clean.find("(") + 1 : s_clean.find(")")] try: t = float(content) except ValueError: pass return t, i, f def _parse_neutrosophic_complex(s: Any) -> Tuple[float, float, float]: """ Parses neutrosophic complex numbers into (t, i, f) tuple. Supports complex numbers where: - Real part represents truth value (t) - Imaginary part represents indeterminacy value (i) - Falsity value (f) is derived or set to 0 Examples: - 3+4j -> (3.0, 4.0, 0.0) - (2+3j) -> (2.0, 3.0, 0.0) - complex(1.5, 2.5) -> (1.5, 2.5, 0.0) """ import re # Eğer zaten kompleks sayı ise if isinstance(s, complex): return float(s.real), float(s.imag), 0.0 # Eğer tuple/list ise ve kompleks sayı içeriyorsa if isinstance(s, (tuple, list)): if len(s) >= 1: # İlk eleman kompleks sayı olabilir if isinstance(s[0], complex): return float(s[0].real), float(s[0].imag), 0.0 # Ya da 2 elemanlı (real, imag) olabilir elif len(s) >= 2: try: real = float(s[0]) imag = float(s[1]) return real, imag, 0.0 except (ValueError, TypeError): pass # String işlemleri if isinstance(s, str): s_clean = s.strip() # 1. Kompleks sayı formatı: "a+bj" veya "a-bj" # Python'da kompleks sayı formatı complex_pattern = r""" ^\s* # Başlangıç ([+-]?\d*\.?\d+) # Real kısım \s* # Boşluk ([+-])\s* # İşaret \s* # Boşluk (\d*\.?\d+)\s*j\s*$ # Imag kısım + j """ match = re.match(complex_pattern, s_clean, re.VERBOSE | re.IGNORECASE) if match: try: real = float(match.group(1)) sign = match.group(2) imag_str = match.group(3) imag = float(imag_str) if sign == "-": imag = -imag return real, imag, 0.0 except ValueError: pass # 2. Parantez içinde kompleks sayı: "(a+bj)" if "(" in s_clean and ")" in s_clean and "j" in s_clean.lower(): # Parantez içeriğini al content = s_clean[s_clean.find("(") + 1 : s_clean.find(")")].strip() try: # Python'ın kompleks sayı parser'ını kullan c = complex(content) return float(c.real), float(c.imag), 0.0 except ValueError: pass # 3. "complex(a, b)" formatı if s_clean.lower().startswith("complex"): # "complex(1.5, 2.5)" veya "complex(1.5,2.5)" formatı match = re.match( r"complex\s*\(\s*([^,]+)\s*,\s*([^)]+)\s*\)", s_clean, re.IGNORECASE ) if match: try: real = float(match.group(1)) imag = float(match.group(2)) return real, imag, 0.0 except ValueError: pass # 4. Diğer formatlar için _parse_neutrosophic'i dene # (Bu, önceki fonksiyonunuz) try: t, i, f = _parse_neutrosophic(s) # Eğer i değeri varsa ve t ile f 0 ise, bu kompleks sayı olabilir if i != 0.0 and t == 0.0 and f == 0.0: return 0.0, i, 0.0 return t, i, f except NameError: # _parse_neutrosophic fonksiyonu tanımlı değilse pass # 5. Sayısal dönüşüm dene try: # Float'a çevirmeyi dene val = float(s) return val, 0.0, 0.0 except (ValueError, TypeError): pass # 6. Hiçbir şey çalışmazsa varsayılan değer return 0.0, 0.0, 0.0 def _parse_hyperreal(s: Any) -> Tuple[float, float, List[float]]: """ Parses hyperreal representations into (finite, infinitesimal, sequence) tuple. Supports extended hyperreal formats including: BASIC FORMATS: - Tuple/list: [1.0, 0.5] or (1.0, 0.5, 0.1) - Numeric: 5.0 -> (5.0, 0.0, [5.0]) - Complex: 3+4j -> (3.0, 4.0, [3.0, 4.0]) STRING FORMATS: - Comma-separated: "1.5,0.3" -> finite=1.5, infinitesimal=0.3 - Exponential: "1.5ε0.3" or "1.5e0.3" - Sequence: "[1.0, 0.5, 0.1]" - Standard: "1.5 + 0.3ε" or "2.0 - 0.5ε" EXTENDED FORMATS: - Infinities: "∞", "inf", "-infinity" - Infinitesimals: "ε", "dx", "dt", "dh" - Engineering: "1.5kε0.3" (k=1e3 multiplier) - Scientific: "1.23e-4ε2.5e-6" - Mixed: "π + 0.001ε" or "e - 0.0001ε" Returns: Tuple[float, float, List[float]]: - finite part (standard real component) - infinitesimal part (ε coefficient) - full sequence representation """ import math import re import warnings # 1. Eğer zaten Hyperreal instance ise if hasattr(s, "__class__"): class_name = s.__class__.__name__ if class_name in ["Hyperreal", "HyperReal"]: try: if hasattr(s, "finite") and hasattr(s, "infinitesimal"): finite = float(s.finite) infinitesimal = float(s.infinitesimal) seq = getattr(s, "sequence", [finite, infinitesimal]) return finite, infinitesimal, seq elif hasattr(s, "real") and hasattr(s, "epsilon"): finite = float(s.real) infinitesimal = float(s.epsilon) seq = getattr(s, "sequence", [finite, infinitesimal]) return finite, infinitesimal, seq except (AttributeError, ValueError, TypeError): pass # 2. Tuple/list için if isinstance(s, (tuple, list)): try: seq = [] for item in s: # Özel değerleri kontrol et if isinstance(item, str): item_str = item.strip().lower() if item_str in ["inf", "infinity", "∞"]: seq.append(float("inf")) elif item_str in ["-inf", "-infinity", "-∞"]: seq.append(float("-inf")) elif item_str in ["nan", "null"]: seq.append(float("nan")) elif "ε" in item_str or "epsilon" in item_str: # ε içeriyorsa, infinitesimal bileşen olarak işle num = re.sub(r"[εepsilon]", "", item_str, flags=re.IGNORECASE) if num in ["", "+"]: seq.append(1.0) elif num == "-": seq.append(-1.0) else: seq.append(float(num)) else: seq.append(float(item)) else: seq.append(float(item)) finite = seq[0] if seq else 0.0 infinitesimal = seq[1] if len(seq) > 1 else 0.0 return finite, infinitesimal, seq except (ValueError, IndexError, TypeError) as e: warnings.warn( f"Hyperreal tuple/list parse error: {e}", RuntimeWarning, stacklevel=2 ) # 3. Sayısal tipler için if isinstance(s, (float, int)): return float(s), 0.0, [float(s)] elif isinstance(s, complex): # Karmaşık sayı: real -> finite, imag -> infinitesimal return float(s.real), float(s.imag), [float(s.real), float(s.imag)] # 4. String işlemleri için if not isinstance(s, str): try: s = str(s) except Exception as e: warnings.warn( f"Hyperreal conversion to string failed: {e}", RuntimeWarning, stacklevel=2, ) return 0.0, 0.0, [0.0] s_clean = s.strip() # 5. Özel durumlar if s_clean == "": return 0.0, 0.0, [0.0] # Sonsuzluk değerleri infinity_map = { "∞": float("inf"), "inf": float("inf"), "infinity": float("inf"), "+∞": float("inf"), "+inf": float("inf"), "+infinity": float("inf"), "-∞": float("-inf"), "-inf": float("-inf"), "-infinity": float("-inf"), } s_lower = s_clean.lower() if s_lower in infinity_map: value = infinity_map[s_lower] return value, 0.0, [value] # NaN değerleri if s_lower in ["nan", "null", "none", "undefined"]: return float("nan"), 0.0, [float("nan")] # 6. Köşeli parantez içinde sequence (JSON benzeri) if s_clean.startswith("[") and s_clean.endswith("]"): try: content = s_clean[1:-1].strip() if content: parts = [p.strip() for p in re.split(r",|;", content)] seq = [] for p in parts: if p: try: # Özel sembolleri kontrol et if p.lower() in infinity_map: seq.append(infinity_map[p.lower()]) elif p.lower() == "nan": seq.append(float("nan")) else: seq.append(float(p)) except ValueError: # Mühendislik notasyonu olabilir try: # 1.5k, 2.3m gibi val = _parse_engineering_notation(p) seq.append(val) except: seq.append(0.0) finite = seq[0] if seq else 0.0 infinitesimal = seq[1] if len(seq) > 1 else 0.0 return finite, infinitesimal, seq except Exception as e: warnings.warn( f"Hyperreal sequence parse error: {e}", RuntimeWarning, stacklevel=2 ) # 7. Virgülle ayrılmış format: a,b,c if "," in s_clean and not s_clean.startswith("(") and not s_clean.endswith(")"): try: parts = [p.strip() for p in s_clean.split(",")] seq = [] for p in parts: if p: try: seq.append(float(p)) except ValueError: # Özel değerleri kontrol et if p.lower() in infinity_map: seq.append(infinity_map[p.lower()]) elif p.lower() == "nan": seq.append(float("nan")) else: seq.append(0.0) finite = seq[0] if seq else 0.0 infinitesimal = seq[1] if len(seq) > 1 else 0.0 return finite, infinitesimal, seq except Exception as e: warnings.warn( f"Hyperreal comma-separated parse error: {e}", RuntimeWarning, stacklevel=2, ) # 8. GELİŞMİŞ: Matematiksel ifadeler (π, e, φ gibi sabitler) constants = { "π": math.pi, "pi": math.pi, "e": math.e, "φ": (1 + math.sqrt(5)) / 2, "phi": (1 + math.sqrt(5)) / 2, } # Sabit içerip içermediğini kontrol et for const_name, const_value in constants.items(): if const_name.lower() in s_lower: # Sabitin değerini al const_val = const_value # ε ile kombinasyonu kontrol et if "ε" in s_clean or "epsilon" in s_lower: # "π + 0.1ε" formatı match = re.search(r"([+-]?\s*\d*\.?\d+)\s*[εε]", s_clean, re.IGNORECASE) if match: eps_val = ( float(match.group(1).replace(" ", "")) if match.group(1).strip() not in ["", "+", "-"] else 1.0 ) if match.group(1).strip() == "-": eps_val = -1.0 return const_val, eps_val, [const_val, eps_val] else: return const_val, 0.0, [const_val] else: return const_val, 0.0, [const_val] # 9. Exponential/epsilon formatları # "aεb", "a e b", "a + bε", "a - bε" epsilon_patterns = [ r"^\s*([+-]?\d*\.?\d+)\s*[εε]\s*([+-]?\d*\.?\d+)\s*$", # aεb r"^\s*([+-]?\d*\.?\d+)\s*e\s*([+-]?\d*\.?\d+)\s*$", # a e b (hyperreal) r"^\s*([+-]?\d*\.?\d+)\s*\+\s*([+-]?\d*\.?\d+)\s*[εε]\s*$", # a + bε r"^\s*([+-]?\d*\.?\d+)\s*\-\s*([+-]?\d*\.?\d+)\s*[εε]\s*$", # a - bε ] for pattern in epsilon_patterns: match = re.match(pattern, s_clean, re.IGNORECASE) if match: try: finite_val = float(match.group(1)) eps_val = float(match.group(2)) return finite_val, eps_val, [finite_val, eps_val] except ValueError: continue # 10. Mühendislik notasyonu ile hyperreal # "1.5kε0.3m" gibi eng_pattern = r"^\s*([+-]?\d*\.?\d+)([kKmMgGtTμμunpf]?)\s*[εε]\s*([+-]?\d*\.?\d+)([kKmMgGtTμμunpf]?)\s*$" match = re.match(eng_pattern, s_clean, re.IGNORECASE) if match: try: finite_num = float(match.group(1)) finite_unit = match.group(2).lower() eps_num = float(match.group(3)) eps_unit = match.group(4).lower() # Mühendislik çarpanları multipliers = { "k": 1e3, "m": 1e-3, "meg": 1e6, "g": 1e9, "t": 1e12, "μ": 1e-6, "u": 1e-6, "n": 1e-9, "p": 1e-12, "f": 1e-15, } finite = finite_num * multipliers.get(finite_unit, 1.0) infinitesimal = eps_num * multipliers.get(eps_unit, 1.0) return finite, infinitesimal, [finite, infinitesimal] except (ValueError, KeyError): pass # 11. Sadece epsilon (infinitesimal) formatı: "ε", "0.5ε", "-ε" epsilon_only = re.match(r"^\s*([+-]?\d*\.?\d*)\s*[εε]\s*$", s_clean, re.IGNORECASE) if epsilon_only: try: eps_str = epsilon_only.group(1) if eps_str in ["", "+"]: infinitesimal = 1.0 elif eps_str == "-": infinitesimal = -1.0 else: infinitesimal = float(eps_str) return 0.0, infinitesimal, [0.0, infinitesimal] except ValueError: pass # 12. Bilimsel gösterim (hyperreal olmayan) sci_pattern = r"^[+-]?\d*\.?\d+[eE][+-]?\d+$" if re.match(sci_pattern, s_clean): try: value = float(s_clean) return value, 0.0, [value] except ValueError: pass # 13. Sadece sayı try: # Mühendislik notasyonu olabilir value = _parse_engineering_notation(s_clean) return value, 0.0, [value] except (ValueError, TypeError): pass # 14. Varsayılan warnings.warn(f"Could not parse hyperreal: '{s}'", RuntimeWarning, stacklevel=2) return 0.0, 0.0, [0.0] """ # ValueError: not enough values to unpack (expected 3, got 2): Type=9, Start='0.0,0.001', Add='0.0,0.001' def _parse_hyperreal(s) -> Tuple[float, float]: #Parses hyperreal string into (finite, infinitesimal) tuple. # Eğer zaten tuple ise doğrudan döndür if isinstance(s, (tuple, list)) and len(s) >= 2: return float(s[0]), float(s[1]) # Sayısal tipse sadece finite değeri olarak işle if isinstance(s, (float, int, complex)): return float(s), 0.0 # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s_clean = s.strip().replace(" ", "") # VİRGÜL formatı: finite,infinitesimal if ',' in s_clean: parts = s_clean.split(',') if len(parts) >= 2: try: return float(parts[0]), float(parts[1]) except ValueError: pass elif len(parts) == 1: try: return float(parts[0]), 0.0 except ValueError: pass # Eski 'a+be' formatını destekle if 'e' in s_clean: try: parts = s_clean.split('e') finite = float(parts[0]) if parts[0] not in ['', '+', '-'] else 0.0 infinitesimal = float(parts[1]) if len(parts) > 1 and parts[1] not in ['', '+', '-'] else 1.0 return finite, infinitesimal except ValueError: pass # Sadece sayısal değer try: return float(s_clean), 0.0 except ValueError: return 0.0, 0.0 # Default """ def _parse_quaternion_from_csv(s) -> quaternion: """Virgülle ayrılmış string'i veya sayıyı quaternion'a dönüştürür. Args: s: Dönüştürülecek değer. Şu formatları destekler: - quaternion nesnesi (doğrudan döndürülür) - float, int, complex sayılar (skaler quaternion) - String ("w,x,y,z" veya "scalar" formatında) - Diğer tipler (string'e dönüştürülerek işlenir) Returns: quaternion: Dönüştürülmüş kuaterniyon Raises: ValueError: Geçersiz format veya sayısal olmayan bileşenler durumunda """ # Eğer zaten quaternion ise doğrudan döndür if isinstance(s, quaternion): return s # Sayısal tipse skaler quaternion olarak işle if isinstance(s, (float, int)): return quaternion(float(s), 0, 0, 0) # Complex sayı için özel işlem if isinstance(s, complex): # Complex sayının sadece gerçek kısmını al return quaternion(float(s.real), 0, 0, 0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # Boş string kontrolü if not s: raise ValueError("Boş string quaternion'a dönüştürülemez") # String'i virgülle ayır parts_str = s.split(",") # Tüm parçaları float'a dönüştürmeyi dene parts_float = [] for p in parts_str: p = p.strip() if not p: raise ValueError(f"Boş bileşen bulundu: '{s}'") try: # Önce normal float olarak dene parts_float.append(float(p)) except ValueError: # Float olarak parse edilemezse complex olarak dene try: # 'i' karakterini 'j' ile değiştir (complex fonksiyonu 'j' bekler) complex_str = p.replace("i", "j").replace("I", "J") # Eğer 'j' yoksa ve sayı değilse hata ver if "j" not in complex_str.lower(): raise ValueError(f"Geçersiz sayı formatı: '{p}'") c = complex(complex_str) parts_float.append(float(c.real)) except ValueError: raise ValueError( f"quaternion bileşeni sayı olmalı: '{p}' (string: '{s}')" ) if len(parts_float) == 4: return quaternion(*parts_float) elif len(parts_float) == 1: # Sadece skaler değer return quaternion(parts_float[0], 0, 0, 0) else: raise ValueError( f"Geçersiz quaternion formatı. 1 veya 4 bileşen bekleniyor, {len(parts_float)} alındı: '{s}'" ) def _has_comma_format(s: Any) -> bool: """ True if value is a string and contains a comma (CSV-like format). Guard against non-strings. """ if s is None: return False if not isinstance(s, str): s = str(s) # Consider comma-format only when there's at least one digit and a comma return "," in s and bool(re.search(r"\d", s)) def _is_complex_like(s: Any) -> bool: """ Check if s looks like a complex literal (contains 'j'/'i' or +-/ with j). Accepts non-strings by attempting to str() them. """ if s is None: return False if not isinstance(s, str): s = str(s) s = s.lower() # quick checks if "j" in s or "i" in s: return True # pattern like "a+bi" or "a-bi" if re.search(r"[+-]\d", s) and ("+" in s or "-" in s): # avoid classifying comma-separated lists as complex if "," in s: return False return True return False def _parse_neutrosophic_bicomplex(s: Any) -> NeutrosophicBicomplexNumber: """ Parses string or numbers into NeutrosophicBicomplexNumber. Supports: - NeutrosophicBicomplexNumber instance - Numeric types (float, int, complex) - Comma-separated string: "1,2,3,4,5,6,7,8" - List/tuple of 8 values """ # Eğer zaten NeutrosophicBicomplexNumber ise doğrudan döndür if isinstance(s, NeutrosophicBicomplexNumber): return s # List/tuple ise if isinstance(s, (list, tuple)): if len(s) == 8: try: values = [_safe_float_convert(v) for v in s] return NeutrosophicBicomplexNumber(*values) except (ValueError, TypeError) as e: raise ValueError(f"Invalid component values: {s}") from e else: raise ValueError(f"Expected 8 components, got {len(s)}") # Sayısal tipse tüm bileşenler 0, sadece ilk bileşen değerli if isinstance(s, (float, int)): values = [_safe_float_convert(s)] + [0.0] * 7 return NeutrosophicBicomplexNumber(*values) elif isinstance(s, complex): values = [_safe_float_convert(s.real), _safe_float_convert(s.imag)] + [0.0] * 6 return NeutrosophicBicomplexNumber(*values) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): try: s = str(s) except Exception as e: raise ValueError(f"Cannot convert to string: {s}") from e s = s.strip() if not s: return NeutrosophicBicomplexNumber(0, 0, 0, 0, 0, 0, 0, 0) # Virgülle ayrılmış format if "," in s: parts = [p.strip() for p in s.split(",")] if len(parts) == 8: try: values = [_safe_float_convert(p) for p in parts] return NeutrosophicBicomplexNumber(*values) except (ValueError, TypeError) as e: raise ValueError(f"Invalid component values in: '{s}'") from e else: # Virgül var ama 8 değil if len(parts) < 8: # Eksik değerleri 0 ile tamamla values = [_safe_float_convert(p) for p in parts] + [0.0] * ( 8 - len(parts) ) return NeutrosophicBicomplexNumber(*values) else: # Fazla değer varsa ilk 8'ini al values = [_safe_float_convert(p) for p in parts[:8]] return NeutrosophicBicomplexNumber(*values) # Karmaşık sayı formatı deneyelim try: # "1+2i+3j+4k+..." formatı values = _parse_complex_like_string(s) if len(values) >= 8: return NeutrosophicBicomplexNumber(*values[:8]) else: values = values + [0.0] * (8 - len(values)) return NeutrosophicBicomplexNumber(*values) except Exception: pass # Sadece sayı olabilir try: scalar = _safe_float_convert(s) values = [scalar] + [0.0] * 7 return NeutrosophicBicomplexNumber(*values) except ValueError as e: raise ValueError(f"Invalid NeutrosophicBicomplex format: '{s}'") from e def _parse_octonion(s) -> OctonionNumber: """String'i veya sayıyı OctonionNumber'a dönüştürür. w,x,y,z,e,f,g,h:e0,e1,e2,e3,e4,e5,e6,e7 """ # Eğer zaten OctonionNumber ise doğrudan döndür if isinstance(s, OctonionNumber): return s # Eğer sayısal tipse (float, int, complex) skaler olarak işle if isinstance(s, (float, int, complex)): scalar = float(s) return OctonionNumber(scalar, 0, 0, 0, 0, 0, 0, 0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s_clean = s.strip() # Eğer virgül içermiyorsa, skaler olarak kabul et if "," not in s_clean: try: scalar = float(s_clean) return OctonionNumber(scalar, 0, 0, 0, 0, 0, 0, 0) except ValueError: raise ValueError(f"Invalid octonion format: '{s}'") # Virgülle ayrılmışsa try: parts = [float(p.strip()) for p in s_clean.split(",")] if len(parts) == 8: return OctonionNumber(*parts) # 8 parametre olarak gönder else: # Eksik veya fazla bileşen için default scalar = parts[0] if parts else 0.0 return OctonionNumber(scalar, 0, 0, 0, 0, 0, 0, 0) except ValueError as e: raise ValueError(f"Invalid octonion format: '{s}'") from e def _parse_sedenion(s) -> SedenionNumber: """String'i veya sayıyı SedenionNumber'a dönüştürür.""" # Eğer zaten SedenionNumber ise doğrudan döndür if isinstance(s, SedenionNumber): return s # Eğer sayısal tipse (float, int, complex) skaler olarak işle if isinstance(s, (float, int, complex)): scalar_val = float(s) return SedenionNumber([scalar_val] + [0.0] * 15) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() parts = [p.strip() for p in s.split(",")] if len(parts) == 16: try: return SedenionNumber(list(map(float, parts))) except ValueError as e: raise ValueError(f"Geçersiz sedenion bileşen değeri: '{s}' -> {e}") from e elif len(parts) == 1: # Sadece skaler değer girildiğinde try: scalar_val = float(parts[0]) return SedenionNumber([scalar_val] + [0.0] * 15) except ValueError as e: raise ValueError(f"Geçersiz skaler sedenion değeri: '{s}' -> {e}") from e raise ValueError( f"Sedenion için 16 bileşen veya tek skaler bileşen gerekir. Verilen: '{s}' ({len(parts)} bileşen)" ) def _parse_pathion(s) -> PathionNumber: """String'i veya sayıyı PathionNumber'a dönüştürür.""" if isinstance(s, PathionNumber): return s if isinstance(s, (float, int, complex)): return PathionNumber(float(s), *[0.0] * 31) if hasattr(s, "__iter__") and not isinstance(s, str): return PathionNumber(s) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # Köşeli parantezleri kaldır (eğer varsa) s = s.strip("[]") parts = [p.strip() for p in s.split(",")] if len(parts) == 32: # Pathion 32 bileşenli olmalı try: return PathionNumber(*map(float, parts)) # 32 parametre except ValueError as e: raise ValueError(f"Geçersiz pathion bileşen değeri: '{s}' -> {e}") from e elif len(parts) == 1: # Sadece skaler değer girildiğinde try: scalar_val = float(parts[0]) return PathionNumber(scalar_val, *[0.0] * 31) # 32 parametre except ValueError as e: raise ValueError(f"Geçersiz skaler pathion değeri: '{s}' -> {e}") from e raise ValueError( f"Pathion için 32 bileşen veya tek skaler bileşen gerekir. Verilen: '{s}' ({len(parts)} bileşen)" ) def _parse_chingon(s) -> ChingonNumber: """String'i veya sayıyı ChingonNumber'a dönüştürür.""" if isinstance(s, ChingonNumber): return s if isinstance(s, (float, int, complex)): return ChingonNumber(float(s), *[0.0] * 63) if hasattr(s, "__iter__") and not isinstance(s, str): return ChingonNumber(s) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # Köşeli parantezleri kaldır (eğer varsa) s = s.strip("[]") parts = [p.strip() for p in s.split(",")] if len(parts) == 64: # Pathion 32 bileşenli olmalı try: return ChingonNumber(*map(float, parts)) # 64 parametre except ValueError as e: raise ValueError(f"Geçersiz chingon bileşen değeri: '{s}' -> {e}") from e elif len(parts) == 1: # Sadece skaler değer girildiğinde try: scalar_val = float(parts[0]) return ChingonNumber(scalar_val, *[0.0] * 63) # 64 parametre except ValueError as e: raise ValueError(f"Geçersiz skaler Chingon değeri: '{s}' -> {e}") from e raise ValueError( f"Chingon için 64 bileşen veya tek skaler bileşen gerekir. Verilen: '{s}' ({len(parts)} bileşen)" ) def _parse_routon(s: Any) -> RoutonNumber: """ Parse input into a RoutonNumber (128-dimensional hypercomplex number). Supports: - RoutonNumber instance (returned as-is) - Numeric scalars (int, float) -> real part, others zero - Complex numbers -> real and imag in first two components - Lists/tuples of numbers (up to 128) - Strings: comma-separated list or single number Args: s: Input to parse Returns: RoutonNumber instance Raises: ValueError: If parsing fails """ try: # If already RoutonNumber, return as-is if isinstance(s, RoutonNumber): return s # Handle numeric types if isinstance(s, (int, float)): return RoutonNumber.from_scalar(float(s)) # Handle complex numbers if isinstance(s, complex): coeffs = [0.0] * 128 coeffs[0] = s.real coeffs[1] = s.imag return RoutonNumber(coeffs) # Handle iterables (non-string) if hasattr(s, "__iter__") and not isinstance(s, str): # Convert to list and ensure it's exactly 128 elements coeffs = list(s) if len(coeffs) < 128: coeffs = coeffs + [0.0] * (128 - len(coeffs)) elif len(coeffs) > 128: coeffs = coeffs[:128] return RoutonNumber(coeffs) # Convert to string for parsing if not isinstance(s, str): s = str(s) s = s.strip() # Remove brackets if present s = s.strip("[]{}()") # Check if empty if not s: return RoutonNumber.from_scalar(0.0) # Try to parse as comma-separated list if "," in s: parts = [p.strip() for p in s.split(",")] parts = [p for p in parts if p] # Filter empty if not parts: return RoutonNumber.from_scalar(0.0) try: # Parse all parts as floats float_parts = [float(p) for p in parts] # Ensure exactly 128 components if len(float_parts) == 128: return RoutonNumber(float_parts) elif len(float_parts) < 128: padded = float_parts + [0.0] * (128 - len(float_parts)) return RoutonNumber(padded) else: # len(float_parts) > 128 import warnings warnings.warn( f"Routon input has {len(float_parts)} components, truncating to 128", RuntimeWarning, ) return RoutonNumber(float_parts[:128]) except ValueError as e: raise ValueError( f"Invalid numeric value in Routon string: '{s}' -> {e}" ) # Try to parse as single number try: return RoutonNumber.from_scalar(float(s)) except ValueError: pass # Try to parse as complex number string try: c = complex(s) coeffs = [0.0] * 128 coeffs[0] = c.real coeffs[1] = c.imag return RoutonNumber(coeffs) except ValueError: pass # Try to extract any numeric content try: # Use regex to find first number import re match = re.search(r"[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?", s) if match: scalar_val = float(match.group()) return RoutonNumber.from_scalar(scalar_val) except Exception: pass # If all else fails raise ValueError(f"Cannot parse Routon from input: {repr(s)}") except Exception as e: # Log the error if logger is available if "logger" in globals(): logger.warning(f"Routon parsing failed for {repr(s)}: {e}") else: import warnings warnings.warn(f"Routon parsing failed for {repr(s)}: {e}", RuntimeWarning) # Return zero Routon as fallback return RoutonNumber.from_scalar(0.0) def _parse_voudon(s: Any) -> VoudonNumber: """ Parse input into a VoudonNumber (256-dimensional hypercomplex number). Supports: - VoudonNumber instance (returned as-is) - Numeric scalars (int, float) -> real part, others zero - Complex numbers -> real and imag in first two components - Lists/tuples of numbers (up to 256) - Strings: comma-separated list or single number Args: s: Input to parse Returns: VoudonNumber instance Raises: ValueError: If parsing fails """ try: # If already VoudonNumber, return as-is if isinstance(s, VoudonNumber): return s # Handle numeric types if isinstance(s, (int, float)): return VoudonNumber.from_scalar(float(s)) # Handle complex numbers if isinstance(s, complex): coeffs = [0.0] * 256 coeffs[0] = s.real coeffs[1] = s.imag return VoudonNumber(coeffs) # Handle iterables (non-string) if hasattr(s, "__iter__") and not isinstance(s, str): return VoudonNumber.from_iterable(s) # Convert to string for parsing if not isinstance(s, str): s = str(s) s = s.strip() # Remove brackets if present s = s.strip("[]{}()") # Check if empty if not s: return VoudonNumber.from_scalar(0.0) # Try to parse as comma-separated list if "," in s: parts = [p.strip() for p in s.split(",")] # Filter out empty parts parts = [p for p in parts if p] if not parts: return VoudonNumber.from_scalar(0.0) try: # Parse all parts as floats float_parts = [float(p) for p in parts] # If we have exactly 256 components if len(float_parts) == 256: return VoudonNumber(float_parts) # If we have fewer than 256, pad with zeros elif len(float_parts) < 256: padded = float_parts + [0.0] * (256 - len(float_parts)) return VoudonNumber(padded) # If we have more than 256, truncate else: warnings.warn( f"Voudon input has {len(float_parts)} components, " f"truncating to first 256", RuntimeWarning, ) return VoudonNumber(float_parts[:256]) except ValueError as e: raise ValueError( f"Invalid numeric value in Voudon string: '{s}' -> {e}" ) # Try to parse as single number try: scalar_val = float(s) return VoudonNumber.from_scalar(scalar_val) except ValueError: pass # Try to parse as complex number string try: c = complex(s) coeffs = [0.0] * 256 coeffs[0] = c.real coeffs[1] = c.imag return VoudonNumber(coeffs) except ValueError: pass # Try to extract any numeric content try: # Use regex to find first number import re match = re.search(r"[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?", s) if match: scalar_val = float(match.group()) return VoudonNumber.from_scalar(scalar_val) except Exception: pass # If all else fails raise ValueError(f"Cannot parse Voudon from input: {repr(s)}") except Exception as e: # Log the error if logger is available if "logger" in globals(): logger.warning(f"Voudon parsing failed for {repr(s)}: {e}") else: warnings.warn(f"Voudon parsing failed for {repr(s)}: {e}", RuntimeWarning) # Return zero Voudon as fallback return VoudonNumber.from_scalar(0.0) def _parse_clifford(s) -> CliffordNumber: """Algebraik string'i CliffordNumber'a dönüştürür (ör: '1.0+2.0e1').""" if isinstance(s, CliffordNumber): return s if isinstance(s, (float, int, complex)): return CliffordNumber({"": float(s)}) if not isinstance(s, str): s = str(s) s = s.strip().replace(" ", "").replace("^", "") # ^ işaretini kaldır basis_dict = {} # Daha iyi regex pattern: +-1.23e12 formatını yakala pattern = r"([+-]?)(\d*\.?\d+)(?:e(\d+))?|([+-]?)(?:e(\d+))" matches = re.findall(pattern, s) for match in matches: sign_str, coeff_str, basis1, sign_str2, basis2 = match # Hangi grup match oldu? if coeff_str or basis1: sign = -1.0 if sign_str == "-" else 1.0 coeff = float(coeff_str) if coeff_str else 1.0 basis_key = basis1 if basis1 else "" else: sign = -1.0 if sign_str2 == "-" else 1.0 coeff = 1.0 basis_key = basis2 value = sign * coeff basis_dict[basis_key] = basis_dict.get(basis_key, 0.0) + value # Ayrıca +e1, -e2 gibi ifadeleri yakala pattern2 = r"([+-])e(\d+)" matches2 = re.findall(pattern2, s) for sign_str, basis_key in matches2: sign = -1.0 if sign_str == "-" else 1.0 basis_dict[basis_key] = basis_dict.get(basis_key, 0.0) + sign return CliffordNumber(basis_dict) def _parse_dual(s) -> DualNumber: """String'i veya sayıyı DualNumber'a dönüştürür.""" # Eğer zaten DualNumber ise doğrudan döndür if isinstance(s, DualNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return DualNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # DEBUG için # print(f"DEBUG _parse_dual: parsing '{s}'") # 1) Sadece ε sembolünü içeriyor mu kontrol et if "ε" in s or "ε" in s.lower(): # Regex pattern: (real kısım)? (+/-) (dual kısım) ε # Örnekler: "1.2e-07ε", "3.14+1.2e-07ε", "3.14-1.2e-07ε", "+1.2e-07ε", "-1.2e-07ε" # ε sembolünü bul ε_pos = s.lower().find("ε") if ε_pos == -1: ε_pos = s.find("ε") before_ε = s[:ε_pos] after_ε = s[ε_pos + 1 :] # ε'dan sonra başka karakter varsa hata if after_ε.strip(): raise ValueError( f"Geçersiz Dual sayı formatı: '{s}' (ε'dan sonra karakter var)" ) # before_ε'i analiz et expr = before_ε.strip() # Eğer expr boşsa, hem real hem dual 0 if not expr: return DualNumber(0.0, 0.0) # Regex ile ayrıştır # Pattern: (sayı)? ([+-] sayı)? # Grup 1: real kısım (opsiyonel) # Grup 2: işaret + sayı (opsiyonel) # Basit regex pattern pattern = ( r"^([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)([+-]\d*\.?\d+(?:[eE][+-]?\d+)?)?$" ) match = re.match(pattern, expr) if match: real_part = match.group(1) dual_part_with_sign = match.group(2) try: if dual_part_with_sign: # Hem real hem dual var real = float(real_part) if real_part else 0.0 dual = float(dual_part_with_sign) return DualNumber(real, dual) else: # Sadece bir sayı var - bu real mi dual mi? # Eğer expr + veya - ile başlıyorsa, bu dual kısım if expr.startswith("+") or expr.startswith("-"): dual = float(expr) return DualNumber(0.0, dual) else: # Sadece sayı - bu real real = float(expr) return DualNumber(real, 0.0) except ValueError: pass # Regex başarısız oldu, manuel parsing dene # "+" işaretiyle ayrılmış mı? if "+" in expr: parts = expr.split("+") if len(parts) == 2: try: real = float(parts[0].strip()) if parts[0].strip() else 0.0 dual = float(parts[1].strip()) if parts[1].strip() else 0.0 return DualNumber(real, dual) except ValueError: pass elif len(parts) == 1: # Sadece dual kısım try: dual = float(parts[0].strip()) if parts[0].strip() else 0.0 return DualNumber(0.0, dual) except ValueError: pass # "-" işaretiyle ayrılmış mı? (ilk karakter hariç) minus_count = expr.count("-") if minus_count > 1 or (minus_count == 1 and expr[0] != "-"): # "real-dual" formatı if expr[0] == "-": # "-real-dual" veya "-dual" formatı # İkinci - işaretini bul second_minus = expr.find("-", 1) if second_minus != -1: real_part = expr[:second_minus].strip() dual_part = expr[second_minus:].strip() try: real = float(real_part) if real_part else 0.0 dual = float(dual_part) return DualNumber(real, dual) except ValueError: pass else: # "real-dual" formatı minus_pos = expr.find("-") if minus_pos != -1: real_part = expr[:minus_pos].strip() dual_part = expr[minus_pos:].strip() try: real = float(real_part) if real_part else 0.0 dual = float(dual_part) return DualNumber(real, dual) except ValueError: pass # Sadece bir sayı olabilir try: val = float(expr) # + veya - ile başlıyorsa dual, değilse real if expr.startswith("+") or expr.startswith("-"): return DualNumber(0.0, val) else: return DualNumber(val, 0.0) except ValueError: pass # 2) Virgülle ayrılmış format: "real, dual" if "," in s: parts = [p.strip() for p in s.split(",")] try: if len(parts) == 2: real = float(parts[0]) if parts[0] else 0.0 dual = float(parts[1]) if parts[1] else 0.0 return DualNumber(real, dual) elif len(parts) == 1: real = float(parts[0]) if parts[0] else 0.0 return DualNumber(real, 0.0) except ValueError: pass # 3) Sadece sayı try: return DualNumber(float(s), 0.0) except ValueError: pass # DEBUG # print(f"DEBUG _parse_dual: failed to parse '{s}'") raise ValueError( f"Geçersiz Dual sayı formatı: '{s}' (Real, Dual veya sadece Real bekleniyor)" ) def _parse_splitcomplex(s) -> SplitcomplexNumber: """String'i veya sayıyı SplitcomplexNumber'a dönüştürür.""" # Eğer zaten SplitcomplexNumber ise doğrudan döndür if isinstance(s, SplitcomplexNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return SplitcomplexNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # DEBUG için # print(f"DEBUG _parse_splitcomplex: parsing '{s}'") # 1) 'j' ile bitiyor mu kontrol et if s.endswith("j") or s.endswith("J"): # 'j' den önceki kısmı al before_j = s[:-1].strip() # Eğer before_j boşsa, hem real hem split 0 if not before_j: return SplitcomplexNumber(0.0, 0.0) # Regex pattern aynı pattern = ( r"^([+-]?\d*\.?\d+(?:[eE][+-]?\d+)?)([+-]\d*\.?\d+(?:[eE][+-]?\d+)?)?$" ) match = re.match(pattern, before_j) if match: real_part = match.group(1) split_part_with_sign = match.group(2) try: if split_part_with_sign: # Hem real hem split var real = float(real_part) if real_part else 0.0 split = float(split_part_with_sign) return SplitcomplexNumber(real, split) else: # Sadece bir sayı var if before_j.startswith("+") or before_j.startswith("-"): split = float(before_j) return SplitcomplexNumber(0.0, split) else: real = float(before_j) return SplitcomplexNumber(real, 0.0) except ValueError: pass # Regex başarısız oldu, manuel parsing if "+" in before_j: parts = before_j.split("+") if len(parts) == 2: try: real = float(parts[0].strip()) if parts[0].strip() else 0.0 split = float(parts[1].strip()) if parts[1].strip() else 0.0 return SplitcomplexNumber(real, split) except ValueError: pass elif len(parts) == 1: try: split = float(parts[0].strip()) if parts[0].strip() else 0.0 return SplitcomplexNumber(0.0, split) except ValueError: pass # "-" işareti kontrolü minus_count = before_j.count("-") if minus_count > 1 or (minus_count == 1 and before_j[0] != "-"): if before_j[0] == "-": second_minus = before_j.find("-", 1) if second_minus != -1: real_part = before_j[:second_minus].strip() split_part = before_j[second_minus:].strip() try: real = float(real_part) if real_part else 0.0 split = float(split_part) return SplitcomplexNumber(real, split) except ValueError: pass else: minus_pos = before_j.find("-") if minus_pos != -1: real_part = before_j[:minus_pos].strip() split_part = before_j[minus_pos:].strip() try: real = float(real_part) if real_part else 0.0 split = float(split_part) return SplitcomplexNumber(real, split) except ValueError: pass # Sadece bir sayı try: val = float(before_j) if before_j.startswith("+") or before_j.startswith("-"): return SplitcomplexNumber(0.0, val) else: return SplitcomplexNumber(val, 0.0) except ValueError: pass # 2) Virgülle ayrılmış format: "real, split" if "," in s: parts = [p.strip() for p in s.split(",")] try: if len(parts) == 2: real = float(parts[0]) if parts[0] else 0.0 split = float(parts[1]) if parts[1] else 0.0 return SplitcomplexNumber(real, split) elif len(parts) == 1: real = float(parts[0]) if parts[0] else 0.0 return SplitcomplexNumber(real, 0.0) except ValueError: pass # 3) Sadece sayı try: return SplitcomplexNumber(float(s), 0.0) except ValueError: pass # DEBUG # print(f"DEBUG _parse_splitcomplex: failed to parse '{s}'") raise ValueError( f"Geçersiz Split-Complex sayı formatı: '{s}' (Real, Split veya sadece Real bekleniyor)" ) """ def _parse_dual(s) -> DualNumber: #String'i veya sayıyı DualNumber'a dönüştürür. # Eğer zaten DualNumber ise doğrudan döndür if isinstance(s, DualNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return DualNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # 1) Sadece ε içeren format: "1.2e-07ε" veya "-1.2e-07ε" s_lower = s.lower() # ε sembolünü kontrol et if 'ε' in s_lower: # ε sembolünün pozisyonunu bul ε_pos = s_lower.find('ε') # ε'dan önceki kısmı al before_ε = s[:ε_pos].strip() after_ε = s[ε_pos+1:].strip() # ε'dan sonraki kısım (boş olmalı) # Eğer ε'dan sonra bir şey varsa geçersiz if after_ε: raise ValueError(f"Geçersiz Dual sayı formatı: '{s}'") # ε'dan önceki kısmı analiz et if before_ε: # + veya - işaretleriyle ayrılmış mı kontrol et if '+' in before_ε: parts = before_ε.split('+') if len(parts) == 2: try: real = float(parts[0].strip()) if parts[0].strip() else 0.0 dual = float(parts[1].strip()) if parts[1].strip() else 0.0 return DualNumber(real, dual) except ValueError: pass elif len(parts) == 1: # Sadece dual kısım: "+1.2e-07" gibi try: dual = float(parts[0].strip()) if parts[0].strip() else 0.0 return DualNumber(0.0, dual) except ValueError: pass elif '-' in before_ε[1:]: # İlk karakter hariç - işareti # İlk karakteri kontrol et if before_ε[0] == '-': # "-1.2e-07" formatı - sadece dual kısım negatif try: dual = float(before_ε.strip()) return DualNumber(0.0, dual) except ValueError: pass else: # "real-dual" formatı minus_pos = before_ε.find('-', 1) if minus_pos != -1: real_part = before_ε[:minus_pos].strip() dual_part = before_ε[minus_pos:].strip() # - işaretiyle birlikte try: real = float(real_part) if real_part else 0.0 dual = float(dual_part) return DualNumber(real, dual) except ValueError: pass else: # Sadece dual kısım: "1.2e-07" gibi try: dual = float(before_ε.strip()) return DualNumber(0.0, dual) except ValueError: pass # 2) Virgülle ayrılmış format: "real, dual" if ',' in s: parts = [p.strip() for p in s.split(',')] if len(parts) >= 2: try: real = float(parts[0]) if parts[0] else 0.0 dual = float(parts[1]) if parts[1] else 0.0 return DualNumber(real, dual) except ValueError: pass elif len(parts) == 1: # Sadece real kısım verilmiş try: real = float(parts[0]) if parts[0] else 0.0 return DualNumber(real, 0.0) except ValueError: pass # 3) Sadece sayı try: return DualNumber(float(s), 0.0) except ValueError: pass raise ValueError(f"Geçersiz Dual sayı formatı: '{s}' (Real, Dual veya sadece Real bekleniyor)") def _parse_splitcomplex(s) -> SplitcomplexNumber: #String'i veya sayıyı SplitcomplexNumber'a dönüştürür. # Eğer zaten SplitcomplexNumber ise doğrudan döndür if isinstance(s, SplitcomplexNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return SplitcomplexNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # 1) j ile biten format: "0.00027182818284590454j" veya "a+bj" s_lower = s.lower() if s_lower.endswith('j'): # 'j' den önceki kısmı al before_j = s[:-1].strip() if before_j: # + veya - işaretleriyle ayrılmış mı kontrol et if '+' in before_j: parts = before_j.split('+') if len(parts) == 2: try: real = float(parts[0].strip()) if parts[0].strip() else 0.0 split = float(parts[1].strip()) if parts[1].strip() else 0.0 return SplitcomplexNumber(real, split) except ValueError: pass elif len(parts) == 1: # Sadece split kısım: "+0.00027182818284590454" gibi try: split = float(parts[0].strip()) if parts[0].strip() else 0.0 return SplitcomplexNumber(0.0, split) except ValueError: pass elif '-' in before_j[1:]: # İlk karakter hariç - işareti if before_j[0] == '-': # Sadece split kısım negatif: "-0.00027182818284590454" try: split = float(before_j.strip()) return SplitcomplexNumber(0.0, split) except ValueError: pass else: # "real-split" formatı minus_pos = before_j.find('-', 1) if minus_pos != -1: real_part = before_j[:minus_pos].strip() split_part = before_j[minus_pos:].strip() # - işaretiyle birlikte try: real = float(real_part) if real_part else 0.0 split = float(split_part) return SplitcomplexNumber(real, split) except ValueError: pass else: # Sadece split kısım: "0.00027182818284590454" try: split = float(before_j.strip()) return SplitcomplexNumber(0.0, split) except ValueError: pass # 2) Virgülle ayrılmış format: "real, split" if ',' in s: parts = [p.strip() for p in s.split(',')] if len(parts) >= 2: try: real = float(parts[0]) if parts[0] else 0.0 split = float(parts[1]) if parts[1] else 0.0 return SplitcomplexNumber(real, split) except ValueError: pass elif len(parts) == 1: # Sadece real kısım verilmiş try: real = float(parts[0]) if parts[0] else 0.0 return SplitcomplexNumber(real, 0.0) except ValueError: pass # 3) Sadece sayı try: return SplitcomplexNumber(float(s), 0.0) except ValueError: pass raise ValueError(f"Geçersiz Split-Complex sayı formatı: '{s}' (Real, Split veya sadece Real bekleniyor)") """ """ def _parse_dual(s) -> DualNumber: #String'i veya sayıyı DualNumber'a dönüştürür. # Eğer zaten DualNumber ise doğrudan döndür if isinstance(s, DualNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return DualNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # 1) Virgülle ayrılmış format: "real, dual" if ',' in s: parts = [p.strip() for p in s.split(',')] if len(parts) >= 2: try: return DualNumber(float(parts[0]), float(parts[1])) except ValueError: pass elif len(parts) == 1: # Sadece real kısım verilmiş try: return DualNumber(float(parts[0]), 0.0) except ValueError: pass # 2) Matematiksel ifade formatı: "a+bε" veya "a-bε" s_lower = s.lower() ε_pos = s_lower.find('ε') if ε_pos != -1: # ε sembolünden önceki kısmı al expr = s[:ε_pos].strip() # + veya - işaretlerini bul if '+' in expr: parts = expr.split('+') if len(parts) == 2: try: real = float(parts[0].strip()) dual = float(parts[1].strip()) return DualNumber(real, dual) except ValueError: pass elif '-' in expr[1:]: # İlk karakterden sonraki - işareti # İlk - işaretini bul (ilk karakter hariç) minus_pos = expr.find('-', 1) if minus_pos != -1: real_part = expr[:minus_pos].strip() dual_part = expr[minus_pos:].strip() # - işaretiyle birlikte try: real = float(real_part) dual = float(dual_part) return DualNumber(real, dual) except ValueError: pass # 3) Sadece real sayı try: return DualNumber(float(s), 0.0) except ValueError: pass raise ValueError(f"Geçersiz Dual sayı formatı: '{s}' (Real, Dual veya sadece Real bekleniyor)") def _parse_splitcomplex(s) -> SplitcomplexNumber: #String'i veya sayıyı SplitcomplexNumber'a dönüştürür. # Eğer zaten SplitcomplexNumber ise doğrudan döndür if isinstance(s, SplitcomplexNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return SplitcomplexNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() # 1) Virgülle ayrılmış format: "real, split" if ',' in s: parts = [p.strip() for p in s.split(',')] if len(parts) >= 2: try: return SplitcomplexNumber(float(parts[0]), float(parts[1])) except ValueError: pass elif len(parts) == 1: # Sadece real kısım verilmiş try: return SplitcomplexNumber(float(parts[0]), 0.0) except ValueError: pass # 2) Matematiksel ifade formatı: "a+bj" veya "a-bj" s_lower = s.lower() # 'j' ile bitiyor mu kontrol et if s_lower.endswith('j'): # 'j' den önceki kısmı al expr = s[:-1].strip() # + veya - işaretlerini bul if '+' in expr: parts = expr.split('+') if len(parts) == 2: try: real = float(parts[0].strip()) split = float(parts[1].strip()) return SplitcomplexNumber(real, split) except ValueError: pass elif '-' in expr[1:]: # İlk karakterden sonraki - işareti minus_pos = expr.find('-', 1) if minus_pos != -1: real_part = expr[:minus_pos].strip() split_part = expr[minus_pos:].strip() # - işaretiyle birlikte try: real = float(real_part) split = float(split_part) return SplitcomplexNumber(real, split) except ValueError: pass # 3) Sadece real sayı try: return SplitcomplexNumber(float(s), 0.0) except ValueError: pass raise ValueError(f"Geçersiz Split-Complex sayı formatı: '{s}' (Real, Split veya sadece Real bekleniyor)") """ """ def _parse_dual(s) -> DualNumber: #String'i veya sayıyı DualNumber'a dönüştürür. # Eğer zaten DualNumber ise doğrudan döndür if isinstance(s, DualNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return DualNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() parts = [p.strip() for p in s.split(',')] # Sadece ilk iki bileşeni al if len(parts) >= 2: try: return DualNumber(float(parts[0]), float(parts[1])) except ValueError: pass elif len(parts) == 1: # Sadece real kısım verilmiş try: return DualNumber(float(parts[0]), 0.0) except ValueError: pass raise ValueError(f"Geçersiz Dual sayı formatı: '{s}' (Real, Dual veya sadece Real bekleniyor)") def _parse_splitcomplex(s) -> SplitcomplexNumber: #String'i veya sayıyı SplitcomplexNumber'a dönüştürür. # Eğer zaten SplitcomplexNumber ise doğrudan döndür if isinstance(s, SplitcomplexNumber): return s # Eğer sayısal tipse (float, int, complex) real kısım olarak işle if isinstance(s, (float, int, complex)): return SplitcomplexNumber(float(s), 0.0) # String işlemleri için önce string'e dönüştür if not isinstance(s, str): s = str(s) s = s.strip() parts = [p.strip() for p in s.split(',')] if len(parts) == 2: try: return SplitcomplexNumber(float(parts[0]), float(parts[1])) except ValueError: pass elif len(parts) == 1: # Sadece real kısım verilmiş try: return SplitcomplexNumber(float(parts[0]), 0.0) except ValueError: pass raise ValueError(f"Geçersiz Split-Complex sayı formatı: '{s}' (Real, Split veya sadece Real bekleniyor)") """ def generate_octonion(w, x, y, z, e, f, g, h): """8 bileşenden bir oktonyon oluşturur.""" return OctonionNumber(w, x, y, z, e, f, g, h) def _parse_quaternion(s: Any) -> Any: """Parses user string ('a+bi+cj+dk' or scalar) into a quaternion - DÜZELTİLMİŞ.""" # ✅ SORUN 1: Parametre tipi düzeltildi (Any yerine str değil) if isinstance(s, (int, float, Fraction)): try: from kececinumbers import QuaternionNumber return QuaternionNumber(float(s), 0, 0, 0) # ✅ SKALER DESTEK except: return [float(s), 0, 0, 0] # List fallback # String değilse dönüştür if not isinstance(s, str): s = str(float(s)) s_clean = s.replace(" ", "").lower() if not s_clean: raise ValueError("Input cannot be empty.") # ✅ SORUN 2: float kontrolü EN BAŞTA try: val = float(s_clean) try: from kececinumbers import quaternion return quaternion(val, 0, 0, 0) # ✅ Sıfır imaginary except: return [val, 0, 0, 0] except ValueError: pass # ✅ SORUN 3: re import kontrolü try: import re except ImportError: # Regex yoksa basit parse return [ float(s_clean.split("+")[0]) if "+" in s_clean else float(s_clean), 0, 0, 0, ] # Regex parsing s_temp = re.sub(r"([+-])([ijk])", r"\g<1>1\g<2>", s_clean) if s_temp.startswith(("i", "j", "k")): s_temp = "1" + s_temp # ✅ SORUN 4: Pattern düzeltildi (raw string) pattern = re.compile(r"([+-]?\d*\.?\d*)([ijk])?") matches = pattern.findall(s_temp) parts = {"w": 0.0, "x": 0.0, "y": 0.0, "z": 0.0} for value_str, component in matches: if not value_str or value_str == "+": continue value = float(value_str) if component == "i": parts["x"] += value elif component == "j": parts["y"] += value elif component == "k": parts["z"] += value else: parts["w"] += value # ✅ SORUN 5: quaternion constructor güvenli try: from kececinumbers import quaternion return quaternion(parts["w"], parts["x"], parts["y"], parts["z"]) except: return [parts["w"], parts["x"], parts["y"], parts["z"]] # List fallback def _parse_superreal(s) -> SuperrealNumber: """String'i veya sayıyı SuperrealNumber'a dönüştürür.""" if isinstance(s, SuperrealNumber): return s if isinstance(s, (float, int)): return SuperrealNumber(float(s), 0.0) if isinstance(s, complex): return SuperrealNumber(s.real, s.imag) if hasattr(s, "__iter__") and not isinstance(s, str): if len(s) == 2: return SuperrealNumber(float(s[0]), float(s[1])) else: raise ValueError("SuperrealNumber için 2 bileşen gereklidir.") # String işlemleri if not isinstance(s, str): s = str(s) s = s.strip().strip("()[]") parts = [p.strip() for p in s.split(",")] if len(parts) == 2: try: real = float(parts[0]) split = float(parts[1]) return SuperrealNumber(real, split) except ValueError as e: raise ValueError( f"Geçersiz SuperrealNumber bileşen değeri: '{s}' -> {e}" ) from e elif len(parts) == 1: try: real = float(parts[0]) return SuperrealNumber(real, 0.0) except ValueError as e: raise ValueError( f"Geçersiz SuperrealNumber skaler değeri: '{s}' -> {e}" ) from e else: raise ValueError("SuperrealNumber için 1 veya 2 bileşen gereklidir.") def _parse_ternary(s: Any) -> Any: """TERNARY parser - %100 çalışan versiyon""" try: if isinstance(s, (TernaryNumber, list)): return s if isinstance(s, (int, float, Fraction)): return TernaryNumber(float(s), 0.0, 0.0) # ✅ SKALER DESTEK if isinstance(s, str): s = s.strip().strip("()[]") if all(c in "012" for c in s): return TernaryNumber.from_ternary_string(s) else: return TernaryNumber(float(s), 0.0, 0.0) # ✅ Float string return TernaryNumber(float(s), 0.0, 0.0) except: return [float(s), 0.0, 0.0] # List fallback
[docs] def get_random_type( num_iterations: int = 10, fixed_start_raw: Union[str, float, int] = "0", fixed_add_base_scalar: Union[str, float, int] = 9.0, exclude_types: Optional[List[int]] = None, seed: Optional[int] = None, ) -> List[Any]: """ Generates Keçeci Numbers for a randomly selected type. Args: num_iterations: Number of iterations to generate fixed_start_raw: Starting value (can be string, float, or int) fixed_add_base_scalar: Value to add each iteration (can be string, float, or int) exclude_types: List of type numbers to exclude from random selection seed: Random seed for reproducible results Returns: List of generated Keçeci numbers """ # Set random seed if provided if seed is not None: random.seed(seed) # Type definitions type_names_list = [ "Positive Real", "Negative Real", "Complex", "Float", "Rational", "Quaternion", "Neutrosophic", "Neutrosophic Complex", "Hyperreal", "Bicomplex", "Neutrosophic Bicomplex", "Octonion", "Sedenion", "Clifford", "Dual", "Split-Complex", "Pathion", "Chingon", "Routon", "Voudon", "Super Real", "Ternary", "Hypercomplex", ] # Define available types (1-based indexing) available_types = list(range(1, len(type_names_list) + 1)) # Exclude specified types if exclude_types: available_types = [t for t in available_types if t not in exclude_types] if not available_types: raise ValueError("No available types after exclusions") # Randomly select a type random_type_choice = random.choice(available_types) # Log the selection logger.info( "Randomly selected Keçeci Number Type: %d (%s)", random_type_choice, type_names_list[random_type_choice - 1], ) # Ensure parameters are strings for get_with_params start_value_str = ( str(fixed_start_raw) if not isinstance(fixed_start_raw, str) else fixed_start_raw ) add_value_str = ( str(fixed_add_base_scalar) if not isinstance(fixed_add_base_scalar, str) else fixed_add_base_scalar ) # Call the generator function return get_with_params( kececi_type_choice=random_type_choice, iterations=num_iterations, start_value_raw=start_value_str, add_value_raw=add_value_str, )
""" # güncel kodlarda kullanılıyor def find_kececi_prime_number(kececi_numbers_list: List[Any]) -> Optional[int]: #Finds the Keçeci Prime Number from a generated sequence. if not kececi_numbers_list: return None integer_prime_reps = [ rep for num in kececi_numbers_list if is_prime(num) and (rep := _get_integer_representation(num)) is not None ] if not integer_prime_reps: return None counts = collections.Counter(integer_prime_reps) repeating_primes = [(freq, prime) for prime, freq in counts.items() if freq > 1] if not repeating_primes: return None _, best_prime = max(repeating_primes) return best_prime """ # def find_kececi_prime_number_cycle_first(kececi_numbers_list: List[Any]) -> Optional[int]:
[docs] def find_kececi_prime_number( kececi_numbers_list: List[Any], include_intermediate_steps: bool = True, min_repeats: int = 3, ) -> Optional[int]: """ ASK algoritması ile üretilmiş dizide (ara adımlar dahil) döngüdeki ilk asal sayıyı (KPN) bulur. Parametreler: kececi_numbers_list: _generate_ask_sequence_complete ile üretilmiş dizi. include_intermediate_steps: Dizi sözlük listesi içeriyorsa True (varsayılan), düz liste ise False. min_repeats: find_period için minimum tekrar sayısı. Dönüş: KPN (int) veya None (döngü veya asal yoksa). """ # 1. İç içe sözlük listesini düz sayı listesine dönüştür (ara adımlar dahil) if ( include_intermediate_steps and kececi_numbers_list and isinstance(kececi_numbers_list[0], dict) ): # Tüm "value" alanlarını topla (her adımda birden çok ara değer olabilir) flat_values = [] for item in kececi_numbers_list: if isinstance(item, dict) and "value" in item: flat_values.append(item["value"]) else: flat_values.append(item) sequence = flat_values else: sequence = kececi_numbers_list if not sequence: return None # 2. Döngüyü (periyodu) bul cycle = find_period(sequence, min_repeats=min_repeats) if not cycle: return None # 3. Döngü içindeki ilk asalı ara for val in cycle: rep = _get_integer_representation(val) if rep is not None and rep > 1 and isprime(rep): return rep return None
def is_divisible( x: Any, d: Any, tol: float = 1e-12, allow_rational: bool = False, max_den: int = 20 ) -> bool: """ x sayısının d ile (yaklaşık olarak) bölünüp bölünemediğini kontrol eder. - Önce Fraction ile kesin kontrol yapar. - Başarısız olursa float bölüm üzerinden toleranslı tam sayı kontrolü. - allow_rational=True ise, bölümün paydası max_den'i aşmayan bir rasyonel sayı olmasına izin verir. """ try: if d == 0: return False # Fraction ile kesin kontrol def to_frac(v): if isinstance(v, Fraction): return v if isinstance(v, int): return Fraction(v) try: return Fraction(Decimal(str(v))) except Exception: return Fraction(float(v)) q = to_frac(x) / to_frac(d) if q.denominator == 1: return True if allow_rational: if q.denominator <= max_den: return True # Float tabanlı toleranslı kontrol qf = float(x) / float(d) if not math.isfinite(qf): return False return math.isclose(qf, round(qf), abs_tol=tol) except Exception: return False def _is_divisible( value: Any, divisor: Union[int, float, Fraction], kececi_type: int ) -> bool: """ Robust divisibility check supporting integer and fractional divisors. Returns True if value is divisible by divisor according to type semantics. """ TOL = 1e-12 # --- helper: numeric divisibility via quotient near-integer --- def _divisible_by_numeric(x, d, tol=TOL): try: if d == 0: return False # Exact Fraction handling if isinstance(x, Fraction) or isinstance(d, Fraction): try: q = Fraction(x) / Fraction(d) return q.denominator == 1 except Exception: # fall through to float check pass # float quotient near-integer check (works for floats and ints) q = float(x) / float(d) if not math.isfinite(q): return False return math.isclose(q, round(q), abs_tol=tol) except Exception: return False def _complex_divisible(c, d): try: return _divisible_by_numeric(c.real, d) and _divisible_by_numeric(c.imag, d) except Exception: return False def _iterable_divisible(it, d): try: for c in it: if isinstance(c, complex): if not _complex_divisible(c, d): return False elif isinstance(c, Fraction): if not _divisible_by_numeric(c, d): return False else: if not _divisible_by_numeric(c, d): return False return True except Exception: return False # coerce divisor to numeric if possible try: if not isinstance(divisor, (int, float, Fraction)): divisor = float(divisor) except Exception: return False try: # --- Type-specific branches --- if kececi_type in (TYPE_POSITIVE_REAL, TYPE_NEGATIVE_REAL): return _divisible_by_numeric(value, divisor) if kececi_type == TYPE_RATIONAL: try: fr = value if isinstance(value, Fraction) else Fraction(value) return _divisible_by_numeric(fr, divisor) except Exception: return False if kececi_type == TYPE_COMPLEX: try: c = value if isinstance(value, complex) else _parse_complex(value) return _complex_divisible(c, divisor) except Exception: return False if kececi_type == TYPE_HYPERREAL: if hasattr(value, "sequence") and isinstance(value.sequence, (list, tuple)): return _iterable_divisible(value.sequence, divisor) return False if kececi_type in ( TYPE_OCTONION, TYPE_SEDENION, TYPE_PATHION, TYPE_CHINGON, TYPE_ROUTON, TYPE_VOUDON, TYPE_HYPERCOMPLEX, ): # try norm first if available try: if hasattr(value, "norm") and callable(getattr(value, "norm")): n = float(value.norm()) if _divisible_by_numeric(n, divisor): return True except Exception: pass # fallback to component-wise if hasattr(value, "coeffs"): try: comps = getattr(value, "coeffs") comps = comps() if callable(comps) else comps return _iterable_divisible(comps, divisor) except Exception: pass if hasattr(value, "__iter__") and not isinstance(value, (str, bytes)): return _iterable_divisible(value, divisor) return _divisible_by_numeric(value, divisor) # ============================================================================ # BÖLÜNEBİLİRLİK KONTROLÜ - Nötrosofik Sayılar için # ============================================================================ # Bu fonksiyon, bir Nötrosofik sayının belirli bir bölene tam bölünüp # bölünmediğini kontrol eder. # # Nötrosofik sayı: t + iI (veya a + bI) # Her iki bileşen de tam bölünmelidir. # ============================================================================ if kececi_type == TYPE_NEUTROSOPHIC: # Sadece Nötrosofik tipi için çalış try: # Hata durumlarını yakala # ----- 1. DURUM: t ve i özellikleri var ----- # Bazı NeutrosophicNumber sınıfları t (truth) ve i (indeterminacy) kullanır if hasattr(value, "t") and hasattr(value, "i"): # Örnek: value.t = 6, value.i = 4, divisor = 2 # _divisible_by_numeric(6, 2) → True (6/2=3) # _divisible_by_numeric(4, 2) → True (4/2=2) # return True and True → True (tam bölünüyor) return _divisible_by_numeric( value.t, divisor ) and _divisible_by_numeric(value.i, divisor) # ----- 2. DURUM: a ve b özellikleri var ----- # Alternatif sınıflar a (deterministic) ve b (uncertainty) kullanır if hasattr(value, "a") and hasattr(value, "b"): # Örnek: value.a = 6, value.b = 4, divisor = 3 # _divisible_by_numeric(6, 3) → True (6/3=2) # _divisible_by_numeric(4, 3) → False (4/3 tam değil) # return True and False → False (tam bölünmüyor) return _divisible_by_numeric( value.a, divisor ) and _divisible_by_numeric(value.b, divisor) except Exception: # Herhangi bir hata olursa return False # Güvenli cevap: bölünemez return False # Hiçbir özellik bulunamadı """ if kececi_type == TYPE_NEUTROSOPHIC: try: if hasattr(value, 't') and hasattr(value, 'i'): return _divisible_by_numeric(value.t, divisor) and _divisible_by_numeric(value.i, divisor) if hasattr(value, 'a') and hasattr(value, 'b'): return _divisible_by_numeric(value.a, divisor) and _divisible_by_numeric(value.b, divisor) except Exception: return False return False """ if kececi_type == TYPE_NEUTROSOPHIC_COMPLEX: try: comps = [] if hasattr(value, "real") and hasattr(value, "imag"): comps.extend([value.real, value.imag]) if hasattr(value, "indeterminacy"): comps.append(value.indeterminacy) return ( all(_divisible_by_numeric(c, divisor) for c in comps) if comps else False ) except Exception: return False # Generic fallback: coeffs -> iterable -> numeric if hasattr(value, "coeffs"): comps = getattr(value, "coeffs") comps = comps() if callable(comps) else comps return _iterable_divisible(comps, divisor) if hasattr(value, "__iter__") and not isinstance(value, (str, bytes)): return _iterable_divisible(value, divisor) return _divisible_by_numeric(value, divisor) except Exception: return False def _get_integer_representation(n_input: Any) -> Optional[int]: """ Extracts the primary integer component from supported Keçeci number types. Returns: absolute integer value (int) when a meaningful integer representation exists, otherwise None. """ try: # None early exit if n_input is None: return None # Direct ints (including numpy ints) if isinstance(n_input, (int, np.integer)): return abs(int(n_input)) # Fractions: only return if it's an integer fraction (denominator == 1) if isinstance(n_input, Fraction): if n_input.denominator == 1: return abs(int(n_input.numerator)) return None # Floats: accept only if near integer if isinstance(n_input, (float, np.floating)): if is_near_integer(n_input): return abs(int(round(float(n_input)))) return None # Complex: require imag ≈ 0 and real near-integer if isinstance(n_input, complex): if abs(n_input.imag) < 1e-12 and is_near_integer(n_input.real): return abs(int(round(n_input.real))) return None # numpy-quaternion or other quaternion types where 'w' is scalar part try: # `quaternion` type from numpy-quaternion has attribute 'w' # if isinstance(n_input, quaternion): # w = getattr(n_input, 'w', None) # if w is not None and is_near_integer(w): # return abs(int(round(float(w))) if quaternion is not None and isinstance(n_input, quaternion): if is_near_integer(n_input.w): return abs(int(round(n_input.w))) return None except Exception: # If quaternion type is not available or isinstance check fails, continue pass # If object exposes 'coeffs' (list/np.array), use first component if hasattr(n_input, "coeffs"): coeffs = getattr(n_input, "coeffs") # numpy array if isinstance(coeffs, np.ndarray): if coeffs.size > 0 and is_near_integer(coeffs.flatten()[0]): return abs(int(round(float(coeffs.flatten()[0])))) return None # list/tuple-like try: # convert to list (works for many iterables) c0 = list(coeffs)[0] if is_near_integer(c0): return abs(int(round(float(c0)))) return None except Exception: # can't iterate coeffs reliably pass # Some classes expose 'coefficients' name instead if hasattr(n_input, "coefficients"): try: c0 = list(getattr(n_input, "coefficients"))[0] if is_near_integer(c0): return abs(int(round(float(c0)))) except Exception: pass # Try common scalar attributes in order of likelihood for attr in ("w", "real", "t", "a", "value"): if hasattr(n_input, attr): val = getattr(n_input, attr) # If this is complex-like, use real part if isinstance(val, complex): if abs(val.imag) < 1e-12 and is_near_integer(val.real): return abs(int(round(val.real))) else: try: if is_near_integer(val): return abs(int(round(float(val)))) except Exception: pass # CliffordNumber: check basis dict scalar part '' if hasattr(n_input, "basis") and isinstance(getattr(n_input, "basis"), dict): scalar = n_input.basis.get("", 0) try: if is_near_integer(scalar): return abs(int(round(float(scalar)))) except Exception: pass # DualNumber / Superreal / others: if they expose .real attribute (and it's numeric) if hasattr(n_input, "real") and not isinstance( n_input, (complex, float, int, np.floating, np.integer) ): try: real_val = getattr(n_input, "real") if is_near_integer(real_val): return abs(int(round(float(real_val)))) except Exception: pass # TernaryNumber: convert digits to decimal if hasattr(n_input, "digits"): try: digits = list(n_input.digits) decimal_value = 0 for i, d in enumerate(reversed(digits)): decimal_value += int(d) * (3**i) return abs(int(decimal_value)) except Exception: pass # HyperrealNumber: use finite part (sequence[0]) if present if hasattr(n_input, "sequence") and isinstance( getattr(n_input, "sequence"), (list, tuple) ): seq = getattr(n_input, "sequence") if seq: try: if is_near_integer(seq[0]): return abs(int(round(float(seq[0])))) except Exception: pass # Fallback: try numeric coercion + is_near_integer try: if is_near_integer(n_input): return abs(int(round(float(n_input)))) except Exception: pass # If nothing matched, return None return None except Exception: # On any unexpected failure, return None rather than raising return None
[docs] def is_prime(n_input: Any) -> bool: """ Checks if a given number (or its principal component) is prime using the robust sympy.isprime function. """ # Adım 1: Karmaşık sayı türünden tamsayıyı çıkarma (Bu kısım aynı kalıyor) value_to_check = _get_integer_representation(n_input) # Adım 2: Tamsayı geçerli değilse False döndür if value_to_check is None: return False # Adım 3: Asallık testini sympy'ye bırak # sympy.isprime, 2'den küçük sayılar (1, 0, negatifler) için zaten False döndürür. return sympy.isprime(value_to_check)
def generate_kececi_vectorial(q0_str, c_str, u_str, iterations): """ Keçeci Haritası'nı tam vektörel toplama ile üreten geliştirilmiş fonksiyon. Bu, kütüphanenin ana üretim fonksiyonu olabilir. Tüm girdileri metin (string) olarak alarak esneklik sağlar. """ try: # Girdi metinlerini kuaterniyon nesnelerine dönüştür w, x, y, z = map(float, q0_str.split(",")) q0 = quaternion(w, x, y, z) cw, cx, cy, cz = map(float, c_str.split(",")) c = quaternion(cw, cx, cy, cz) uw, ux, uy, uz = map(float, u_str.split(",")) u = quaternion(uw, ux, uy, uz) except (ValueError, IndexError): raise ValueError("Girdi metinleri 'w,x,y,z' formatında olmalıdır.") trajectory = [q0] prime_events = [] current_q = q0 for i in range(iterations): y = current_q + c processing_val = y while True: scalar_int = int(processing_val.w) if scalar_int % 2 == 0: next_q = processing_val / 2.0 break elif scalar_int % 3 == 0: next_q = processing_val / 3.0 break elif is_prime(scalar_int): if processing_val == y: prime_events.append((i, scalar_int)) processing_val += u continue else: next_q = processing_val break trajectory.append(next_q) current_q = next_q return trajectory, prime_events def analyze_all_types(iterations=120, additional_params=None): """ Performs automated analysis on all Keçeci number types. - Uses module-level helpers (_find_kececi_zeta_zeros, _compute_gue_similarity, get_with_params, _plot_comparison). - Avoids heavy imports at module import time by importing lazily where needed. - Iterates over 1..TYPE_TERNARY (inclusive). Returns: (sorted_by_zeta, sorted_by_gue) """ print("Automated Analysis for Keçeci Types") print("=" * 80) include_intermediate = True results = [] # Default parameter sets (keçeçi testleri için örnekler) param_sets = [ ("2.0", "3.0"), ("1+1j", "0.5+0.5j"), ("1.0,0.0,0.0,0.0", "0.1,0.0,0.0,0.0"), ("0.8,0.1,0.1", "0.0,0.05,0.0"), ("1.0", "0.1"), ("102", "1"), ] if additional_params: param_sets.extend(additional_params) type_names = { 1: "Positive Real", 2: "Negative Real", 3: "Complex", 4: "Float", 5: "Rational", 6: "Quaternion", 7: "Neutrosophic", 8: "Neutro-Complex", 9: "Hyperreal", 10: "Bicomplex", 11: "Neutro-Bicomplex", 12: "Octonion", 13: "Sedenion", 14: "Clifford", 15: "Dual", 16: "Split-Complex", 17: "Pathion", 18: "Chingon", 19: "Routon", 20: "Voudon", 21: "Super Real", 22: "Ternary", 23: "Hypercomplex", } # Iterate all defined types (inclusive) for kececi_type in range(TYPE_POSITIVE_REAL, TYPE_HYPERCOMPLEX + 1): name = type_names.get(kececi_type, f"Type {kececi_type}") best_zeta_score = 0.0 best_gue_score = 0.0 best_params = None print(f"\nAnalyzing type {kececi_type} ({name})...") for start, add in param_sets: try: # generate sequence (get_with_params is defined in this module) sequence = get_with_params( kececi_type_choice=kececi_type, iterations=iterations, start_value_raw=start, add_value_raw=add, include_intermediate_steps=include_intermediate, ) if not sequence or len(sequence) < 20: # Skip too-short sequences # (analysis routines expect some minimal data) print(f" Skipped (insufficient length): params {start}, {add}") continue # Lazy import heavy helper functions (they exist in-module) try: zzeros, zeta_score = _find_kececi_zeta_zeros( sequence, tolerance=0.5 ) except Exception as zz_err: zzeros, zeta_score = [], 0.0 print( f" Warning: _find_kececi_zeta_zeros failed for {name} with params {start},{add}: {zz_err}" ) try: gue_score, gue_p = _compute_gue_similarity(sequence) except Exception as gue_err: gue_score, gue_p = 0.0, 0.0 print( f" Warning: _compute_gue_similarity failed for {name} with params {start},{add}: {gue_err}" ) if zeta_score > best_zeta_score or ( zeta_score == best_zeta_score and gue_score > best_gue_score ): best_zeta_score = zeta_score best_gue_score = gue_score best_params = (start, add) except Exception as e: print( f" Error analyzing params ({start}, {add}) for type {kececi_type}: {e}" ) continue if best_params: results.append( { "type": kececi_type, "name": name, "start": best_params[0], "add": best_params[1], "zeta_score": best_zeta_score, "gue_score": best_gue_score, } ) else: print(f" No successful parameter set found for {name}.") # Sort and display results sorted_by_zeta = sorted(results, key=lambda x: x["zeta_score"], reverse=True) sorted_by_gue = sorted(results, key=lambda x: x["gue_score"], reverse=True) # Plot comparison if there are results (lazy-plot) try: if sorted_by_zeta or sorted_by_gue: _plot_comparison(sorted_by_zeta, sorted_by_gue) except Exception as plot_err: print(f"Plotting failed: {plot_err}") return sorted_by_zeta, sorted_by_gue def _load_zeta_zeros(filename="zeta.txt"): """ Loads Riemann zeta zeros from a text file. Each line should contain one floating-point number representing the imaginary part of a zeta zero. Lines that are empty or start with '#' are ignored. Returns: numpy.ndarray of zeros, or empty array if file not found / invalid. """ try: with open(filename, "r", encoding="utf-8") as file: lines = file.readlines() zeta_zeros = [] for line in lines: line = line.strip() if not line or line.startswith("#"): continue try: zeta_zeros.append(float(line)) except ValueError: logger.warning("Invalid line skipped in %s: %r", filename, line) logger.info("%d zeta zeros loaded from %s.", len(zeta_zeros), filename) return np.array(zeta_zeros) except FileNotFoundError: logger.warning("Zeta zeros file '%s' not found.", filename) return np.array([]) except Exception as e: logger.exception("Error while loading zeta zeros from %s: %s", filename, e) return np.array([]) def _compute_gue_similarity(sequence, tolerance=0.5): """ Measures how closely the frequency spectrum of a Keçeci sequence matches the GUE (Gaussian Unitary Ensemble) statistics. Uses Kolmogorov-Smirnov test against Wigner-Dyson distribution. Args: sequence (list): The Keçeci number sequence. tolerance (float): Not used here; kept for interface consistency. Returns: tuple: (similarity_score, p_value) """ from . import _get_integer_representation values = [ val for z in sequence if (val := _get_integer_representation(z)) is not None ] if len(values) < 10: return 0.0, 0.0 values = np.array(values) - np.mean(values) N = len(values) powers = np.abs(fft(values)) ** 2 freqs = fftfreq(N) mask = freqs > 0 freqs_pos = freqs[mask] powers_pos = powers[mask] if len(powers_pos) == 0: return 0.0, 0.0 peaks, _ = find_peaks(powers_pos, height=np.max(powers_pos) * 1e-7) strong_freqs = freqs_pos[peaks] if len(strong_freqs) < 2: return 0.0, 0.0 # Scale so the strongest peak aligns with the first Riemann zeta zero peak_freq = strong_freqs[np.argmax(powers_pos[peaks])] scale_factor = 14.134725 / peak_freq scaled_freqs = np.sort(strong_freqs * scale_factor) # Compute level spacings if len(scaled_freqs) < 2: return 0.0, 0.0 diffs = np.diff(scaled_freqs) if np.mean(diffs) == 0: return 0.0, 0.0 diffs_norm = diffs / np.mean(diffs) # Generate GUE sample using Wigner-Dyson distribution def wigner_dyson(s): return (32 / np.pi) * s**2 * np.exp(-4 * s**2 / np.pi) s_gue = np.linspace(0.01, 3.0, 1000) p_gue = wigner_dyson(s_gue) p_gue = p_gue / np.sum(p_gue) sample_gue = np.random.choice(s_gue, size=1000, p=p_gue) # Perform KS test ks_stat, ks_p = ks_2samp(diffs_norm, sample_gue) similarity_score = 1.0 - ks_stat return similarity_score, ks_p def _plot_comparison(zeta_results, gue_results): """ Generates bar charts comparing the performance of Keçeci types in matching Riemann zeta zeros and GUE statistics. Args: zeta_results (list): Results sorted by zeta matching score. gue_results (list): Results sorted by GUE similarity score. """ # Riemann Zeta Matching Plot plt.figure(figsize=(14, 7)) types = [r["name"] for r in zeta_results] scores = [r["zeta_score"] for r in zeta_results] colors = ["skyblue"] * len(scores) if scores: colors[0] = "red" bars = plt.bar(types, scores, color=colors, edgecolor="black", alpha=0.8) plt.xticks(rotation=45, ha="right") plt.ylabel("Riemann Zeta Matching Score") plt.title("Keçeci Types vs Riemann Zeta Zeros") plt.grid(True, alpha=0.3) if bars: bars[0].set_edgecolor("darkred") bars[0].set_linewidth(1.5) plt.tight_layout() plt.show() # GUE Similarity Plot plt.figure(figsize=(14, 7)) types = [r["name"] for r in gue_results] scores = [r["gue_score"] for r in gue_results] colors = ["skyblue"] * len(scores) if scores: colors[0] = "red" bars = plt.bar(types, scores, color=colors, edgecolor="black", alpha=0.8) plt.xticks(rotation=45, ha="right") plt.ylabel("GUE Similarity Score") plt.title("Keçeci Types vs GUE Statistics") plt.grid(True, alpha=0.3) if bars: bars[0].set_edgecolor("darkred") bars[0].set_linewidth(1.5) plt.tight_layout() plt.show() def _find_kececi_zeta_zeros(sequence, tolerance=0.5): """ Estimates the zeros of the Keçeci Zeta Function from the spectral peaks of the sequence. Compares them to known Riemann zeta zeros. Args: sequence (list): The Keçeci number sequence. tolerance (float): Maximum distance for a match between Keçeci and Riemann zeros. Returns: tuple: (list of Keçeci zeta zeros, matching score) """ from . import _get_integer_representation values = [ val for z in sequence if (val := _get_integer_representation(z)) is not None ] if len(values) < 10: return [], 0.0 values = np.array(values) - np.mean(values) N = len(values) powers = np.abs(fft(values)) ** 2 freqs = fftfreq(N) mask = freqs > 0 freqs_pos = freqs[mask] powers_pos = powers[mask] if len(powers_pos) == 0: return [], 0.0 peaks, _ = find_peaks(powers_pos, height=np.max(powers_pos) * 1e-7) strong_freqs = freqs_pos[peaks] if len(strong_freqs) < 2: return [], 0.0 # Scale so the strongest peak aligns with the first Riemann zeta zero peak_freq = strong_freqs[np.argmax(powers_pos[peaks])] scale_factor = 14.134725 / peak_freq scaled_freqs = np.sort(strong_freqs * scale_factor) # Find candidate zeros by analyzing the Keçeci Zeta Function t_vals = np.linspace(0, 650, 10000) zeta_vals = np.array( [sum((scaled_freqs + 1e-10) ** (-(0.5 + 1j * t))) for t in t_vals] ) minima, _ = find_peaks( -np.abs(zeta_vals), height=-0.5 * np.max(np.abs(zeta_vals)), distance=5 ) kececi_zeta_zeros = t_vals[minima] # Load Riemann zeta zeros for comparison zeta_zeros_imag = _load_zeta_zeros("zeta.txt") if len(zeta_zeros_imag) == 0: return kececi_zeta_zeros, 0.0 # Calculate matching score close_matches = [ kz for kz in kececi_zeta_zeros if min(abs(kz - zeta_zeros_imag)) < tolerance ] score = ( len(close_matches) / len(kececi_zeta_zeros) if kececi_zeta_zeros.size > 0 else 0.0 ) return kececi_zeta_zeros, score def _pair_correlation(ordered_zeros, max_gap=3.0, bin_size=0.1): """ Computes the pair correlation of a list of ordered zeros. This function calculates the normalized spacings between all pairs of zeros and returns a histogram of their distribution. Args: ordered_zeros (numpy.ndarray): Sorted array of zero locations (e.g., Keçeci or Riemann zeta zeros). max_gap (float): Maximum normalized gap to consider. bin_size (float): Size of bins for the histogram. Returns: tuple: (bin_centers, histogram) - The centers of the bins and the normalized histogram values. """ n = len(ordered_zeros) if n < 2: return np.array([]), np.array([]) # Compute average spacing for normalization avg_spacing = np.mean(np.diff(ordered_zeros)) normalized_zeros = ordered_zeros / avg_spacing # Compute all pairwise gaps within max_gap gaps = [] for i in range(n): for j in range(i + 1, n): gap = abs(normalized_zeros[j] - normalized_zeros[i]) if gap <= max_gap: gaps.append(gap) # Generate histogram bins = np.arange(0, max_gap + bin_size, bin_size) hist, _ = np.histogram(gaps, bins=bins, density=True) bin_centers = (bins[:-1] + bins[1:]) / 2 return bin_centers, hist def _gue_pair_correlation(s): """ Theoretical pair correlation function for the Gaussian Unitary Ensemble (GUE). This function is used as a reference for comparing the statistical distribution of eigenvalues (or zeta zeros) in quantum chaotic systems. Args: s (numpy.ndarray or float): Normalized spacing(s). Returns: numpy.ndarray or float: The GUE pair correlation value(s) at s. """ return 1 - np.sinc(s) ** 2 def analyze_pair_correlation(sequence, title="Pair Correlation of Keçeci Zeta Zeros"): """ Analyzes and plots the pair correlation of Keçeci Zeta zeros derived from a Keçeci sequence. Compares the empirical pair correlation to the theoretical GUE prediction. Performs a Kolmogorov-Smirnov test to quantify the similarity. Args: sequence (list): A Keçeci number sequence. title (str): Title for the resulting plot. """ from . import _get_integer_representation # Extract integer representations and remove DC component values = [ val for z in sequence if (val := _get_integer_representation(z)) is not None ] if len(values) < 10: print("Insufficient data.") return values = np.array(values) - np.mean(values) N = len(values) powers = np.abs(fft(values)) ** 2 freqs = fftfreq(N) # Filter positive frequencies mask = freqs > 0 freqs_pos = freqs[mask] powers_pos = powers[mask] if len(powers_pos) == 0: print("No positive frequencies found.") return # Find spectral peaks peaks, _ = find_peaks(powers_pos, height=np.max(powers_pos) * 1e-7) strong_freqs = freqs_pos[peaks] if len(strong_freqs) < 2: print("Insufficient frequency peaks.") return # Scale frequencies so the strongest peak aligns with the first Riemann zeta zero peak_freq = strong_freqs[np.argmax(powers_pos[peaks])] scale_factor = 14.134725 / peak_freq scaled_freqs = np.sort(strong_freqs * scale_factor) # Estimate Keçeci Zeta zeros by finding minima of |ζ_Kececi(0.5 + it)| t_vals = np.linspace(0, 650, 10000) zeta_vals = np.array( [sum((scaled_freqs + 1e-10) ** (-(0.5 + 1j * t))) for t in t_vals] ) minima, _ = find_peaks( -np.abs(zeta_vals), height=-0.5 * np.max(np.abs(zeta_vals)), distance=5 ) kececi_zeta_zeros = t_vals[minima] if len(kececi_zeta_zeros) < 2: print("Insufficient Keçeci zeta zeros found.") return # Compute pair correlation bin_centers, hist = _pair_correlation(kececi_zeta_zeros, max_gap=3.0, bin_size=0.1) gue_corr = _gue_pair_correlation(bin_centers) # Plot results plt.figure(figsize=(12, 6)) plt.plot(bin_centers, hist, "o-", label="Keçeci Zeta Zeros", linewidth=2) plt.plot(bin_centers, gue_corr, "r-", label="GUE (Theoretical)", linewidth=2) plt.title(title) plt.xlabel("Normalized Spacing (s)") plt.ylabel("Pair Correlation Density") plt.legend() plt.grid(True, alpha=0.3) plt.tight_layout() plt.show() # Perform Kolmogorov-Smirnov test ks_stat, ks_p = ks_2samp(hist, gue_corr) print(f"Pair Correlation KS Test: Statistic={ks_stat:.4f}, p-value={ks_p:.4f}") # ============================================================================== # --- CORE GENERATOR --- # ============================================================================== def _parse_kececi_values( kececi_type: int, start_input_raw: str, add_input_raw: str = "0" ) -> Tuple[Any, Any]: """ Tüm tipler destekler """ def safe_float(x): try: return float(x) except: return 0.0 try: # ✅ BASİT TÜRLER (1-5) if kececi_type in [1, 2, 4, 5]: start_val = safe_float(start_input_raw) add_val = safe_float(add_input_raw) if kececi_type == 1: return abs(start_val), abs(add_val) if kececi_type == 2: return -abs(start_val), -abs(add_val) return start_val, add_val # COMPLEX if kececi_type == 3: return complex(start_input_raw), complex(add_input_raw) # ✅ TERNARY (22) if kececi_type == 22: return _parse_ternary(start_input_raw), _parse_ternary(add_input_raw) # QUATERNION (6) if kececi_type == 6: from kececinumbers import _parse_quaternion return _parse_quaternion(start_input_raw), _parse_quaternion(add_input_raw) # ✅ GENEL FALLBACK - TÜM DİĞER TİPLER dims = {12: 8, 13: 16, 20: 32}.get(kececi_type, 4) start_list = [safe_float(start_input_raw)] + [0.0] * (dims - 1) add_list = [safe_float(add_input_raw)] + [0.0] * (dims - 1) return start_list, add_list except Exception as e: print(f"Parse fallback type {kececi_type}: {e}") return safe_float(start_input_raw), safe_float(add_input_raw) """ def _parse_kececi_values( kececi_type: int, start_input_raw: str, add_input_raw: str ) -> Tuple[Any, Any]: #Parse values for a specific Keçeci number type. #Returns (start_value, add_value) try: # Import parsers from .kececinumbers import _parse_fraction # For basic types (1, 2, 4, 5) use _parse_fraction if kececi_type in [1, 2, 4, 5]: start_val = _parse_fraction(start_input_raw) add_val = _parse_fraction(add_input_raw) if kececi_type == 1: # Positive Real return abs(start_val), abs(add_val) elif kececi_type == 2: # Negative Real return -abs(start_val), -abs(add_val) else: # Type 4 (Float), 5 (Rational) return start_val, add_val # For complex type (3) elif kececi_type == 3: from .kececinumbers import _parse_complex return _parse_complex(start_input_raw), _parse_complex(add_input_raw) # For other types, try to import specific parsers else: # Try to import all parsers try: from .kececinumbers import ( _parse_bicomplex, _parse_chingon, _parse_clifford, _parse_complex, _parse_complex_like_string, _parse_dual, _parse_engineering_notation, _parse_fraction, _parse_hyperreal, _parse_neutrosophic, _parse_neutrosophic_bicomplex, _parse_neutrosophic_complex, _parse_octonion, _parse_pathion, _parse_quaternion, _parse_quaternion_from_csv, _parse_real, _parse_routon, _parse_sedenion, _parse_splitcomplex, _parse_super_real, _parse_superreal, _parse_ternary, _parse_hypercomplex, _parse_universal, _parse_voudon, _generate_simple_ask_sequence, _parse_with_fallback_simple, _parse_kececi_values, parse_to_hyperreal, parse_to_neutrosophic, ) # Map type to parser parser_map = { 6: _parse_quaternion, 7: _parse_neutrosophic, 8: _parse_neutrosophic_complex, 9: _parse_hyperreal, 10: _parse_bicomplex, 11: _parse_neutrosophic_bicomplex, 12: _parse_octonion, 13: _parse_sedenion, 14: _parse_clifford, 15: _parse_dual, 16: _parse_splitcomplex, 17: _parse_pathion, 18: _parse_chingon, 19: _parse_routon, 20: _parse_voudon, 21: _parse_super_real, 22: _parse_ternary, 23: _parse_hypercomplex, } parser = parser_map.get(kececi_type) if parser: return parser(start_input_raw), parser(add_input_raw) else: raise ValueError(f"No parser for type {kececi_type}") except ImportError: # Fallback to simple parsing logger.warning(f"Parsers not available for type {kececi_type}, using fallback") return _parse_with_fallback_simple(kececi_type, start_input_raw, add_input_raw) except Exception as e: logger.error(f"Error parsing values for type {kececi_type}: {e}") # Fallback to simple parsing return _parse_with_fallback_simple(kececi_type, start_input_raw, add_input_raw) """ def get_parser(kececi_type: int) -> Callable[[Any], Any]: """Parser fonksiyonunu döndürür - test beklentilerine uygun.""" parsers = { # Basit Python tipleri (test beklentileri) TYPE_POSITIVE_REAL: lambda s: int(_parse_fraction(s)), # int TYPE_NEGATIVE_REAL: lambda s: int(-_parse_fraction(s)), # int TYPE_FLOAT: lambda s: float(_parse_fraction(s)), # float TYPE_RATIONAL: lambda s: Fraction.from_float(_parse_fraction(s)), # Fraction TYPE_COMPLEX: lambda s: complex(s), # built-in complex # Kececi özel tipler (import edilen parser'lar) TYPE_QUATERNION: _parse_quaternion, TYPE_NEUTROSOPHIC: _parse_neutrosophic, TYPE_NEUTROSOPHIC_COMPLEX: _parse_neutrosophic_complex, TYPE_HYPERREAL: _parse_hyperreal, TYPE_BICOMPLEX: _parse_bicomplex, TYPE_NEUTROSOPHIC_BICOMPLEX: _parse_neutrosophic_bicomplex, TYPE_OCTONION: _parse_octonion, TYPE_SEDENION: _parse_sedenion, TYPE_CLIFFORD: _parse_clifford, TYPE_DUAL: _parse_dual, TYPE_SPLIT_COMPLEX: _parse_splitcomplex, TYPE_PATHION: _parse_pathion, TYPE_CHINGON: _parse_chingon, TYPE_ROUTON: _parse_routon, TYPE_VOUDON: _parse_voudon, TYPE_SUPERREAL: _parse_super_real, TYPE_TERNARY: _parse_ternary, TYPE_HYPERCOMPLEX: _parse_hypercomplex, } parser = parsers.get(kececi_type) if parser is None: raise ValueError(f"Unsupported kececi_type: {kececi_type}") return parser def _parse_with_fallback_simple( kececi_type: int, start_input_raw: str, add_input_raw: str ) -> Tuple[Any, Any]: """ Simple fallback parser when main parsers fail. Accepts flexible inputs: - plain numbers: "3.5", "2", "-1" - fractions: "3/4" - mixed numbers: "1 1/2" - complex: "1+2i", "3-4j" - lists/tuples: "[1,2,3]", "(1, 2, 3)", "1,2,3", "1 2 3" - component-wise complex: "1+2i,3+4i" Returns values mapped to the requested algebraic type. """ def parse_number_token(tok: str): tok = tok.strip() if not tok: return 0.0 # normalize imaginary unit tok = tok.replace("I", "i").replace("J", "j").replace("i", "j") # try complex first try: # complex() accepts '1+2j' or '2j' etc. c = complex(tok) # if purely real, return float for convenience if c.imag == 0: return float(c.real) return c except Exception: pass # mixed number "a b/c" if " " in tok and "/" in tok: try: whole, frac = tok.split(" ", 1) num, den = frac.split("/") return float(whole) + (float(num) / float(den)) except Exception: pass # fraction "a/b" if "/" in tok: try: num, den = tok.split("/") return float(num) / float(den) except Exception: pass # fallback float try: return float(tok) except Exception: return 0.0 def parse_simple(val: str): if val is None: return 0.0 s = str(val).strip() if s == "": return 0.0 # If looks like a bracketed list or comma-separated components if ( (s.startswith("[") and s.endswith("]")) or (s.startswith("(") and s.endswith(")")) or ("," in s) ): # remove brackets inner = s.strip("[]() ") # split by comma first parts = [p.strip() for p in inner.split(",") if p.strip() != ""] if len(parts) == 1: # maybe space-separated inside single part parts = parts[0].split() comps = [] for p in parts: # allow each part to be complex or numeric comps.append(parse_number_token(p)) return comps # If space-separated multiple tokens (e.g., "1 2 3") if " " in s and "/" not in s: # avoid splitting mixed numbers like "1 1/2" parts = [p for p in s.split() if p != ""] if len(parts) > 1: return [parse_number_token(p) for p in parts] # single token: try to parse as number/complex return parse_number_token(s) # Parse base values start_base = parse_simple(start_input_raw) add_base = parse_simple(add_input_raw) # Helper to coerce parsed value into numeric list of length n def to_components(x, n): if isinstance(x, list) or isinstance(x, tuple): comps = list(x) elif isinstance(x, complex): comps = [x.real, x.imag] + [0.0] * (n - 2) else: comps = [float(x)] + [0.0] * (n - 1) # ensure length n if len(comps) < n: comps += [0.0] * (n - len(comps)) return comps[:n] # Map to appropriate type with flexible input handling if kececi_type == 1: # Positive Real s = ( float(start_base[0]) if isinstance(start_base, (list, tuple)) else float( start_base.real if isinstance(start_base, complex) else start_base ) ) a = ( float(add_base[0]) if isinstance(add_base, (list, tuple)) else float(add_base.real if isinstance(add_base, complex) else add_base) ) return abs(s), abs(a) elif kececi_type == 2: # Negative Real s = ( float(start_base[0]) if isinstance(start_base, (list, tuple)) else float( start_base.real if isinstance(start_base, complex) else start_base ) ) a = ( float(add_base[0]) if isinstance(add_base, (list, tuple)) else float(add_base.real if isinstance(add_base, complex) else add_base) ) return -abs(s), -abs(a) elif kececi_type == 3: # Complex # If parsed as list with 2 components, use them as (real, imag) def make_complex(x): if isinstance(x, complex): return x if isinstance(x, (list, tuple)): comps = to_components(x, 2) return complex(comps[0], comps[1]) return complex(float(x), 0.0) return make_complex(start_base), make_complex(add_base) elif kececi_type == 4: # Float def make_float(x): if isinstance(x, complex): return float(x.real) if isinstance(x, (list, tuple)): return float(x[0]) if len(x) > 0 else 0.0 return float(x) return make_float(start_base), make_float(add_base) elif kececi_type == 5: # Rational def make_fraction(x): try: if isinstance(x, (list, tuple)): return Fraction(float(x[0])).limit_denominator() if isinstance(x, complex): return Fraction(float(x.real)).limit_denominator() return Fraction(x).limit_denominator() except Exception: return Fraction(float(x)).limit_denominator() return make_fraction(start_base), make_fraction(add_base) elif kececi_type == 6: # Quaternion (4D tuple) s_comps = to_components(start_base, 4) a_comps = to_components(add_base, 4) return tuple(float(c) for c in s_comps), tuple(float(c) for c in a_comps) elif kececi_type == 7: # Neutrosophic (T, I, F) 3-tuple s_comps = to_components(start_base, 3) a_comps = to_components(add_base, 3) return (s_comps[0], s_comps[1], s_comps[2]), ( a_comps[0], a_comps[1], a_comps[2], ) elif kececi_type == 8: # Neutrosophic Complex (complex for T, I, F fallback) def to_nc(x): if isinstance(x, complex): return x if isinstance(x, (list, tuple)): # if list of two complex-like entries, combine first as real, second as imag comps = to_components(x, 2) return complex(comps[0], comps[1]) return complex(float(x), 0.0) return to_nc(start_base), to_nc(add_base) elif ( kececi_type == 9 ): # Hyperreal (finite, infinitesimal) -> tuple [real, infinitesimal] def to_hyperreal(x): if isinstance(x, (list, tuple)): comps = to_components(x, 2) return [float(comps[0]), float(comps[1])] if isinstance(x, complex): return [float(x.real), float(x.imag)] return [float(x), 0.0] return to_hyperreal(start_base), to_hyperreal(add_base) elif kececi_type == 10: # Bicomplex (fallback to complex) def to_bi(x): if isinstance(x, complex): return x if isinstance(x, (list, tuple)): comps = to_components(x, 2) return complex(comps[0], comps[1]) return complex(float(x), 0.0) return to_bi(start_base), to_bi(add_base) elif kececi_type == 11: # Neutrosophic Bicomplex (fallback to complex) def to_nb(x): if isinstance(x, complex): return x if isinstance(x, (list, tuple)): comps = to_components(x, 2) return complex(comps[0], comps[1]) return complex(float(x), 0.0) return to_nb(start_base), to_nb(add_base) elif kececi_type == 12: # Octonion (8D) s_comps = to_components(start_base, 8) a_comps = to_components(add_base, 8) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 13: # Sedenion (16D) s_comps = to_components(start_base, 16) a_comps = to_components(add_base, 16) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 14: # Clifford (simple dict) s0 = ( float(start_base[0]) if isinstance(start_base, (list, tuple)) else ( start_base.real if isinstance(start_base, complex) else float(start_base) ) ) a0 = ( float(add_base[0]) if isinstance(add_base, (list, tuple)) else (add_base.real if isinstance(add_base, complex) else float(add_base)) ) return {"e0": s0}, {"e0": a0} elif kececi_type == 15: # Dual (real, dual) s_comps = to_components(start_base, 2) a_comps = to_components(add_base, 2) return (s_comps[0], s_comps[1]), (a_comps[0], a_comps[1]) elif kececi_type == 16: # Split-complex s_comps = to_components(start_base, 2) a_comps = to_components(add_base, 2) return (s_comps[0], s_comps[1]), (a_comps[0], a_comps[1]) elif kececi_type == 17: # Pathion (32D) s_comps = to_components(start_base, 32) a_comps = to_components(add_base, 32) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 18: # Chingon (64D) s_comps = to_components(start_base, 64) a_comps = to_components(add_base, 64) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 19: # Routon (128D) s_comps = to_components(start_base, 128) a_comps = to_components(add_base, 128) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 20: # Voudon (256D) s_comps = to_components(start_base, 256) a_comps = to_components(add_base, 256) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 21: # Superreal (real, superreal) s_comps = to_components(start_base, 2) a_comps = to_components(add_base, 2) return (s_comps[0], s_comps[1]), (a_comps[0], a_comps[1]) elif kececi_type == 22: # Ternary (3D) s_comps = to_components(start_base, 3) a_comps = to_components(add_base, 3) return [float(c) for c in s_comps], [float(c) for c in a_comps] elif kececi_type == 23: # Hypercomplex (arbitrary-length components) # If user provided a list/tuple, use it; if single number, wrap it; if complex, split to [real, imag] def to_hc(x): if isinstance(x, (list, tuple)): return [ float(c.real) if isinstance(c, complex) else float(c) for c in x ] if isinstance(x, complex): return [float(x.real), float(x.imag)] return [float(x)] return to_hc(start_base), to_hc(add_base) else: # Default fallback: return parsed raw values coerced to floats where possible def fallback(x): if isinstance(x, complex): return float(x.real) if isinstance(x, (list, tuple)): return float(x[0]) if len(x) > 0 else 0.0 return float(x) return fallback(start_base), fallback(add_base) # ---------------------------------------------------------------------- # Ana ASK üretici (tüm tipler için) # ---------------------------------------------------------------------- """ # Parse işlemleri (mevcut kütüphanenizin parser'larını kullanın) parser_map = { 1: lambda s: float(s), # Positive Real 2: lambda s: -float(s), # Negative Real 3: lambda s: complex(s), # Complex 4: lambda s: float(s), # Float 5: lambda s: float(s), # Rational (float olarak) 6: lambda s: _parse_quaternion(s), # Quaternion 7: lambda s: _parse_neutrosophic(s), 8: lambda s: _parse_neutrosophic_complex(s), 9: lambda s: _parse_hyperreal(s), 10: lambda s: _parse_bicomplex(s), 11: lambda s: _parse_neutrosophic_bicomplex(s), 12: lambda s: _parse_octonion(s), 13: lambda s: _parse_sedenion(s), 14: lambda s: _parse_clifford(s), 15: lambda s: _parse_dual(s), 16: lambda s: _parse_splitcomplex(s), 17: lambda s: _parse_pathion(s), 18: lambda s: _parse_chingon(s), 19: lambda s: _parse_routon(s), 20: lambda s: _parse_voudon(s), 21: lambda s: _parse_superreal(s), 22: lambda s: _parse_ternary(s), 23: lambda s: _parse_hypercomplex(s), } parser = parser_map.get(kececi_type) if parser is None: raise ValueError(f"Tip {kececi_type} için parser tanımlanmamış.") start = parser(start_input_raw) add_val = parser(add_input_raw) """ def convert_to_plot_value(item): if isinstance(item, dict): val = item["value"] else: val = item return float(_first_component_as_int(val)) # veya doğrudan ilk bileşen def _first_component_as_int(val): """Her türlü Keçeci sayısından ilk sayısal bileşeni int olarak döndürür.""" try: # HyperrealNumber için if hasattr(val, "finite"): f = val.finite if not callable(val.finite) else val.finite() return int(round(float(f))) # BicomplexNumber için if hasattr(val, "a"): # BicomplexNumber'ın a attribute'ü complex olabilir a = val.a if hasattr(a, "real"): return int(round(float(a.real))) return int(round(float(a))) if hasattr(val, "real"): # complex, dual, split-complex, vs. r = val.real if callable(r): r = r() return int(round(float(r))) if hasattr(val, "t"): # NeutrosophicNumber return int(round(float(val.t))) if hasattr(val, "components"): comps = val.components if not callable(val.components) else val.components() if comps: return int(round(float(comps[0]))) if hasattr(val, "coeffs"): c = val.coeffs if not callable(val.coeffs) else val.coeffs() if c: return int(round(float(c[0]))) if isinstance(val, (int, float)): return int(round(val)) if isinstance(val, (list, tuple)) and val: return int(round(float(val[0]))) return 0 except: return 0 def make_unit(exemplar): cls = type(exemplar) if cls is dict: return {"": 1.0} if cls is tuple: return cls((1, 1, 1)) if cls is list: return cls([1, 1, 1]) if issubclass(cls, (int, float, complex)): return cls(1) if hasattr(cls, "__init__"): init = cls.__init__ if hasattr(init, "__code__"): total_args = init.__code__.co_argcount # self dahil expected = total_args - 1 if expected == 0: return cls() elif expected == 1: return cls(1) elif expected == 2: return cls(1, 1) elif expected == 3: return cls(1, 1, 1) elif expected == 4: return cls(1, 1, 1, 1) elif expected == 8: return cls(1, 1, 1, 1, 1, 1, 1, 1) else: return cls(*([1] * expected)) else: # built-in if cls in (int, float, complex, str, bool): return cls(1) elif cls in (tuple, list): return cls([1]) else: return cls() return cls(1)
[docs] def unified_generator( kececi_type: int, # Sayı tipi (7 = Neutrosophic) start_input_raw: str, # Başlangıç değeri ("3+2I") add_input_raw: str, # Artış miktarı (1.5) iterations: int, # İterasyon sayısı operation="ask", # İşlem tipi ('ask' = Collatz benzeri) include_intermediate_steps: bool = True, # Ara adımları dahil et? first_divisor: int = 3, # İlk bölen ask_plus_first: bool = True, # ASK işleminde önce +1 mi? ) -> List[Any]: """ 1. Başlangıç değerini parse et → start_value 2. Artış değerini parse et → add_value 3. İşlem tipine göre (operation) döngüyü çalıştır: - 'ask': Collatz benzeri kural - 'add': Sadece toplama - 'multiply': Çarpma - vs. 4. Her adımda: - include_intermediate_steps=True ise TÜM değerleri kaydet - False ise sadece ana adımları kaydet Keçeci sayıları üretici – 23 farklı sayı sistemi için ask_unit kullanır. Tüm matematiksel işlemler (+, -, *, /, %, is_prime_like) tip-specific olarak tanımlanmıştır. """ logger = logging.getLogger(__name__) def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) def _is_prime_decimal(n: int) -> bool: """Basit ve hızlı asallık testi.""" if n < 2: return False if n == 2 or n == 3: return True if n % 2 == 0 or n % 3 == 0: return False i = 5 while i * i <= n: if n % i == 0 or n % (i + 2) == 0: return False i += 6 return True # ------------------------------------------------------------------ # Yardımcı: make_unit (doğru argüman sayısı ile birim eleman üretir) # ------------------------------------------------------------------ def make_unit(exemplar): cls = type(exemplar) if cls is dict: return {"": 1.0} if cls is tuple: return cls((1, 1, 1)) if cls is list: return cls([1, 1, 1]) if issubclass(cls, (int, float, complex)): return cls(1) if hasattr(cls, "__init__"): init = cls.__init__ if hasattr(init, "__code__"): total_args = init.__code__.co_argcount # self dahil expected = total_args - 1 if expected == 0: return cls() elif expected == 1: return cls(1) elif expected == 2: return cls(1, 1) elif expected == 3: return cls(1, 1, 1) elif expected == 4: return cls(1, 1, 1, 1) elif expected == 8: return cls(1, 1, 1, 1, 1, 1, 1, 1) else: return cls(*([1] * expected)) else: # built-in if cls in (int, float, complex, str, bool): return cls(1) elif cls in (tuple, list): return cls([1]) else: return cls() return cls(1) # ------------------------------------------------------------------ # Parser (mevcut modülün get_parser'ını kullan, fallback ile) # ------------------------------------------------------------------ try: from .kececinumbers import get_parser as _get_parser base_parser = _get_parser(kececi_type) except ImportError: def base_parser(s): s = s.strip() if "," in s: parts = [p.strip() for p in s.split(",")] return [float(p) if "." in p or "e" in p else int(p) for p in parts] try: return int(s) if "." not in s and "e" not in s else float(s) except: return s def parser(val): """Güvenli parser: None/boş girdi -> 0, tip 7/8 için özel nesneler.""" if val is None: return 0 if isinstance(val, str) and val.strip() == "": return 0 return base_parser(val) start_val = parser(start_input_raw) add_val = parser(add_input_raw) # ------------------------------------------------------------------ # convert_to_number: ham veriyi uygun Keçeci sınıfına çevir # ------------------------------------------------------------------ def convert_to_number(val, typ): # Tip 7: NeutrosophicNumber if typ == 7: from .kececinumbers import NeutrosophicNumber if isinstance(val, NeutrosophicNumber): return val if isinstance(val, str): parts = val.split(",") t = float(parts[0]) if parts else 0.0 i = float(parts[1]) if len(parts) > 1 else 0.0 f = float(parts[2]) if len(parts) > 2 else 0.0 return NeutrosophicNumber(t, i, f) elif isinstance(val, (list, tuple)): return NeutrosophicNumber(*val) else: return NeutrosophicNumber(float(val), 0.0, 0.0) # Tip 8: NeutrosophicComplexNumber if typ == 8: from .kececinumbers import NeutrosophicComplexNumber if isinstance(val, NeutrosophicComplexNumber): return val if isinstance(val, str): parts = val.split(",") real = float(parts[0]) if parts else 0.0 imag = float(parts[1]) if len(parts) > 1 else 0.0 return NeutrosophicComplexNumber(real, imag) elif isinstance(val, (list, tuple)): return NeutrosophicComplexNumber(*val) else: return NeutrosophicComplexNumber(float(val), 0.0) # Tip 9: HyperrealNumber if typ == 9: from .kececinumbers import HyperrealNumber if isinstance(val, HyperrealNumber): return val if isinstance(val, str): parts = val.split(",") finite = float(parts[0]) if parts else 0.0 infinitesimal = float(parts[1]) if len(parts) > 1 else 0.0 return HyperrealNumber(finite, infinitesimal) elif isinstance(val, (list, tuple)): if len(val) >= 2: return HyperrealNumber(float(val[0]), float(val[1])) else: return HyperrealNumber(float(val[0]), 0.0) else: return HyperrealNumber(float(val), 0.0) # Tip 10: BicomplexNumber if typ == 10: from .kececinumbers import BicomplexNumber if isinstance(val, BicomplexNumber): return val if isinstance(val, str): parts = val.split(",") a = ( complex(float(parts[0]), float(parts[1])) if len(parts) > 1 else complex(float(parts[0]), 0) ) b = 0j return BicomplexNumber(a, b) elif isinstance(val, (list, tuple)): if len(val) >= 2: return BicomplexNumber(val[0], val[1]) else: return BicomplexNumber(val[0], 0j) else: return BicomplexNumber(complex(float(val), 0), 0j) # Tip 22: TernaryNumber if typ == 22: from .kececinumbers import TernaryNumber if isinstance(val, TernaryNumber): return val if isinstance(val, str): return TernaryNumber.from_ternary_string(val) if isinstance(val, (list, tuple)): # Eski parser'dan gelen [sayı, 0, 0] formatını temizle if len(val) == 3 and val[1] == 0.0 and val[2] == 0.0: return TernaryNumber.from_decimal(int(round(val[0]))) return TernaryNumber(val) if isinstance(val, (int, float)): return TernaryNumber.from_decimal(int(val)) return TernaryNumber.from_decimal(0) # Diğer tipler için doğrudan dönüş if isinstance(val, (int, float, complex)): return val if isinstance(val, str): try: return int(val) if "." not in val else float(val) except: return val if isinstance(val, (list, tuple)): return val return val start_val = convert_to_number(start_val, kececi_type) add_val = convert_to_number(add_val, kececi_type) # Güvenlik: None ise 0 ata if start_val is None: start_val = 0 if add_val is None: add_val = 0 def _first_component_as_int(val): """Her türlü Keçeci sayısından ilk sayısal bileşeni int olarak döndürür.""" try: if hasattr(val, "a"): return int(round(float(val.a.real))) # HyperrealNumber için if hasattr(val, "finite"): f = val.finite if not callable(val.finite) else val.finite() return int(round(float(f))) # BicomplexNumber için if hasattr(val, "a"): # BicomplexNumber'ın a attribute'ü complex olabilir a = val.a if hasattr(a, "real"): return int(round(float(a.real))) return int(round(float(a))) if hasattr(val, "real"): # complex, dual, split-complex, vs. r = val.real if callable(r): r = r() return int(round(float(r))) if hasattr(val, "t"): # NeutrosophicNumber return int(round(float(val.t))) if hasattr(val, "components"): comps = ( val.components if not callable(val.components) else val.components() ) if comps: return int(round(float(comps[0]))) if hasattr(val, "coeffs"): c = val.coeffs if not callable(val.coeffs) else val.coeffs() if c: return int(round(float(c[0]))) if isinstance(val, (int, float)): return int(round(val)) if isinstance(val, (list, tuple)) and val: return int(round(float(val[0]))) return 0 except: return 0 # Birim eleman (ask_unit) ask_unit = make_unit(start_val) # ------------------------------------------------------------------ # Tip-specific işlemlerin tanımı (1..23) # ------------------------------------------------------------------ if kececi_type in (1, 2, 4, 5): # Positive Real, Negative Real, Float, Rational def add(a, b): return a + b def is_divisible(val, d): try: return math.isclose(float(val) % d, 0) or math.isclose( float(val) % d, d ) except: return False def divide(val, d): if kececi_type in (1, 2): return int(float(val) // d) else: return float(val) / d def is_prime_like(val): v = int(round(float(val))) return v > 1 and isprime(v) elif kececi_type == 3: # Complex def add(a, b): return a + b def is_divisible(val, d): return math.isclose(val.real % d, 0) def divide(val, d): return complex(val.real / d, val.imag / d) def is_prime_like(val): v = int(round(val.real)) return v > 1 and isprime(v) elif kececi_type == 6: # Quaternion def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, "w"): return math.isclose(val.w % d, 0) return False def divide(val, d): if hasattr(val, "__truediv__"): return val / d return type(val)(val.w / d, val.x / d, val.y / d, val.z / d) def is_prime_like(val): v = int(round(val.w)) return v > 1 and isprime(v) elif kececi_type == 7: # NeutrosophicNumber Tipi (TYPE_NEUTROSOPHIC = 7) # ----- 1. TOPLAMA FONKSİYONU ----- # İki Neutrosophic sayıyı toplar # Örnek: (3+2I) + (1+1I) = (4+3I) def add(a, b): return a + b # NeutrosophicNumber.__add__ metodunu çağırır # ----- 2. BÖLÜNEBİLİRLİK KONTROLÜ ----- # Bir Neutrosophic sayının bir bölene tam bölünüp bölünmediğini kontrol eder # Bu, 1. KOD ile AYNI işlevi görür! def is_divisible(val, d): # val.t (truth/doğruluk bileşeni) kullanarak kontrol et # math.isclose ile kayan nokta hassasiyetinde kontrol return math.isclose(val.t % d, 0) if hasattr(val, "t") else False # ----- 3. BÖLME FONKSİYONU ----- # Neutrosophic sayının tüm bileşenlerini (t, i, f) bir sayıya böler # Bu, 2. KOD'un ÇİFT sayı durumundaki işlemin AYNISIDIR! # Örnek: (6+4I) / 2 = (3+2I) def divide(val, d): # Yeni bir NeutrosophicNumber oluştur: (t/d, i/d, f/d) return type(val)(val.t / d, val.i / d, val.f / d) # ----- 4. ASALLIK KONTROLÜ ----- # Bir Neutrosophic sayının "Keçeci Asal" olup olmadığını kontrol eder # Sadece deterministik kısım (t) kontrol edilir def is_prime_like(val): v = int(round(val.t)) # t bileşenini yuvarla ve integer'a çevir return v > 1 and isprime(v) # >1 ve asal mı? """ elif kececi_type == 7: # NeutrosophicNumber def add(a, b): return a + b def is_divisible(val, d): # val.t (T bileşeni) kullan return math.isclose(val.t % d, 0) if hasattr(val, 't') else False def divide(val, d): # Tüm bileşenleri d'ye böl return type(val)(val.t/d, val.i/d, val.f/d) def is_prime_like(val): v = int(round(val.t)) return v > 1 and isprime(v) """ elif kececi_type == 8: # NeutrosophicComplexNumber def add(a, b): return a + b def is_divisible(val, d): return math.isclose(val.real % d, 0) if hasattr(val, "real") else False def divide(val, d): return type(val)( val.real / d, val.imag / d, getattr(val, "indeterminacy", 0) / d ) def is_prime_like(val): v = int(round(val.real)) return v > 1 and isprime(v) """ elif kececi_type == 9: # HyperrealNumber from .kececinumbers import HyperrealNumber if isinstance(val, str): # NameError: name 'val' is not defined parts = val.split(',') finite = float(parts[0]) if parts else 0.0 infinitesimal = float(parts[1]) if len(parts) > 1 else 0.0 return HyperrealNumber(finite, infinitesimal) elif isinstance(val, (list, tuple)): if len(val) >= 2: return HyperrealNumber(float(val[0]), float(val[1])) else: return HyperrealNumber(float(val[0]), 0.0) else: return HyperrealNumber(float(val), 0.0) elif kececi_type == 10: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'a'): return math.isclose(val.a.real % d, 0) return False def divide(val, d): if hasattr(val, 'a'): return type(val)(val.a/d, val.b/d) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = type(start_val)(1+1j, 1+1j) """ """ # Bicomplex (tip 10) elif kececi_type == 10: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'a'): return math.isclose(val.a.real % d, 0) return False def divide(val, d): if hasattr(val, 'a'): return type(val)(val.a/d, val.b/d) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = type(start_val)(1+1j, 1+1j) # özel birim """ """ # Bicomplex (tip 10) elif kececi_type == 10: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'a'): return math.isclose(val.a.real % d, 0) return False def divide(val, d): if hasattr(val, 'a'): return type(val)(val.a/d, val.b/d) return val def is_prime_like(val): v = int(round(val.a.real)) return v > 1 and isprime(v) ask_unit = type(start_val)(1+1j, 1+1j) """ # Neutrosophic Bicomplex (tip 11) elif kececi_type == 11: def add(a, b): return a + b def is_divisible(val, d): v = int(round(val.coeffs[0].real if hasattr(val, "coeffs") else 0)) return math.isclose(v % d, 0) def divide(val, d): if hasattr(val, "coeffs"): c = val.coeffs if not callable(val.coeffs) else val.coeffs() return type(val)(*(x / d for x in c)) return val def is_prime_like(val): v = int(round(val.coeffs[0].real if hasattr(val, "coeffs") else 0)) return v > 1 and isprime(v) ask_unit = make_unit(start_val) elif kececi_type in (12, 13, 17, 18, 19, 20, 23): def add(a, b): return a + b def is_divisible(val, d): # Hem components hem coeffs kontrolü if hasattr(val, "components"): comps = ( val.components if not callable(val.components) else val.components() ) elif hasattr(val, "coeffs"): comps = val.coeffs if not callable(val.coeffs) else val.coeffs() else: return False if comps and len(comps) > 0: return math.isclose(comps[0] % d, 0) return False def divide(val, d): if hasattr(val, "components"): comps = ( val.components if not callable(val.components) else val.components() ) elif hasattr(val, "coeffs"): comps = val.coeffs if not callable(val.coeffs) else val.coeffs() else: return val new = [c / d for c in comps] try: return type(val)(*new) except TypeError: return type(val)(new) def is_prime_like(val): # Benzer şekilde components/coeffs kontrolü if hasattr(val, "components"): comps = ( val.components if not callable(val.components) else val.components() ) elif hasattr(val, "coeffs"): comps = val.coeffs if not callable(val.coeffs) else val.coeffs() else: return False first = comps[0] if comps else 0 v = int(round(float(first))) return v > 1 and isprime(v) """ elif kececi_type in (12, 13, 17, 18, 19, 20, 23): # Octonion, Sedenion, Pathion, Chingon, Routon, Voudon, Hypercomplex def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() if comps: return math.isclose(comps[0] % d, 0) return False def divide(val, d): if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() new = [c/d for c in comps] try: return type(val)(*new) except TypeError: return type(val)(new) return val def is_prime_like(val): if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() first = comps[0] if comps else 0 v = int(round(float(first))) return v > 1 and isprime(v) return False """ elif kececi_type == 14: # Clifford def add(a, b): return a + b def is_divisible(val, d): scalar = val.basis.get("", 0) return math.isclose(scalar % d, 0) def divide(val, d): new_basis = {k: v / d for k, v in val.basis.items()} return type(val)(new_basis) def is_prime_like(val): v = int(round(val.basis.get("", 0))) return v > 1 and isprime(v) elif kececi_type in (15, 16): # Dual, Split-Complex def add(a, b): return a + b def is_divisible(val, d): return math.isclose(val.real % d, 0) def divide(val, d): if hasattr(val, "dual"): return type(val)(val.real / d, val.dual / d) else: return type(val)(val.real / d, val.imag / d) def is_prime_like(val): v = int(round(val.real)) return v > 1 and isprime(v) # Super Real (tip 21) elif kececi_type == 21: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, "finite"): f = val.finite if not callable(val.finite) else val.finite() return math.isclose(f % d, 0) if isinstance(val, (int, float)): return math.isclose(val % d, 0) return False def divide(val, d): if hasattr(val, "finite"): f = val.finite if not callable(val.finite) else val.finite() i = ( val.infinitesimal if not callable(val.infinitesimal) else val.infinitesimal() ) return type(val)(f / d, i / d) if isinstance(val, (int, float)): return type(val)(val / d) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = make_unit(start_val) elif kececi_type == 22: # Ternary from .kececinumbers import ( TernaryNumber, _generate_ternary_ask_sequence, _generate_ternary_operation_sequence, ) start_str = str(start_input_raw).strip() add_str = str(add_input_raw).strip() if not all(c in "012" for c in start_str): raise ValueError(f"Geçersiz ternary başlangıç: {start_str}") if not all(c in "012" for c in add_str): raise ValueError(f"Geçersiz ternary artış: {add_str}") start_val = TernaryNumber.from_ternary_string(start_str) add_val = TernaryNumber.from_ternary_string(add_str) if operation == "ask": return _generate_ternary_ask_sequence( start_val, add_val, iterations, include_intermediate_steps ) else: return _generate_ternary_operation_sequence( start_val, add_val, iterations, operation, include_intermediate_steps ) else: # Fallback (sadece toplama) def add(a, b): return a + b def is_divisible(val, d): return False def divide(val, d): return val def is_prime_like(val): return False # ================================================================== # ASK algoritması (ask_unit kullanarak) # ================================================================== all_steps = [] main_steps = [] current = start_val ask_counter = 0 primary = first_divisor secondary = 2 if primary == 3 else 3 if include_intermediate_steps: all_steps.append(current) main_steps.append(current) for i in range(1, iterations + 1): added = add(current, add_val) if include_intermediate_steps: all_steps.append(added) next_val = added divided = False for divisor in (primary, secondary): if is_divisible(added, divisor): divided_val = divide(added, divisor) if include_intermediate_steps: all_steps.append(divided_val) next_val = divided_val divided = True if divisor == primary: primary, secondary = secondary, primary break if not divided and is_prime_like(added): delta = 1 if ask_counter == 0 else -1 if not ask_plus_first: delta = -delta # Güvenli birim ayarlaması (int * obj yerine) if delta == 1: unit_adjust = ask_unit else: # Negatif birim oluşturmayı dene try: unit_adjust = -ask_unit except Exception: # Negasyon yoksa, bileşenleri negatifleyerek yeni nesne oluştur if hasattr(ask_unit, "components"): neg_comps = [-c for c in ask_unit.components] unit_adjust = type(ask_unit)(*neg_comps) elif hasattr(ask_unit, "coeffs"): neg_coeffs = [-c for c in ask_unit.coeffs] unit_adjust = type(ask_unit)(*neg_coeffs) else: # En kötü durum: çarpma dene (eğer başarısız olursa hata fırlat) unit_adjust = ask_unit * (-1) adjusted = add(added, unit_adjust) if include_intermediate_steps: all_steps.append(adjusted) next_val = adjusted ask_counter = 1 - ask_counter ask_divided = False for divisor in (primary, secondary): if is_divisible(adjusted, divisor): final_val = divide(adjusted, divisor) if include_intermediate_steps: all_steps.append(final_val) next_val = final_val ask_divided = True if divisor == primary: primary, secondary = secondary, primary break if not ask_divided: next_val = adjusted current = next_val main_steps.append(current) if include_intermediate_steps: return all_steps else: return main_steps
""" def unified_generator( kececi_type: int, start_input_raw: str, add_input_raw: str, iterations: int, operation='ask', include_intermediate_steps: bool = True, first_divisor: int = 3, ask_plus_first: bool = True, ) -> List[Any]: #Keçeci sayıları üretici – 23 farklı sayı sistemi için ask_unit kullanır. #Tüm matematiksel işlemler (+, -, *, /, %, is_prime_like) tip-specific olarak tanımlanmıştır. logger = logging.getLogger(__name__) def _is_prime_decimal(n: int) -> bool: #Check if an integer is prime. if n < 2: return False if n == 2 or n == 3: return True if n % 2 == 0 or n % 3 == 0: return False i = 5 while i * i <= n: if n % i == 0 or n % (i + 2) == 0: return False i += 6 return True # ------------------------------------------------------------------ # Yardımcı: make_unit (doğru argüman sayısı ile birim eleman üretir) # ------------------------------------------------------------------ def make_unit(exemplar): cls = type(exemplar) if cls is dict: return {'': 1.0} if cls is tuple: return cls((1, 1, 1)) if cls is list: return cls([1, 1, 1]) if issubclass(cls, (int, float, complex)): return cls(1) if hasattr(cls, '__init__'): init = cls.__init__ if hasattr(init, '__code__'): total_args = init.__code__.co_argcount # self dahil expected = total_args - 1 if expected == 0: return cls() elif expected == 1: return cls(1) elif expected == 2: return cls(1, 1) elif expected == 3: return cls(1, 1, 1) elif expected == 4: return cls(1, 1, 1, 1) elif expected == 8: return cls(1, 1, 1, 1, 1, 1, 1, 1) else: return cls(*([1] * expected)) else: # built-in if cls in (int, float, complex, str, bool): return cls(1) elif cls in (tuple, list): return cls([1]) else: return cls() return cls(1) # ------------------------------------------------------------------ # Parser (mevcut modülün get_parser'ını kullan, fallback ile): PARSER (tek bir yerde) # ------------------------------------------------------------------ try: from .kececinumbers import get_parser as _get_parser parser = _get_parser(kececi_type) except ImportError: def parse_simple(s): s = s.strip() if ',' in s: parts = [p.strip() for p in s.split(',')] return [float(p) if '.' in p or 'e' in p else int(p) for p in parts] try: return int(s) if '.' not in s and 'e' not in s else float(s) except: return s parser = parse_simple start_val = parser(start_input_raw) add_val = parser(add_input_raw) # ---------- 2. ORTAK YARDIMCI: ilk bileşeni int'e çevir ---------- def _first_component_as_int(val): #Her türlü Keçeci sayısından ilk sayısal bileşeni int olarak döndürür. try: if hasattr(val, 'real'): r = val.real if callable(r): r = r() return int(round(float(r))) if hasattr(val, 'finite'): f = val.finite if callable(f): f = f() return int(round(float(f))) if hasattr(val, 'a'): a = val.a if hasattr(a, 'real'): return int(round(float(a.real))) return int(round(float(a))) if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() if comps: return int(round(float(comps[0]))) if hasattr(val, 'coeffs'): c = val.coeffs if not callable(val.coeffs) else val.coeffs() if c: return int(round(float(c[0]))) if isinstance(val, (int, float)): return int(round(val)) if isinstance(val, (list, tuple)) and val: return int(round(float(val[0]))) return 0 except: return 0 # ------------------------------------------------------------------ # Tip-specific işlemlerin tanımı (1..23) # ------------------------------------------------------------------ # Tip eşleme (sınıf isimleri) – dönüşüm için type_class_map = { 6: 'QuaternionNumber', 7: 'NeutrosophicNumber', 8: 'NeutrosophicComplexNumber', 10: 'BicomplexNumber', 11: 'NeutrosophicBicomplexNumber', 12: 'OctonionNumber', 13: 'SedenionNumber', 14: 'CliffordNumber', 15: 'DualNumber', 16: 'SplitcomplexNumber', 17: 'PathionNumber', 18: 'ChingonNumber', 19: 'RoutonNumber', 20: 'VoudonNumber', 21: 'SuperrealNumber', 22: 'TernaryNumber', 23: 'HypercomplexNumber' } def convert_to_number(val, typ): # TERNARY İÇİN YENİ EKLEME if typ == 22: from .kececinumbers import TernaryNumber if isinstance(val, str): return TernaryNumber.from_ternary_string(val) if isinstance(val, (list, tuple)): # Eski parser hatası için düzeltme if len(val) == 3 and val[1] == 0.0 and val[2] == 0.0: return TernaryNumber.from_decimal(int(round(val[0]))) return TernaryNumber(val) if isinstance(val, (int, float)): return TernaryNumber.from_decimal(int(val)) return TernaryNumber.from_decimal(0) # ORİJİNAL KOD (HİÇBİR ŞEY DEĞİŞTİRME) # Aşağıdaki satırlar zaten vardır, aynen bırakın if isinstance(val, (int, float, complex)): return val if isinstance(val, str): try: return int(val) if '.' not in val else float(val) except: return val if isinstance(val, (list, tuple)): return val return val # veya 0 def convert_to_number0(val, typ): if typ == 22: from .kececinumbers import TernaryNumber flat = val if isinstance(val, (list, tuple)) else [val] return TernaryNumber(*flat) if isinstance(val, (int, float, complex)): return val if isinstance(val, (list, tuple)): cls_name = type_class_map.get(typ) if cls_name and cls_name in globals(): cls = globals()[cls_name] try: return cls(*val) except TypeError: return cls(val) return val[0] if val else 0 return val start_val = convert_to_number(start_val, kececi_type) add_val = convert_to_number(add_val, kececi_type) # Birim eleman (ask_unit) ask_unit = make_unit(start_val) # ================================================================== # Tip-specific fonksiyonlar (1..23) # ================================================================== if kececi_type in (1, 2, 4, 5): # Positive Real, Negative Real, Float, Rational def add(a, b): return a + b def is_divisible(val, d): try: return math.isclose(float(val) % d, 0) or math.isclose(float(val) % d, d) except: return False def divide(val, d): if kececi_type in (1, 2): return int(float(val) // d) else: return float(val) / d def is_prime_like(val): v = int(round(float(val))) return v > 1 and isprime(v) elif kececi_type == 3: # Complex def add(a, b): return a + b def is_divisible(val, d): return math.isclose(val.real % d, 0) def divide(val, d): return complex(val.real / d, val.imag / d) def is_prime_like(val): v = int(round(val.real)) return v > 1 and isprime(v) elif kececi_type == 6: # Quaternion def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'w'): return math.isclose(val.w % d, 0) return False def divide(val, d): if hasattr(val, '__truediv__'): return val / d return type(val)(val.w/d, val.x/d, val.y/d, val.z/d) def is_prime_like(val): v = int(round(val.w)) return v > 1 and isprime(v) elif kececi_type == 7: # Neutrosophic def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 't'): return math.isclose(val.t % d, 0) return False def divide(val, d): if hasattr(val, 't'): return type(val)(val.t/d, val.i/d, val.f/d) return val def is_prime_like(val): try: # İlk bileşeni al (T) if isinstance(val, tuple) and len(val) >= 1: comp = val[0] elif hasattr(val, 't'): comp = val.t else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False #ask_unit = make_unit(start) elif kececi_type == 8: # Neutrosophic Complex def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'real'): return math.isclose(val.real % d, 0) return False def divide(val, d): if hasattr(val, 'real'): return type(val)(val.real/d, val.imag/d, getattr(val, 'indeterminacy', 0)/d) return val def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'real'): comp = val.real else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False #ask_unit = make_unit(start) # Hyperreal (tip 9) elif kececi_type == 9: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'finite'): f = val.finite if not callable(val.finite) else val.finite() return math.isclose(f % d, 0) return False def divide(val, d): if hasattr(val, 'finite'): f = val.finite if not callable(val.finite) else val.finite() i = val.infinitesimal if not callable(val.infinitesimal) else val.infinitesimal() return type(val)(f/d, i/d) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = make_unit(start_val) # Bicomplex (tip 10) elif kececi_type == 10: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'a'): return math.isclose(val.a.real % d, 0) return False def divide(val, d): if hasattr(val, 'a'): return type(val)(val.a/d, val.b/d) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = type(start_val)(1+1j, 1+1j) # özel birim # Neutrosophic Bicomplex (tip 11) elif kececi_type == 11: def add(a, b): return a + b def is_divisible(val, d): v = _first_component_as_int(val) return math.isclose(v % d, 0) def divide(val, d): if hasattr(val, 'coeffs'): c = val.coeffs if not callable(val.coeffs) else val.coeffs() return type(val)(*(x/d for x in c)) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = make_unit(start_val) elif kececi_type in (12, 13, 17, 18, 19, 20, 23): # Octonion, Sedenion, Pathion, Chingon, Routon, Voudon, Hypercomplex def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() if comps: return math.isclose(comps[0] % d, 0) return False def divide(val, d): if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() new = [c/d for c in comps] try: return type(val)(*new) except TypeError: return type(val)(new) return val def is_prime_like(val): if hasattr(val, 'components'): comps = val.components if not callable(val.components) else val.components() first = comps[0] if comps else 0 v = int(round(float(first))) return v > 1 and isprime(v) return False elif kececi_type == 14: # Clifford def add(a, b): return a + b def is_divisible(val, d): scalar = val.basis.get('', 0) return math.isclose(scalar % d, 0) def divide(val, d): new_basis = {k: v/d for k, v in val.basis.items()} return type(val)(new_basis) def is_prime_like(val): v = int(round(val.basis.get('', 0))) return v > 1 and isprime(v) elif kececi_type in (15, 16): # Dual, Split-Complex def add(a, b): return a + b def is_divisible(val, d): return math.isclose(val.real % d, 0) def divide(val, d): if hasattr(val, 'dual'): return type(val)(val.real/d, val.dual/d) else: return type(val)(val.real/d, val.imag/d) def is_prime_like(val): v = int(round(val.real)) return v > 1 and isprime(v) # Super Real (tip 21) elif kececi_type == 21: def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'finite'): f = val.finite if not callable(val.finite) else val.finite() return math.isclose(f % d, 0) # scalar ise doğrudan val if isinstance(val, (int, float)): return math.isclose(val % d, 0) return False def divide(val, d): if hasattr(val, 'finite'): f = val.finite if not callable(val.finite) else val.finite() i = val.infinitesimal if not callable(val.infinitesimal) else val.infinitesimal() return type(val)(f/d, i/d) if isinstance(val, (int, float)): return type(val)(val / d) return val def is_prime_like(val): v = _first_component_as_int(val) return v > 1 and isprime(v) ask_unit = make_unit(start_val) elif kececi_type == 22: # Ternary from .kececinumbers import TernaryNumber, _generate_ternary_ask_sequence, _generate_ternary_operation_sequence # Girdileri ternary string olarak kabul et start_str = str(start_input_raw).strip() add_str = str(add_input_raw).strip() # Geçerlilik kontrolü (sadece 0,1,2 rakamları) if not all(c in '012' for c in start_str): raise ValueError(f"Geçersiz ternary başlangıç: {start_str}") if not all(c in '012' for c in add_str): raise ValueError(f"Geçersiz ternary artış: {add_str}") start_value = TernaryNumber.from_ternary_string(start_str) add_value = TernaryNumber.from_ternary_string(add_str) if operation == 'ask': return _generate_ternary_ask_sequence(start_value, add_value, iterations, include_intermediate_steps) else: return _generate_ternary_operation_sequence(start_value, add_value, iterations, operation, include_intermediate_steps) else: # Fallback (sadece toplama) def add(a, b): return a + b def is_divisible(val, d): return False def divide(val, d): return val def is_prime_like(val): return False # ================================================================== # ASK algoritması (ask_unit kullanarak) – DÜZELTİLMİŞ VERSİYON # ================================================================== all_steps = [] # tüm adımlar (ara adımlar dahil) main_steps = [] # sadece ana adımlar (her iterasyon sonundaki current) current = start_val ask_counter = 0 primary = first_divisor secondary = 2 if primary == 3 else 3 # İlk değeri ekle if include_intermediate_steps: all_steps.append(current) main_steps.append(current) for i in range(1, iterations + 1): # 1. Adım: Add added = add(current, add_val) if include_intermediate_steps: all_steps.append(added) # 2. Adım: Bölünebilirlik kontrolü (primary, secondary) next_val = added divided = False for divisor in (primary, secondary): if is_divisible(added, divisor): divided_val = divide(added, divisor) if include_intermediate_steps: all_steps.append(divided_val) next_val = divided_val divided = True # swap divisors if divisor == primary: primary, secondary = secondary, primary break if not divided and is_prime_like(added): # ASK işlemi delta = 1 if ask_counter == 0 else -1 if not ask_plus_first: delta = -delta adjusted = add(added, delta * ask_unit) if include_intermediate_steps: all_steps.append(adjusted) next_val = adjusted ask_counter = 1 - ask_counter # ASK sonrası bölme kontrolü ask_divided = False for divisor in (primary, secondary): if is_divisible(adjusted, divisor): final_val = divide(adjusted, divisor) if include_intermediate_steps: all_steps.append(final_val) next_val = final_val ask_divided = True if divisor == primary: primary, secondary = secondary, primary break if not ask_divided: next_val = adjusted current = next_val # Ana adımı kaydet (her iterasyon sonundaki current) main_steps.append(current) # Sonuç döndür if include_intermediate_steps: return all_steps else: return main_steps # artık sadece son değer değil, tüm ana adımlar """ """ def unified_generator(kececi_type, start_input_raw, add_input_raw, iterations, include_intermediate_steps=True, first_divisor=3, ask_plus_first=True): from .kececinumbers import ( _parse_bicomplex, _parse_chingon, _parse_clifford, _parse_complex, _parse_complex_like_string, _parse_dual, _parse_engineering_notation, _parse_fraction, _parse_hyperreal, _parse_neutrosophic, _parse_neutrosophic_bicomplex, _parse_neutrosophic_complex, _parse_octonion, _parse_pathion, _parse_quaternion, _parse_quaternion_from_csv, _parse_real, _parse_routon, _parse_sedenion, _parse_splitcomplex, _parse_super_real, _parse_superreal, _parse_ternary, _parse_hypercomplex, _parse_universal, _parse_voudon, _generate_simple_ask_sequence, _parse_with_fallback_simple, _parse_kececi_values, parse_to_hyperreal, parse_to_neutrosophic, ) def _coerce_unit_to_value(unit, exemplar): try: if exemplar is None: return unit if type(unit) == type(exemplar): return unit cls = exemplar.__class__ # Eğer unit zaten iterable ise önce liste/tuple dene if hasattr(unit, "__iter__") and not isinstance(unit, (str, bytes)): try: return cls(list(unit)) except Exception: pass try: return cls(*unit) except Exception: pass # tek argümanlı constructor dene try: return cls(unit) except Exception: pass # fallback: orijinal unit return unit except Exception: return unit # --- Güvenli uygulama yardımcıları (operatörler için) --- def _safe_apply_op(a, op, b, integer_division=False): #a op b denemesi: + - * / ; integer_division yalnızca bölme için kullanılır. #Denemeler: a.op(b), b.op(a) (noncommutative için), fallback elementwise. try: if op == '+': return a + b if op == '-': return a - b if op == '*': return a * b if op == '/': # eğer b numeric scalar ise safe_divide kullan if isinstance(b, (int, float)): try: return _safe_divide(a, b, integer_division) except Exception: return a / b else: return a / b except Exception: # ters yönden dene (ör. scalar * hypercomplex) try: if op == '*': return b * a if op == '/': return b / a except Exception: pass # elementwise fallback: eğer her iki taraf da iterable ise elementwise uygula try: if hasattr(a, "__iter__") and hasattr(b, "__iter__") and not isinstance(a, (str, bytes)): la = list(a); lb = list(b) n = max(len(la), len(lb)) la += [0.0] * (n - len(la)) lb += [0.0] * (n - len(lb)) if op == '+': res = [x + y for x, y in zip(la, lb)] elif op == '-': res = [x - y for x, y in zip(la, lb)] elif op == '*': res = [x * y for x, y in zip(la, lb)] elif op == '/': res = [ (x / y if y != 0 else float('inf')) for x, y in zip(la, lb) ] # preserve type of a if possible try: return type(a)(res) except Exception: return res except Exception: pass raise TypeError("Operation not supported for given operands") # --- Güçlü safe_mul_add (value * multiplier + constant) --- def safe_mul_add(value: Any, multiplier: Any, constant: Any): try: multiplied = _safe_apply_op(value, '*', multiplier) except Exception: # fallback: try elementwise or python * try: multiplied = value * multiplier except Exception: multiplied = value try: return _safe_apply_op(multiplied, '+', constant) except Exception: try: return multiplied + constant except Exception: return multiplied def safe_add(a: Any, b: Any, direction: Optional[int] = None) -> Any: #Type-safe addition that handles various number types. #Args: # a: First value # b: Second value or unit # direction: Optional direction multiplier (1 for +, -1 for -) #Returns: # Result of safe addition try: # Apply direction if specified if direction is not None: b = b * direction if hasattr(b, "__mul__") else b # If both are same type or compatible types if type(a) == type(b): try: return a + b except Exception: pass # Convert to compatible types if possible # Handle Fraction with other types if isinstance(a, Fraction): if isinstance(b, (int, float)): return a + Fraction(b) elif isinstance(b, Fraction): return a + b else: # For other types, convert Fraction to float return float(a) + b elif isinstance(b, Fraction): if isinstance(a, (int, float)): return Fraction(a) + b else: return a + float(b) # Handle complex numbers if isinstance(a, complex) or isinstance(b, complex): # Convert both to complex try: a_complex = complex(a) if not isinstance(a, complex) else a b_complex = complex(b) if not isinstance(b, complex) else b return a_complex + b_complex except Exception: pass # Handle tuples/lists if isinstance(a, (tuple, list)) and isinstance(b, (tuple, list)): # Element-wise addition max_len = max(len(a), len(b)) result = [] for i in range(max_len): val_a = a[i] if i < len(a) else 0 val_b = b[i] if i < len(b) else 0 result.append(val_a + val_b) return ( tuple(result) if isinstance(a, tuple) and isinstance(b, tuple) else result ) # Scalar addition to tuple/list if isinstance(a, (tuple, list)) and isinstance(b, (int, float)): result = [x + b for x in a] return tuple(result) if isinstance(a, tuple) else result elif isinstance(b, (tuple, list)) and isinstance(a, (int, float)): result = [a + x for x in b] return tuple(result) if isinstance(b, tuple) else result # Default: try normal addition return a + b except Exception as e: logger.debug(f"safe_add failed: {e}") # Fallback for direction operations if direction is not None: try: if direction > 0: return a + b else: return a - b except Exception as e2: logger.debug(f"Fallback add/sub failed: {e2}") # Return the first operand as fallback return a def safe_divide(val: Any, divisor: Union[int, float, Fraction], integer_mode: bool = False) -> Any: try: # coerce divisor if isinstance(divisor, Fraction): pass elif isinstance(divisor, float) and integer_mode: # if divisor is near-integer, use int if math.isclose(divisor, round(divisor), abs_tol=1e-12): divisor_int = int(round(divisor)) return val // divisor_int if hasattr(val, "__floordiv__") else type(val)(int(val) // divisor_int) else: # integer_mode requested but divisor not integer-like -> fallback to true division integer_mode = False if integer_mode: if hasattr(val, "__floordiv__"): return val // int(divisor) # iterable fallback... else: if hasattr(val, "__truediv__"): return val / divisor # iterable fallback... except Exception: raise def format_fraction(frac: Any) -> Any: #Format fractions for output. #Args: # frac: Value to format #Returns: # Formatted value if isinstance(frac, Fraction): if frac.denominator == 1: return int(frac.numerator) return frac return frac # Alias for backward compatibility _safe_divide = safe_divide # Helper function for fraction formatting def format_fraction_local(f: Fraction) -> str: #Format a Fraction for display. if f.denominator == 1: return str(f.numerator) else: return f"{f.numerator}/{f.denominator}" def get_parser(kececi_type: int) -> Callable[[Any], Any]: #Parser fonksiyonunu döndürür - test beklentilerine uygun. parsers = { # Basit Python tipleri (test beklentileri) TYPE_POSITIVE_REAL: lambda s: int(_parse_fraction(s)), # int TYPE_NEGATIVE_REAL: lambda s: int(-_parse_fraction(s)), # int TYPE_FLOAT: lambda s: float(_parse_fraction(s)), # float TYPE_RATIONAL: lambda s: Fraction.from_float( _parse_fraction(s) ), # Fraction TYPE_COMPLEX: lambda s: complex(s), # built-in complex # Kececi özel tipler (import edilen parser'lar) TYPE_QUATERNION: _parse_quaternion, TYPE_NEUTROSOPHIC: _parse_neutrosophic, TYPE_NEUTROSOPHIC_COMPLEX: _parse_neutrosophic_complex, TYPE_HYPERREAL: _parse_hyperreal, TYPE_BICOMPLEX: _parse_bicomplex, TYPE_NEUTROSOPHIC_BICOMPLEX: _parse_neutrosophic_bicomplex, TYPE_OCTONION: _parse_octonion, TYPE_SEDENION: _parse_sedenion, TYPE_CLIFFORD: _parse_clifford, TYPE_DUAL: _parse_dual, TYPE_SPLIT_COMPLEX: _parse_splitcomplex, TYPE_PATHION: _parse_pathion, TYPE_CHINGON: _parse_chingon, TYPE_ROUTON: _parse_routon, TYPE_VOUDON: _parse_voudon, TYPE_SUPERREAL: _parse_super_real, TYPE_TERNARY: _parse_ternary, TYPE_HYPERCOMPLEX: _parse_hypercomplex, } parser = parsers.get(kececi_type) if parser is None: raise ValueError(f"Unsupported kececi_type: {kececi_type}") return parser # Tip eşleme sözlüğü (kececi_type -> sınıf adı) type_class_map = { 6: 'QuaternionNumber', 7: 'NeutrosophicNumber', 8: 'NeutrosophicComplexNumber', 10: 'BicomplexNumber', 11: 'NeutrosophicBicomplexNumber', 12: 'OctonionNumber', 13: 'SedenionNumber', 14: 'CliffordNumber', 15: 'DualNumber', 16: 'SplitcomplexNumber', 17: 'PathionNumber', 18: 'ChingonNumber', 19: 'RoutonNumber', 20: 'VoudonNumber', 21: 'SuperrealNumber', 22: 'TernaryNumber', 23: 'HypercomplexNumber' } def flatten_deep(lst): result = [] for item in lst: if isinstance(item, (list, tuple)): result.extend(flatten_deep(item)) else: result.append(item) return result def convert_to_obj(val, typ): if typ == 22: # Ternary flat = flatten_deep(val) if isinstance(val, (list, tuple)) else [val] return TernaryNumber(*flat) if isinstance(val, (int, float, complex)): return val if isinstance(val, (list, tuple)): flat = flatten_deep(val) class_name = type_class_map.get(typ) if class_name and class_name in globals(): cls = globals()[class_name] try: return cls(*flat) except TypeError: return cls(flat) return flat[0] if flat else 0 return val # NeutrosophicBicomplexNumber için element-wise çarpım (geçici) def _patch_neutrosophic_bicomplex_mul(): if 'NeutrosophicBicomplexNumber' in globals(): cls = globals()['NeutrosophicBicomplexNumber'] def fixed_mul(self, other): if isinstance(other, (int, float)): return cls(*(c * other for c in self.coeffs)) elif isinstance(other, cls): # Element-wise product (geçici) return cls(*(self.coeffs[i] * other.coeffs[i] for i in range(8))) return NotImplemented cls.__mul__ = fixed_mul cls.__rmul__ = fixed_mul # Patch uygula (modül yüklendikten sonra) _patch_neutrosophic_bicomplex_mul() #ask_unit kullanmadan doğrudan dizi üretimi. parser = get_parser(kececi_type) start_raw = parser(start_input_raw) add_raw = parser(add_input_raw) start_val = convert_to_obj(start_raw, kececi_type) add_val = convert_to_obj(add_raw, kececi_type) # Hata kontrolü: eğer hala liste ise dönüştürülememiş demektir if isinstance(start_val, (list, tuple)) or isinstance(add_val, (list, tuple)): raise TypeError(f"Cannot convert to number object: start={start_val}, add={add_val}") sequence = [start_val] current = start_val divisor = first_divisor for i in range(iterations - 1): if i == 0 and ask_plus_first: try: current = current + add_val except Exception as e: logger.error(f"Addition failed at step {i}: {e}") raise else: divisible = False try: # Bölünebilirlik kontrolü remainder = current % divisor if hasattr(remainder, 'real'): divisible = abs(remainder.real) < 1e-12 else: divisible = abs(remainder) < 1e-12 except Exception: divisible = False if divisible: try: current = current / divisor except Exception as e: logger.error(f"Division failed at step {i}: {e}") raise else: try: current = current * add_val except TypeError: # Çarpma hatası varsa, element-wise çarpma dene (sadece aynı tipte) if hasattr(current, 'a') and hasattr(add_val, 'a'): # NeutrosophicBicomplexNumber için current = type(current)( current.a * add_val.a, current.b * add_val.b, current.c * add_val.c, current.d * add_val.d, current.e * add_val.e, current.f * add_val.f, current.g * add_val.g, current.h * add_val.h ) else: raise sequence.append(current) divisor += 1 if not ask_plus_first else (1 if i > 0 else 0) if include_intermediate_steps: return sequence else: return [sequence[-1]] type_names = [ "Positive Real", "Negative Real", "Complex", "Float", "Rational", "Quaternion", "Neutrosophic", "Neutrosophic Complex", "Hyperreal", "Bicomplex", "Neutrosophic Bicomplex", "Octonion", "Sedenion", "Clifford", "Dual", "Split-Complex", "Pathion", "Chingon", "Routon", "Voudon", "Super Real", "Ternary", "Hypercomplex" ] # 1. Parse işlemi (mevcut get_parser'ınızı kullanın) parser_func = get_parser(kececi_type) start = parser_func(start_input_raw) add_val = parser_func(add_input_raw) def make_unit(start): cls = type(start) if cls is dict: return {'': 1.0} if cls is tuple: return cls((1,1,1)) if cls is list: return cls([1,1,1]) if issubclass(cls, (int, float, complex)): return cls(1) if hasattr(cls, '__init__'): init = cls.__init__ if hasattr(init, '__code__'): total_args = init.__code__.co_argcount expected = total_args - 1 if expected == 0: return cls() elif expected == 1: return cls(1) elif expected == 2: return cls(1, 1) elif expected == 3: return cls(1, 1, 1) elif expected == 4: return cls(1, 1, 1, 1) elif expected == 8: return cls(1, 1, 1, 1, 1, 1, 1, 1) else: return cls(*([1] * expected)) else: if cls in (int, float, complex, str, bool): return cls(1) elif cls in (tuple, list): return cls([1]) else: return cls() return cls(1) # Kullanım ask_unit = make_unit(start) # 2. Tip-specific yardımcı fonksiyonlar (1-23 tamamı) # (Bu kısmı daha önce verdiğim uzun kodun tamamıdır – sadece attribute isimlerini sizin sınıflarınıza göre güncellemelisiniz) if kececi_type in (1, 2, 4, 5): # Positive, Negative, Float, Rational def add(a, b): return a + b def is_divisible(val, d): if isinstance(val, (int, float)): return math.isclose(val % d, 0) or math.isclose(val % d, d) else: return math.isclose(float(val) % d, 0) or math.isclose(float(val) % d, d) def divide(val, d): if kececi_type in (1, 2): return int(val // d) else: return val / d def is_prime_like(val): v = int(round(val)) return v > 1 and isprime(v) ask_unit = 1.0 if kececi_type in (1,4,5) else -1.0 elif kececi_type == 3: # Complex def add(a, b): return a + b def is_divisible(val, d): return math.isclose(val.real % d, 0) def divide(val, d): return complex(val.real / d, val.imag / d) def is_prime_like(val): v = int(round(val.real)) return v > 1 and isprime(v) ask_unit = complex(1, 0) elif kececi_type == 6: # Quaternion def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'w'): return math.isclose(val.w % d, 0) return False def divide(val, d): if hasattr(val, '__truediv__'): return val / d # Skaler bölme (varsayılan) return type(val)(val.w/d, val.x/d, val.y/d, val.z/d) def is_prime_like(val): v = int(round(val.w)) return v > 1 and isprime(v) # Birim quaternion oluştur (w=1, x=y=z=0) if hasattr(start, 'w'): # eğer start bir quaternion nesnesiyse ask_unit = type(start)(1, 0, 0, 0) else: ask_unit = make_unit(start) # aşağıda tanımlanan make_unit kullan elif kececi_type == 7: # Neutrosophic def add(a, b): return a + b def is_divisible(val, d): # Neutrosophic sayı (T, I, F) tuple veya özel sınıf olabilir if isinstance(val, tuple) and len(val) >= 1: return math.isclose(val[0] % d, 0) elif hasattr(val, 't'): return math.isclose(val.t % d, 0) return False def divide(val, d): if isinstance(val, tuple): return tuple(x/d for x in val) elif hasattr(val, 't'): return type(val)(val.t/d, val.i/d, val.f/d) return val def is_prime_like(val): try: # İlk bileşeni al (T) if isinstance(val, tuple) and len(val) >= 1: comp = val[0] elif hasattr(val, 't'): comp = val.t else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False ask_unit = make_unit(start) elif kececi_type == 8: # Neutrosophic Complex def add(a, b): return a + b def is_divisible(val, d): if isinstance(val, tuple) and len(val) >= 2: return math.isclose(val[0] % d, 0) elif hasattr(val, 'real'): return math.isclose(val.real % d, 0) return False def divide(val, d): if isinstance(val, tuple): return tuple(x/d for x in val) else: return type(val)(val.real/d, val.imag/d, getattr(val, 'indeterminacy', 0)/d) def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'real'): comp = val.real else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False ask_unit = make_unit(start) elif kececi_type == 9: # Hyperreal def add(a, b): return a + b def is_divisible(val, d): if isinstance(val, tuple) and len(val) >= 1: return math.isclose(val[0] % d, 0) elif hasattr(val, 'finite'): return math.isclose(val.finite % d, 0) return False def divide(val, d): if isinstance(val, tuple): return tuple(x/d for x in val) else: return type(val)(val.finite/d, val.infinitesimal/d) def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'finite'): comp = val.finite else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False #ask_unit = make_unit(start) if isinstance(start, (int, float)): ask_unit = type(start)(1) else: ask_unit = make_unit(start) elif kececi_type == 10: # Bicomplex def add(a, b): return a + b def is_divisible(val, d): # Sınıfınızın ilk bileşenine erişim: .a, .e1, .components[0] vs. if hasattr(val, 'a'): return math.isclose(val.a.real % d, 0) elif hasattr(val, 'components'): return math.isclose(val.components[0].real % d, 0) return False def divide(val, d): if hasattr(val, 'a'): return type(val)(val.a/d, val.b/d) elif hasattr(val, 'components'): return type(val)([c/d for c in val.components]) def is_prime_like(val): if hasattr(val, 'a'): v = int(round(val.a.real)) elif hasattr(val, 'components'): v = int(round(val.components[0].real)) else: return False return v > 1 and isprime(v) ask_unit = type(start)(1+1j, 1+1j) elif kececi_type == 11: # Neutrosophic Bicomplex def add(a, b): return a + b def is_divisible(val, d): # İlk reel kısım – sınıfınıza göre değişebilir if hasattr(val, 'real'): return math.isclose(val.real % d, 0) else: return False def divide(val, d): # 8 bileşenli vektör olduğunu varsayalım return type(val)(val.real/d, val.imag/d, getattr(val, 'ind1',0)/d, getattr(val, 'ind2',0)/d, getattr(val, 'ind3',0)/d, getattr(val, 'ind4',0)/d, getattr(val, 'ind5',0)/d, getattr(val, 'ind6',0)/d) def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'real'): comp = val.real else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False ask_unit = make_unit(start) # Octonion, Sedenion, Pathion, Chingon, Routon, Voudon, Hypercomplex # Hepsi vektör tabanlı (components listesi) elif kececi_type in (12, 13, 17, 18, 19, 20, 23): def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'components'): comps = val.components() if callable(val.components) else val.components if comps and len(comps) > 0: return math.isclose(comps[0] % d, 0) elif hasattr(val, 'scalar'): scalar = val.scalar() if callable(val.scalar) else val.scalar return math.isclose(scalar % d, 0) return False def divide(val, d): if hasattr(val, 'components'): comps = val.components() if callable(val.components) else val.components if isinstance(comps, (list, tuple)): new_comps = [c / d for c in comps] # Sınıfın __init__'i *args mı yoksa tek liste mi bekliyor? try: return type(val)(*new_comps) # önce yıldızlı dene except TypeError: return type(val)(new_comps) # yoksa liste olarak ver else: return val elif hasattr(val, 'scalar'): scalar = val.scalar() if callable(val.scalar) else val.scalar return type(val)(scalar/d, getattr(val, 'vector', [0])[0]/d) return val def is_prime_like(val): try: if hasattr(val, 'components'): comps = val.components() if callable(val.components) else val.components first = comps[0] if comps else 0 v = int(round(float(first))) elif hasattr(val, 'scalar'): scalar = val.scalar() if callable(val.scalar) else val.scalar v = int(round(float(scalar))) else: return False return v > 1 and isprime(v) except: return False # Birim eleman oluştur if hasattr(start, 'components'): comps = start.components() if callable(start.components) else start.components dim = len(comps) unit_comps = [1.0] + [0.0]*(dim-1) try: ask_unit = type(start)(*unit_comps) except TypeError: ask_unit = type(start)(unit_comps) else: ask_unit = make_unit(start) elif kececi_type == 14: # Clifford def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'basis'): scalar = val.basis.get('', 0) return math.isclose(scalar % d, 0) return False def divide(val, d): new_basis = {k: v/d for k, v in val.basis.items()} return type(val)(new_basis) def is_prime_like(val): scalar = val.basis.get('', 0) v = int(round(scalar)) return v > 1 and isprime(v) ask_unit = type(start)({"": 1.0}) elif kececi_type in (15, 16): # Dual, Split-Complex def add(a, b): return a + b def is_divisible(val, d): return hasattr(val, 'real') and math.isclose(val.real % d, 0) def divide(val, d): if hasattr(val, 'dual'): return type(val)(val.real/d, val.dual/d) else: return type(val)(val.real/d, val.imag/d) def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'real'): comp = val.real else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False ask_unit = make_unit(start) elif kececi_type == 21: # Super Real def add(a, b): return a + b def is_divisible(val, d): return hasattr(val, 'finite') and math.isclose(val.finite % d, 0) def divide(val, d): return type(val)(val.finite/d, val.infinitesimal/d) def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'finite'): comp = val.finite else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False #ask_unit = make_unit(start) if isinstance(start, (int, float)): ask_unit = type(start)(1) else: ask_unit = make_unit(start) elif kececi_type == 22: # Ternary def add(a, b): return a + b def is_divisible(val, d): if hasattr(val, 'to_int'): return val.to_int() % d == 0 # Eğer val liste ise if isinstance(val, (list, tuple)): if len(val) == 0: return False val = val[0] # ilk bileşeni al try: return int(val) % d == 0 except: return False def divide(val, d): if hasattr(val, 'divide_by'): return val.divide_by(d) # Eğer val liste ise, her elemanı böl if isinstance(val, (list, tuple)): return type(val)([int(x)//d if isinstance(x, (int, float)) else x for x in val]) # Tekil değer try: return type(val)(int(val)//d) except: return val def is_prime_like(val): try: if isinstance(val, tuple): comp = val[0] elif hasattr(val, 'to_int'): comp = val.to_int() else: return False v = int(round(float(comp))) return v > 1 and isprime(v) except: return False #ask_unit = make_unit(start) if isinstance(start, (int, float)): ask_unit = type(start)(1) else: ask_unit = make_unit(start) else: # Fallback (sadece toplama) def add(a, b): return a + b is_divisible = lambda val, d: False divide = lambda val, d: val is_prime_like = lambda val: False ask_unit = 1 # 3. ASK algoritması (genel) result = [] current = start ask_counter = 0 primary = first_divisor secondary = 2 if primary == 3 else 3 if include_intermediate_steps: result.append({"step": 0, "value": current, "operation": "start"}) for i in range(1, iterations + 1): added = add(current, add_val) if include_intermediate_steps: result.append({"step": i, "value": added, "operation": "add"}) else: result.append(added) current = added next_val = added divided = False for divisor in (primary, secondary): if is_divisible(added, divisor): divided_val = divide(added, divisor) if include_intermediate_steps: result.append({"step": i, "value": divided_val, "operation": f"div_{divisor}"}) next_val = divided_val divided = True if divisor == primary: primary, secondary = secondary, primary break if not divided and is_prime_like(added): if ask_plus_first: delta = 1 if ask_counter == 0 else -1 else: delta = -1 if ask_counter == 0 else 1 adjusted = add(added, delta * ask_unit) if include_intermediate_steps: result.append({"step": i, "value": adjusted, "operation": "ask"}) ask_counter = 1 - ask_counter ask_divided = False for divisor in (primary, secondary): if is_divisible(adjusted, divisor): final_val = divide(adjusted, divisor) if include_intermediate_steps: result.append({"step": i, "value": final_val, "operation": f"ask_div_{divisor}"}) next_val = final_val ask_divided = True if divisor == primary: primary, secondary = secondary, primary break if not ask_divided: next_val = adjusted current = next_val if not include_intermediate_steps: result.append(current) return result """ """ def unified_generator( kececi_type: int, start_input_raw: str, add_input_raw: str, iterations: int, include_intermediate_steps: bool = True, first_divisor: int = 3, ask_plus_first: bool = True ) -> List[Any]: ASK algoritması – Keçeci dizisi üretir (tüm tipler 1-23). include_intermediate_steps=True -> her işlem sözlük (value, operation, description) include_intermediate_steps=False -> sadece nihai değerler (düz liste) first_divisor: 3 veya 2 – ilk denenmesi gereken bölen ask_plus_first: True -> +1,-1,+1,... ; False -> -1,+1,-1,... # -------------------- 1. TİP AYRIŞTIRMA -------------------- # Bu kısım mevcut kodunuzdaki parser mantığını kullanmalıdır. # Aşağıda özet olarak gösterilmiştir. Gerçek implementasyonda # sizin _parse_... fonksiyonlarınızı çağırın. def _parse_value(raw: str, typ: int) -> Any: if typ == TYPE_POSITIVE_REAL: return abs(float(raw)) if typ == TYPE_NEGATIVE_REAL: return -abs(float(raw)) if typ == TYPE_FLOAT: return float(raw) if typ == TYPE_RATIONAL: return Fraction(raw) if typ == TYPE_COMPLEX: return complex(raw) # Diğer tipler için mevcut parser'larınızı kullanın # (kısaltmak için burada sadece temel tipleri yazıyorum) return float(raw) # fallback start_value = _parse_value(start_input_raw, kececi_type) add_value = _parse_value(add_input_raw, kececi_type) ask_unit = _get_ask_unit_for_type(kececi_type, start_value) # -------------------- 2. DÖNGÜ -------------------- result = [] current = start_value ask_counter = 0 # 0: ilk yön, 1: ikinci yön primary = first_divisor secondary = 2 if primary == 3 else 3 last_divisor_used = None # opsiyonel if include_intermediate_steps: result.append({ "step": 0, "value": current, "operation": "start", "description": f"Start: {current}" }) for i in range(1, iterations + 1): # 1. Toplama added = current + add_value if include_intermediate_steps: result.append({ "step": i, "value": added, "operation": "add", "description": f"Add {add_value}: {current} + {add_value} = {added}" }) next_val = added divided = False # 2. Bölme – önce primary, sonra secondary for divisor in (primary, secondary): if _is_divisible(added, divisor, kececi_type): divided_val = _safe_divide(added, divisor, kececi_type) if include_intermediate_steps: result.append({ "step": i, "value": divided_val, "operation": f"divide by {divisor}", "description": f"Divide by {divisor}: {added} / {divisor} = {divided_val}" }) next_val = divided_val divided = True if divisor == primary: primary, secondary = secondary, primary break # 3. ASK (bölünmedi ve asal) if not divided and _is_prime_like(added, kececi_type): # Yön belirleme if ask_plus_first: delta = 1 if ask_counter == 0 else -1 else: delta = -1 if ask_counter == 0 else 1 adjusted = added + delta * ask_unit if include_intermediate_steps: op_desc = f"+{ask_unit}" if delta > 0 else f"-{ask_unit}" result.append({ "step": i, "value": adjusted, "operation": "keçeci unit", "description": f"Apply Keçeci unit {op_desc}: {added} {op_desc} = {adjusted}" }) ask_counter = 1 - ask_counter # ASK sonrası bölme dene (aynı sıra) ask_divided = False for divisor in (primary, secondary): if _is_divisible(adjusted, divisor, kececi_type): final_val = _safe_divide(adjusted, divisor, kececi_type) if include_intermediate_steps: result.append({ "step": i, "value": final_val, "operation": f"divide by {divisor}", "description": f"Divide adjusted by {divisor}: {adjusted} / {divisor} = {final_val}" }) next_val = final_val ask_divided = True if divisor == primary: primary, secondary = secondary, primary break if not ask_divided: next_val = adjusted # 4. Güncelleme current = next_val if not include_intermediate_steps: result.append(current) return result """ def _parse_quaternion_fixed(s: str): """ Fixed quaternion parser that handles single numbers correctly. """ from .kececinumbers import _parse_fraction, quaternion s_str = str(s).strip() # Handle empty string if not s_str: return quaternion(0, 0, 0, 0) # Handle comma-separated format: "w,x,y,z" or "w, x, y, z" if "," in s_str: parts = [p.strip() for p in s_str.split(",")] if len(parts) == 4: try: w = _parse_fraction(parts[0]) x = _parse_fraction(parts[1]) y = _parse_fraction(parts[2]) z = _parse_fraction(parts[3]) return quaternion(w, x, y, z) except: pass # Handle single number - only w component, others 0 try: w = _parse_fraction(s_str) return quaternion(w, 0, 0, 0) except: # Try as float try: w = float(s_str) return quaternion(w, 0, 0, 0) except: return quaternion(0, 0, 0, 0) def _parse_neutrosophic_fixed(s: str): """Fixed neutrosophic parser.""" from .kececinumbers import NeutrosophicNumber, _parse_neutrosophic try: return _parse_neutrosophic(s) except: # Fallback from .kececinumbers import _parse_fraction try: val = _parse_fraction(s) return NeutrosophicNumber(val, 0.0, 0.0) except: return NeutrosophicNumber(0.0, 0.0, 0.0) def _parse_octonion_fixed(s: str): """Fixed octonion parser.""" from .kececinumbers import OctonionNumber, _parse_octonion try: return _parse_octonion(s) except: # Fallback from .kececinumbers import _parse_fraction try: val = _parse_fraction(s) return OctonionNumber(val, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) except: return OctonionNumber(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) # Similar fixed parsers for other types... def _parse_sedenion_fixed(s: str): from .kececinumbers import SedenionNumber, _parse_fraction, _parse_sedenion try: return _parse_sedenion(s) except: try: val = _parse_fraction(s) components = [val] + [0.0] * 15 return SedenionNumber(components) except: return SedenionNumber([0.0] * 16) def _parse_ternary(s: Any) -> Any: """TernaryNumber hatasız""" try: if isinstance(s, (int, float, Fraction)): try: from kececinumbers import TernaryNumber return TernaryNumber(float(s), 0.0, 0.0) except: return [float(s), 0.0, 0.0] return [float(s), 0.0, 0.0] except: return [0.0, 0.0, 0.0] def _generate_proper_ask_sequence( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Proper ASK sequence that extracts values for plotting. """ result = [] current = start_value ask_counter = 0 # Helper to extract plot value def extract_plot_value(val): """Extract a plottable value from any Keçeci number type.""" try: # For quaternions, use w component or norm if ( hasattr(val, "w") and hasattr(val, "x") and hasattr(val, "y") and hasattr(val, "z") ): return float(val.w) # Use real part # For octonions elif hasattr(val, "__len__") and len(val) >= 8: return float(val[0]) if val else 0.0 # For sedenions elif hasattr(val, "__len__") and len(val) >= 16: return float(val[0]) if val else 0.0 # For complex elif isinstance(val, complex): return float(val.real) # For tuples (neutrosophic, etc.) elif isinstance(val, tuple) and len(val) >= 1: return float(val[0]) # For lists elif isinstance(val, list) and val: return float(val[0]) # For custom objects with real attribute elif hasattr(val, "real"): return float(val.real) # For custom objects with value attribute elif hasattr(val, "value"): return float(val.value) # For everything else, try to convert to float else: return float(val) except: return 0.0 if include_intermediate_steps: plot_val = extract_plot_value(current) result.append( { "step": 0, "value": current, "plot_value": plot_val, "operation": "start", "description": f"Start: {current}", } ) else: result.append(extract_plot_value(current)) for i in range(1, iterations): try: # 1. ADD added = current + add_value next_val = added divided = False # 2. Check division by 2 or 3 for divisor in [2, 3]: try: # For quaternions, check norm for divisibility if number_type == 6: # Quaternion if hasattr(added, "norm"): norm = added.norm() if norm % divisor == 0: next_val = added / divisor divided = True break else: # Try division anyway next_val = added / divisor divided = True break else: # For other types, try division next_val = added / divisor divided = True break except Exception as e: logger.debug(f"Division by {divisor} failed: {e}") continue # 3. Keçeci unit adjustment if not divided: # Check if prime-like is_prime_like = False try: if number_type == 6: # Quaternion if hasattr(added, "norm"): norm = added.norm() is_prime_like = _is_prime_int(int(norm)) else: # Try to extract a numeric value val = extract_plot_value(added) is_prime_like = _is_prime_int(int(abs(val))) except: is_prime_like = False if is_prime_like: # Get appropriate unit unit = _get_proper_unit(number_type, current) if ask_counter == 0: adjusted = added + unit else: adjusted = added - unit ask_counter = 1 - ask_counter # Try division on adjusted value for divisor in [2, 3]: try: next_val = adjusted / divisor break except: continue else: next_val = adjusted current = next_val if include_intermediate_steps: plot_val = extract_plot_value(current) result.append( { "step": i, "value": current, "plot_value": plot_val, "operation": "step", "description": f"Step {i}: {current}", } ) else: result.append(extract_plot_value(current)) except Exception as e: logger.error(f"Error at iteration {i}: {e}") default_val = _get_proper_default(number_type) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "plot_value": extract_plot_value(default_val), "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(extract_plot_value(default_val)) current = default_val return result def _is_prime_int(n: int) -> bool: """Check if integer is prime.""" if n < 2: return False if n == 2 or n == 3: return True if n % 2 == 0 or n % 3 == 0: return False i = 5 while i * i <= n: if n % i == 0 or n % (i + 2) == 0: return False i += 6 return True def _get_proper_unit(number_type: int, sample=None): """Get proper unit for number type.""" # helper to determine dimension from sample or default def _dim_from_sample(s, default=4): if s is None: return default # if sample is list/tuple-like, use its length try: if isinstance(s, (list, tuple)): return max(1, len(s)) # if sample is an object with .components or similar, try to infer if hasattr(s, "__len__"): return max(1, len(s)) except Exception: pass return default if number_type == 1: # Positive Real return 1.0 elif number_type == 2: # Negative Real return -1.0 elif number_type == 3: # Complex return complex(1, 0) elif number_type == 4: # Float return 1.0 elif number_type == 5: # Rational try: from fractions import Fraction return Fraction(1, 1) except Exception: return 1.0 elif number_type == 6: # Quaternion from .kececinumbers import quaternion return quaternion(1, 0, 0, 0) elif number_type == 7: # Neutrosophic from .kececinumbers import NeutrosophicNumber return NeutrosophicNumber(1.0, 0.0, 0.0) elif number_type == 12: # Octonion from .kececinumbers import OctonionNumber return OctonionNumber(1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) elif number_type == 13: # Sedenion from .kececinumbers import SedenionNumber return SedenionNumber([1.0] + [0.0] * 15) elif number_type == 22: # Ternary from .kececinumbers import TernaryNumber return TernaryNumber([1]) elif number_type == 23: # Hypercomplex # infer dimension from sample if provided, default to 4 dim = _dim_from_sample(sample, default=4) try: from .kececinumbers import HypercomplexNumber comps = [1.0] + [0.0] * (dim - 1) # assume HypercomplexNumber accepts a list of components return HypercomplexNumber(comps) except Exception: # fallback to plain list if class not available return [1.0] + [0.0] * dim else: return 1.0 def _get_proper_default(number_type: int, sample=None): """Get proper default for number type.""" # helper to determine dimension from sample or default def _dim_from_sample(s, default=4): if s is None: return default try: if isinstance(s, (list, tuple)): return max(1, len(s)) if hasattr(s, "__len__"): return max(1, len(s)) except Exception: pass return default if number_type == 1: # Positive Real return 0.0 elif number_type == 2: # Negative Real return 0.0 elif number_type == 3: # Complex return complex(0, 0) elif number_type == 4: # Float return 0.0 elif number_type == 5: # Rational try: from fractions import Fraction return Fraction(0, 1) except Exception: return 0.0 elif number_type == 6: # Quaternion from .kececinumbers import quaternion return quaternion(0, 0, 0, 0) elif number_type == 7: # Neutrosophic from .kececinumbers import NeutrosophicNumber return NeutrosophicNumber(0.0, 0.0, 0.0) elif number_type == 12: # Octonion from .kececinumbers import OctonionNumber return OctonionNumber(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) elif number_type == 13: # Sedenion from .kececinumbers import SedenionNumber return SedenionNumber([0.0] * 16) elif number_type == 22: # Ternary from .kececinumbers import TernaryNumber return TernaryNumber([0]) elif number_type == 23: # Hypercomplex dim = _dim_from_sample(sample, default=4) try: from .kececinumbers import HypercomplexNumber comps = [0.0] * dim return HypercomplexNumber(comps) except Exception: return [0.0] * dim else: return 0.0 def _generate_fallback_sequence( kececi_type: int, start_input_raw: str, add_input_raw: str, iterations: int, include_intermediate_steps: bool = True, operation: str = "ask", ) -> List[Any]: """ Fallback sequence generator when main generator fails. """ # Simple float parser def parse_float(val): try: return float(val) except: return 0.0 start_val = parse_float(start_input_raw) add_val = parse_float(add_input_raw) result = [] current = start_val if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: if operation == "ask": # Simple ASK for floats added = current + add_val next_val = added # Check division for divisor in [2, 3]: if added % divisor == 0: next_val = added / divisor break # Prime check and unit adjustment if next_val == added: # Not divided if _is_prime_int(int(abs(added))): unit = 1.0 # Simple unit adjustment adjusted = added + unit if i % 2 == 0 else added - unit # Try division again for divisor in [2, 3]: if adjusted % divisor == 0: next_val = adjusted / divisor break else: next_val = adjusted current = next_val else: # Simple operations if operation == "add": current = current + add_val elif operation == "subtract": current = current - add_val elif operation == "multiply": current = current * add_val elif operation == "divide": current = current / add_val if add_val != 0 else float("inf") elif operation == "mod": current = current % add_val if add_val != 0 else current elif operation == "power": current = current**add_val else: current = current + add_val if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": operation if operation != "ask" else "step", "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} in fallback: {e}") if include_intermediate_steps: result.append( { "step": i, "value": 0.0, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(0.0) current = 0.0 return result def _unified_generator_fallback( kececi_type: int, start_input_raw: str, add_input_raw: str, iterations: int, include_intermediate_steps: bool = True, operation: str = "ask", ) -> List[Any]: """ Fallback generator when imports fail. """ # Simple parser def parse_simple(val: str) -> float: if not val: return 0.0 val_str = str(val).strip() # Try complex val_str = val_str.replace("i", "j").replace("J", "j") try: c = complex(val_str) return float(c.real) except: pass # Try float try: return float(val_str) except: # Try fraction if "/" in val_str: try: num, den = val_str.split("/") return float(num) / float(den) except: pass # Try mixed number if " " in val_str and "/" in val_str: try: whole, frac = val_str.split(" ", 1) num, den = frac.split("/") return float(whole) + (float(num) / float(den)) except: pass return 0.0 # Parse values start_base = parse_simple(start_input_raw) add_base = parse_simple(add_input_raw) # Adjust based on type if kececi_type == 1: # Positive Real start_value = abs(start_base) add_value = abs(add_base) elif kececi_type == 2: # Negative Real start_value = -abs(start_base) add_value = -abs(add_base) elif kececi_type == 3: # Complex start_value = complex(start_base, 0) add_value = complex(add_base, 0) elif kececi_type in [4, 5]: # Float, Rational start_value = start_base add_value = add_base else: # For other types, use float as fallback start_value = start_base add_value = add_base # Generate simple sequence return _generate_simple_sequence_direct( start_value=start_value, add_value=add_value, iterations=iterations, include_intermediate_steps=include_intermediate_steps, number_type=kececi_type, ) def _generate_ask_sequence_direct( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Direct ASK sequence generation. """ result = [] current = start_value ask_counter = 0 if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: # 1. ADD added = current + add_value next_val = added divided = False # 2. Check division by 2 or 3 for divisor in [2, 3]: try: # Try to check divisibility if _check_divisible_simple(added, divisor): # Try to divide next_val = _divide_simple(added, divisor) divided = True logger.debug( f"Step {i}: Divided {added} by {divisor} = {next_val}" ) break except Exception as e: logger.debug(f"Division failed: {e}") continue # 3. Keçeci unit adjustment if not divided and _check_prime_like_simple(added): unit = _get_unit_for_type_simple(number_type) if ask_counter == 0: adjusted = added + unit logger.debug(f"Step {i}: Added unit {unit} to {added} = {adjusted}") else: adjusted = added - unit logger.debug( f"Step {i}: Subtracted unit {unit} from {added} = {adjusted}" ) ask_counter = 1 - ask_counter # Try division on adjusted value for divisor in [2, 3]: try: if _check_divisible_simple(adjusted, divisor): next_val = _divide_simple(adjusted, divisor) logger.debug( f"Step {i}: Divided adjusted {adjusted} by {divisor} = {next_val}" ) break except Exception: continue else: next_val = adjusted current = next_val if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": "step", "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i}: {e}") default_val = _get_default_for_type_simple(number_type) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _generate_operation_sequence_direct( start_value: Any, add_value: Any, iterations: int, operation: str, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Direct operation sequence generation. """ result = [] current = start_value if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: if operation == "add": current = current + add_value elif operation == "subtract": current = current - add_value elif operation == "multiply": current = current * add_value elif operation == "divide": current = _divide_simple(current, add_value) elif operation == "mod": try: current = current % add_value except: current = current # Mod not supported elif operation == "power": try: current = current**add_value except: current = current # Power not supported else: current = current + add_value # Default to add if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": operation, "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i}, operation {operation}: {e}") default_val = _get_default_for_type_simple(number_type) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _check_divisible_simple(value: Any, divisor: float) -> bool: """ Simple divisibility check. """ try: if isinstance(value, (int, float)): return abs(value % divisor) < 1e-12 elif isinstance(value, complex): return ( abs(value.real % divisor) < 1e-12 and abs(value.imag % divisor) < 1e-12 ) else: # For other types, assume divisible return True except: return True def _divide_simple(value: Any, divisor: float) -> Any: """ Simple division. """ try: return value / divisor except: # Try alternatives if isinstance(value, (tuple, list)): return type(value)([x / divisor for x in value]) else: raise def _check_prime_like_simple(value: Any) -> bool: """ Simple prime-like check. """ try: # Get a numeric value if isinstance(value, (int, float)): val = abs(value) elif isinstance(value, complex): val = abs(value) elif hasattr(value, "__abs__"): val = abs(value) else: return False # Simple prime check if val < 2: return False for i in range(2, int(val**0.5) + 1): if val % i == 0: return False return True except: return False def _get_unit_for_type_simple(number_type: int) -> Any: """ Get unit for number type. """ if number_type in [1, 4, 5]: return 1.0 elif number_type == 2: return -1.0 elif number_type == 3: return complex(1, 0) elif number_type == 6: # Quaternion try: from .kececinumbers import quaternion return quaternion(1, 0, 0, 0) except: return (1.0, 0.0, 0.0, 0.0) elif number_type == 7: # Neutrosophic return (1.0, 0.0, 0.0) else: return 1.0 def _get_default_for_type_simple(number_type: int) -> Any: """ Get default value for number type. """ if number_type in [1, 2, 4, 5]: return 0.0 elif number_type == 3: return complex(0, 0) elif number_type == 6: # Quaternion try: from .kececinumbers import quaternion return quaternion(0, 0, 0, 0) except: return (0.0, 0.0, 0.0, 0.0) elif number_type == 7: # Neutrosophic return (0.0, 0.0, 0.0) else: return 0.0 def _generate_simple_sequence_direct( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Simple sequence generation (just addition). """ result = [] current = start_value if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: current = current + add_value if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": "add", "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i}: {e}") default_val = _get_default_for_type_simple(number_type) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _generate_ternary_ask_sequence( start_value: "TernaryNumber", add_value: "TernaryNumber", iterations: int, include_intermediate_steps: bool = True, ) -> List[Any]: """ ASK algorithm for TernaryNumber. """ result = [] current = start_value ask_counter = 0 # 0: +unit, 1: -unit if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations + 1): # iterations kadar adım (1'den başla) try: # STEP 1: ADDITION added = current + add_value next_val = added divided = False # STEP 2: CHECK DIVISIBILITY by 2 or 3 added_decimal = added.to_decimal() for divisor in [2, 3]: if added_decimal % divisor == 0: divided_decimal = added_decimal // divisor divided_val = TernaryNumber.from_decimal(divided_decimal) next_val = divided_val divided = True break # STEP 3: KECEÇI UNIT ADJUSTMENT if not divided and prime-like if not divided and _is_prime_decimal(added_decimal): unit = TernaryNumber.from_decimal(1) if ask_counter == 0: adjusted = added + unit else: adjusted = ( added - unit ) # Burada negatif olabilir, hata yönetimi gerekli ask_counter = 1 - ask_counter # Try division again on adjusted value adjusted_decimal = adjusted.to_decimal() for divisor in [2, 3]: if adjusted_decimal % divisor == 0: final_decimal = adjusted_decimal // divisor next_val = TernaryNumber.from_decimal(final_decimal) break else: # No division successful after adjustment next_val = adjusted current = next_val if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": "step", "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} for Ternary: {e}") default_val = TernaryNumber.from_decimal(0) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result """ def _generate_ternary_ask_sequence( start_value: 'TernaryNumber', add_value: 'TernaryNumber', iterations: int, include_intermediate_steps: bool = True ) -> List[Any]: #ASK algorithm specifically for TernaryNumber. result = [] current = start_value ask_counter = 0 # 0: +unit, 1: -unit if include_intermediate_steps: result.append({ "step": 0, "value": current, "operation": "start", "description": f"Start: {current}" }) else: result.append(current) for i in range(1, iterations): try: # STEP 1: ADDITION added = current + add_value next_val = added divided = False # STEP 2: CHECK DIVISIBILITY by 2 or 3 # Convert to decimal for divisibility checks added_decimal = added.to_decimal() for divisor in [2, 3]: try: if added_decimal % divisor == 0: # Divide in decimal, convert back to ternary divided_decimal = added_decimal // divisor divided_val = TernaryNumber.from_decimal(divided_decimal) next_val = divided_val divided = True break except Exception: continue # STEP 3: KECEÇI UNIT ADJUSTMENT if not divided and prime-like if not divided: # Check if prime-like (check decimal value) if _is_prime_decimal(added_decimal): # Ternary unit is 1 in ternary = [1] unit = TernaryNumber.from_decimal(1) # Apply unit based on ask_counter if ask_counter == 0: adjusted = added + unit else: adjusted = added - unit # Toggle ask counter ask_counter = 1 - ask_counter # Try division again on adjusted value adjusted_decimal = adjusted.to_decimal() for divisor in [2, 3]: try: if adjusted_decimal % divisor == 0: final_decimal = adjusted_decimal // divisor next_val = TernaryNumber.from_decimal(final_decimal) break except Exception: continue else: # No division successful after adjustment next_val = adjusted current = next_val if include_intermediate_steps: result.append({ "step": i, "value": current, "operation": "step", "description": f"Step {i}: {current}" }) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} for Ternary: {e}") default_val = TernaryNumber.from_decimal(0) if include_intermediate_steps: result.append({ "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}" }) else: result.append(default_val) current = default_val return result """ def _generate_ternary_operation_sequence( start_value: "TernaryNumber", add_value: "TernaryNumber", iterations: int, operation: str, include_intermediate_steps: bool = True, ) -> List[Any]: """ Standard operations for TernaryNumber. """ result = [] current = start_value if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: if operation == "add": current = current + add_value elif operation == "subtract": current = current - add_value elif operation == "multiply": # Convert add_value to scalar if it's a single digit ternary if isinstance(add_value, TernaryNumber): add_decimal = add_value.to_decimal() current = current * add_decimal else: current = current * add_value elif operation == "divide": if isinstance(add_value, TernaryNumber): add_decimal = add_value.to_decimal() if add_decimal == 0: raise ZeroDivisionError("Division by zero") current_decimal = current.to_decimal() result_decimal = current_decimal // add_decimal current = TernaryNumber.from_decimal(result_decimal) else: if add_value == 0: raise ZeroDivisionError("Division by zero") current_decimal = current.to_decimal() result_decimal = current_decimal // add_value current = TernaryNumber.from_decimal(result_decimal) elif operation == "mod": # Mod operation for Ternary (convert to decimal) current_decimal = current.to_decimal() if isinstance(add_value, TernaryNumber): add_decimal = add_value.to_decimal() else: add_decimal = add_value if add_decimal == 0: raise ZeroDivisionError("Modulo by zero") result_decimal = current_decimal % add_decimal current = TernaryNumber.from_decimal(result_decimal) elif operation == "power": # Power operation (convert to decimal) current_decimal = current.to_decimal() if isinstance(add_value, TernaryNumber): add_decimal = add_value.to_decimal() else: add_decimal = add_value result_decimal = current_decimal**add_decimal current = TernaryNumber.from_decimal(result_decimal) else: current = current + add_value # Default to addition if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": operation, "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error( f"Error at iteration {i} for Ternary, operation {operation}: {e}" ) default_val = TernaryNumber.from_decimal(0) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result # kullanılmıyor def _generate_ask_sequence_proper( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ ASK algoritması – tüm türler için tek tip işlemlerle. Bölünebilirlik ve asallık kontrollerini robust_int üzerinden yapar. """ result = [] current = start_value ask_counter = 0 if include_intermediate_steps: result.append({"step": 0, "value": current, "operation": "start"}) else: result.append(current) # İhtiyaç duyulan birim ve varsayılan değerler (türe göre değişebilir) # Basitçe 1 ve 0 alalım; tür uyumsuzluğunda kütüphanenin __add__ overload'ları devreye girer. unit = 1 default_val = 0 for i in range(1, iterations): try: # 1. Topla added = current + add_value next_val = added divided = False # 2. 2 veya 3'e bölünebilir mi? (robust_int ile tamsayı değerine bakarak) int_val = robust_int(added) if int_val is not None and (int_val % 2 == 0 or int_val % 3 == 0): next_val = ( safe_divide(added, 2) if int_val % 2 == 0 else safe_divide(added, 3) ) divided = True else: # 3. Bölünemediyse ve asal ise Keçeci birim uygula if is_prime(added): adjusted = added + unit if ask_counter == 0 else added - unit ask_counter = 1 - ask_counter # adjusted'ın 2 veya 3'e bölünebilirliğini tekrar kontrol et adj_int = robust_int(adjusted) if adj_int is not None and (adj_int % 2 == 0 or adj_int % 3 == 0): next_val = ( safe_divide(adjusted, 2) if adj_int % 2 == 0 else safe_divide(adjusted, 3) ) else: next_val = adjusted current = next_val if include_intermediate_steps: result.append({"step": i, "value": current, "operation": "step"}) else: result.append(current) except Exception: # Hata durumunda varsayılan değere geç current = default_val if include_intermediate_steps: result.append({"step": i, "value": current, "operation": "error"}) else: result.append(current) return result """ #kullanılmıyor def _generate_ask_sequence_proper( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1 ) -> List[Any]: #Proper ASK algorithm that handles different number types correctly. # Get type-specific handler handler = _get_type_handler(number_type) result = [] current = start_value ask_counter = 0 if include_intermediate_steps: result.append({ "step": 0, "value": current, "operation": "start", "description": f"Start: {current}" }) else: result.append(current) for i in range(1, iterations): try: # Use handler for all operations added = handler["add"](current, add_value) next_val = added divided = False # Check divisibility for divisor in [2, 3]: if handler["is_divisible"](added, divisor): next_val = handler["divide"](added, divisor) divided = True break # Keçeci unit adjustment if not divided and handler["is_prime_like"](added): unit = handler["get_unit"]() if ask_counter == 0: adjusted = handler["add"](added, unit) else: adjusted = handler["subtract"](added, unit) ask_counter = 1 - ask_counter # Try division on adjusted value for divisor in [2, 3]: if handler["is_divisible"](adjusted, divisor): next_val = handler["divide"](adjusted, divisor) break else: next_val = adjusted current = next_val if include_intermediate_steps: result.append({ "step": i, "value": current, "operation": "step", "description": f"Step {i}: {current}" }) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} for type {number_type}: {e}") default_val = handler["get_default"]() if include_intermediate_steps: result.append({ "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}" }) else: result.append(default_val) current = default_val return result """ def _get_type_handler(number_type: int) -> Dict[str, Callable]: """ Get proper handler for each number type. """ # For simple numeric types (1-5) if number_type in [1, 2, 4, 5]: from .kececinumbers import _safe_divide def numeric_add(a, b): return a + b def numeric_subtract(a, b): return a - b def numeric_divide(a, b): return _safe_divide(a, b) def numeric_is_divisible(a, divisor): try: if hasattr(a, "__mod__"): remainder = a % divisor return abs(remainder) < 1e-12 return True except: return False def numeric_is_prime_like(a): try: val = abs(float(a)) if val < 2: return False for i in range(2, int(val**0.5) + 1): if val % i == 0: return False return True except: return False def numeric_get_unit(): return 1.0 if number_type != 2 else -1.0 def numeric_get_default(): return 0.0 return { "add": numeric_add, "subtract": numeric_subtract, "divide": numeric_divide, "is_divisible": numeric_is_divisible, "is_prime_like": numeric_is_prime_like, "get_unit": numeric_get_unit, "get_default": numeric_get_default, } # For Complex (3) elif number_type == 3: def complex_add(a, b): return a + b def complex_subtract(a, b): return a - b def complex_divide(a, b): try: return a / b except ZeroDivisionError: return complex(float("inf"), 0) def complex_is_divisible(a, divisor): # Check both real and imaginary parts try: return abs(a.real % divisor) < 1e-12 and abs(a.imag % divisor) < 1e-12 except: return False def complex_is_prime_like(a): # Check magnitude try: mag = abs(a) if mag < 2: return False for i in range(2, int(mag**0.5) + 1): if mag % i == 0: return False return True except: return False def complex_get_unit(): return complex(1, 0) def complex_get_default(): return complex(0, 0) return { "add": complex_add, "subtract": complex_subtract, "divide": complex_divide, "is_divisible": complex_is_divisible, "is_prime_like": complex_is_prime_like, "get_unit": complex_get_unit, "get_default": complex_get_default, } # For Quaternion (6) elif number_type == 6: try: from .kececinumbers import quaternion def quaternion_add(a, b): return a + b def quaternion_subtract(a, b): return a - b def quaternion_divide(a, b): try: # Quaternion division might need special handling if hasattr(a, "__truediv__"): return a / b else: # Convert to list and divide components if ( hasattr(a, "a") and hasattr(a, "b") and hasattr(a, "c") and hasattr(a, "d") ): return type(a)(a.a / b, a.b / b, a.c / b, a.d / b) else: return a / b except: return a def quaternion_is_divisible(a, divisor): # Check all components try: if ( hasattr(a, "a") and hasattr(a, "b") and hasattr(a, "c") and hasattr(a, "d") ): comps = [a.a, a.b, a.c, a.d] elif isinstance(a, (tuple, list)) and len(a) >= 4: comps = a[:4] else: comps = [a] for comp in comps: if abs(comp % divisor) > 1e-12: return False return True except: return True def quaternion_is_prime_like(a): # Check norm try: if hasattr(a, "norm"): norm = a.norm() elif hasattr(a, "__abs__"): norm = abs(a) else: norm = 0 return _is_prime_decimal(norm) except: return False def quaternion_get_unit(): return quaternion(1, 0, 0, 0) def quaternion_get_default(): return quaternion(0, 0, 0, 0) return { "add": quaternion_add, "subtract": quaternion_subtract, "divide": quaternion_divide, "is_divisible": quaternion_is_divisible, "is_prime_like": quaternion_is_prime_like, "get_unit": quaternion_get_unit, "get_default": quaternion_get_default, } except: # Fallback return _get_generic_handler() # For other special types (7-21) elif 7 <= number_type <= 21: return _get_generic_handler() else: return _get_generic_handler() def _get_generic_handler() -> Dict[str, Callable]: """ Generic handler for number types without special implementation. """ def generic_add(a, b): try: return a + b except: return a def generic_subtract(a, b): try: return a - b except: return a def generic_divide(a, b): try: return a / b except: return a def generic_is_divisible(a, divisor): return True # Assume divisible def generic_is_prime_like(a): return False # Assume not prime-like def generic_get_unit(): return 1.0 def generic_get_default(): return 0.0 return { "add": generic_add, "subtract": generic_subtract, "divide": generic_divide, "is_divisible": generic_is_divisible, "is_prime_like": generic_is_prime_like, "get_unit": generic_get_unit, "get_default": generic_get_default, } def _is_prime_decimal(n: int) -> bool: """ Check if an integer is prime. """ if n < 2: return False if n == 2 or n == 3: return True if n % 2 == 0 or n % 3 == 0: return False i = 5 while i * i <= n: if n % i == 0 or n % (i + 2) == 0: return False i += 6 return True def _get_parser_for_type(kececi_type: int) -> Callable[[str], Any]: """ Get parser function for Keçeci type. """ parser_map = { 1: lambda s: abs(float(s)), # Positive Real 2: lambda s: -abs(float(s)), # Negative Real 3: lambda s: complex(s), # Complex 4: lambda s: float(s), # Float 5: lambda s: float(s), # Rational 6: lambda s: _parse_quaternion(s), # Quaternion 7: lambda s: _parse_neutrosophic(s), # Neutrosophic 8: lambda s: _parse_neutrosophic_complex(s), # Neutrosophic Complex 9: lambda s: _parse_hyperreal(s), # Hyperreal 10: lambda s: _parse_bicomplex(s), # Bicomplex 11: lambda s: _parse_neutrosophic_bicomplex(s), # Neutrosophic Bicomplex 12: lambda s: _parse_octonion(s), # Octonion 13: lambda s: _parse_sedenion(s), # Sedenion 14: lambda s: _parse_clifford(s), # Clifford 15: lambda s: _parse_dual(s), # Dual 16: lambda s: _parse_splitcomplex(s), # Split-Complex 17: lambda s: _parse_pathion(s), # Pathion 18: lambda s: _parse_chingon(s), # Chingon 19: lambda s: _parse_routon(s), # Routon 20: lambda s: _parse_voudon(s), # Voudon 21: lambda s: _parse_superreal(s), # Superreal 22: lambda s: _parse_ternary(s), # Ternary 23: lambda s: _parse_hypercomplex(s), # } return parser_map.get(kececi_type, lambda s: float(s)) def _generate_ask_sequence_fixed( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Fixed ASK algorithm that actually works for all number types. """ # Get type-specific operations type_ops = _get_type_specific_operations(number_type) result = [] current = start_value ask_counter = 0 # 0: +unit, 1: -unit if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): step_values = [] try: # STEP 1: ADDITION added = type_ops["add"](current, add_value) step_values.append(("add", added)) logger.debug(f"Step {i}.1: ADD {current} + {add_value} = {added}") next_val = added divided = False # STEP 2: CHECK DIVISIBILITY by 2 or 3 for divisor in [2, 3]: try: # Check if divisible if type_ops["is_divisible"](added, divisor): # Try to divide divided_val = type_ops["divide"](added, divisor) step_values.append((f"divide by {divisor}", divided_val)) logger.debug( f"Step {i}.2: DIVIDE {added} / {divisor} = {divided_val}" ) next_val = divided_val divided = True break except Exception as e: logger.debug(f"Division by {divisor} failed: {e}") continue # STEP 3: KECEÇI UNIT ADJUSTMENT if not divided and looks prime-like if not divided: # Check if value looks prime-like if type_ops["is_prime_like"](added): # Get Keçeci unit for this type unit = type_ops["get_unit"]() # Apply unit based on ask_counter if ask_counter == 0: adjusted = type_ops["add"](added, unit) op_desc = f"+unit({unit})" else: adjusted = type_ops["subtract"](added, unit) op_desc = f"-unit({unit})" step_values.append(("keçeci unit", adjusted)) logger.debug( f"Step {i}.3: KECEÇI UNIT {added} {op_desc} = {adjusted}" ) # Toggle ask counter ask_counter = 1 - ask_counter # Try division again on adjusted value for divisor in [2, 3]: try: if type_ops["is_divisible"](adjusted, divisor): final_val = type_ops["divide"](adjusted, divisor) step_values.append( (f"divide adjusted by {divisor}", final_val) ) logger.debug( f"Step {i}.4: DIVIDE ADJUSTED {adjusted} / {divisor} = {final_val}" ) next_val = final_val break except Exception as e: logger.debug(f"Division on adjusted failed: {e}") continue else: # No division successful after adjustment next_val = adjusted else: # Not prime-like, keep as is logger.debug(f"Step {i}.3: Not prime-like, keeping {added}") # Update current value current = next_val # Build result if include_intermediate_steps: # Add all intermediate steps for j, (op, val) in enumerate(step_values): result.append( { "step": i, "substep": j, "value": val, "operation": op, "description": f"Step {i}.{j}: {op}{val}", } ) # Add final value result.append( { "step": i, "substep": len(step_values), "value": current, "operation": "final", "description": f"Step {i} final: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} for type {number_type}: {e}") default_val = type_ops["get_default"]() if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _get_type_specific_operations(number_type: int) -> Dict[str, Callable]: """ Get type-specific operations with proper handling for each number type. """ # Common operations def common_add(a, b): return a + b def common_subtract(a, b): return a - b def common_multiply(a, b): return a * b def common_divide(a, b): try: return a / b except ZeroDivisionError: # Handle division by zero if hasattr(a, "__class__"): try: return a.__class__(float("inf")) except: return float("inf") return float("inf") def common_mod(a, b): try: return a % b except: return a # Return original if mod not supported # Type-specific implementations if number_type in [1, 2, 4, 5]: # Real types def is_divisible_real(a, divisor): try: remainder = a % divisor return abs(remainder) < 1e-12 except: # For floats, check if result is close to integer result = a / divisor return abs(result - round(result)) < 1e-12 def is_prime_like_real(a): try: val = abs(a) if val < 2: return False if val == 2 or val == 3: return True if val % 2 == 0 or val % 3 == 0: return False i = 5 while i * i <= val: if val % i == 0 or val % (i + 2) == 0: return False i += 6 return True except: return False def get_unit_real(): return 1.0 if number_type != 2 else -1.0 def get_default_real(): return 0.0 return { "add": common_add, "subtract": common_subtract, "multiply": common_multiply, "divide": common_divide, "mod": common_mod, "is_divisible": is_divisible_real, "is_prime_like": is_prime_like_real, "get_unit": get_unit_real, "get_default": get_default_real, } elif number_type == 3: # Complex def is_divisible_complex(a, divisor): # For complex, check if both real and imag parts are divisible try: real_rem = a.real % divisor imag_rem = a.imag % divisor return abs(real_rem) < 1e-12 and abs(imag_rem) < 1e-12 except: return False def is_prime_like_complex(a): # Check magnitude try: mag = abs(a) return ( is_prime_like_complex.__closure__[0].cell_contents(mag) if number_type == 1 else False ) except: return False def get_unit_complex(): return complex(1, 0) def get_default_complex(): return complex(0, 0) return { "add": common_add, "subtract": common_subtract, "multiply": common_multiply, "divide": common_divide, "mod": lambda a, b: a, # Mod not typically defined for complex "is_divisible": is_divisible_complex, "is_prime_like": is_prime_like_complex, "get_unit": get_unit_complex, "get_default": get_default_complex, } elif number_type == 6: # Quaternion try: from .kececinumbers import quaternion def is_divisible_quaternion(q, divisor): # For quaternion, check if all components are divisible try: # q is typically (w, x, y, z) or has .a, .b, .c, .d attributes if ( hasattr(q, "a") and hasattr(q, "b") and hasattr(q, "c") and hasattr(q, "d") ): comps = [q.a, q.b, q.c, q.d] elif isinstance(q, (tuple, list)) and len(q) >= 4: comps = [q[0], q[1], q[2], q[3]] else: # Try to extract components comps = [ getattr(q, "w", 0), getattr(q, "x", 0), getattr(q, "y", 0), getattr(q, "z", 0), ] for comp in comps: if abs(comp % divisor) > 1e-12: return False return True except: return False def is_prime_like_quaternion(q): # Check norm try: if hasattr(q, "norm"): norm = q.norm() elif hasattr(q, "__abs__"): norm = abs(q) else: # Calculate norm manually if ( hasattr(q, "a") and hasattr(q, "b") and hasattr(q, "c") and hasattr(q, "d") ): norm = (q.a**2 + q.b**2 + q.c**2 + q.d**2) ** 0.5 else: norm = 0 # Simple prime check on norm if norm < 2: return False for i in range(2, int(norm**0.5) + 1): if norm % i == 0: return False return True except: return False def get_unit_quaternion(): return quaternion(1, 0, 0, 0) def get_default_quaternion(): return quaternion(0, 0, 0, 0) return { "add": common_add, "subtract": common_subtract, "multiply": common_multiply, "divide": common_divide, "mod": lambda a, b: a, "is_divisible": is_divisible_quaternion, "is_prime_like": is_prime_like_quaternion, "get_unit": get_unit_quaternion, "get_default": get_default_quaternion, } except ImportError: # Fallback for quaternion logger.warning("Quaternion class not available, using tuple representation") return _get_array_type_operations(4, "Quaternion") elif number_type == 7: # Neutrosophic def is_divisible_neutro(n, divisor): # n is (T, I, F) tuple try: t, i, f = n return ( abs(t % divisor) < 1e-12 and abs(i % divisor) < 1e-12 and abs(f % divisor) < 1e-12 ) except: return False def is_prime_like_neutro(n): # Check truth component try: t, i, f = n # Simple prime check on truth component if t < 2: return False for j in range(2, int(t**0.5) + 1): if t % j == 0: return False return True except: return False def get_unit_neutro(): return (1.0, 0.0, 0.0) def get_default_neutro(): return (0.0, 0.0, 0.0) return { "add": lambda a, b: (a[0] + b[0], a[1] + b[1], a[2] + b[2]), "subtract": lambda a, b: (a[0] - b[0], a[1] - b[1], a[2] - b[2]), "multiply": lambda a, b: (a[0] * b[0], a[1] * b[1], a[2] * b[2]), "divide": lambda a, b: (a[0] / b[0], a[1] / b[1], a[2] / b[2]), "mod": lambda a, b: a, "is_divisible": is_divisible_neutro, "is_prime_like": is_prime_like_neutro, "get_unit": get_unit_neutro, "get_default": get_default_neutro, } elif number_type in [12, 13, 17, 18, 19, 20, 22]: # Array-based types sizes = { 12: 8, # Octonion 13: 16, # Sedenion 17: 32, # Pathion 18: 64, # Chingon 19: 128, # Routon 20: 256, # Voudon 22: 3, # Ternary } size = sizes.get(number_type, 1) return _get_array_type_operations(size, f"Type {number_type}") else: # Default for other types return { "add": common_add, "subtract": common_subtract, "multiply": common_multiply, "divide": common_divide, "mod": lambda a, b: a, "is_divisible": lambda a, b: True, "is_prime_like": lambda a: False, "get_unit": lambda: 1.0, "get_default": lambda: 0.0, } def _get_array_type_operations(size: int, type_name: str) -> Dict[str, Callable]: """ Get operations for array-based number types. """ def array_add(a, b): if isinstance(b, (int, float)): return [x + b for x in a] else: # Element-wise addition return [a[i] + b[i] for i in range(min(len(a), len(b)))] def array_subtract(a, b): if isinstance(b, (int, float)): return [x - b for x in a] else: return [a[i] - b[i] for i in range(min(len(a), len(b)))] def array_multiply(a, b): if isinstance(b, (int, float)): return [x * b for x in a] else: return [a[i] * b[i] for i in range(min(len(a), len(b)))] def array_divide(a, b): if isinstance(b, (int, float)): return [x / b for x in a] else: return [a[i] / b[i] for i in range(min(len(a), len(b)))] def array_is_divisible(a, divisor): # Check first component try: return abs(a[0] % divisor) < 1e-12 except: return True def array_is_prime_like(a): # Check first component try: val = abs(a[0]) if val < 2: return False for i in range(2, int(val**0.5) + 1): if val % i == 0: return False return True except: return False def array_get_unit(): unit = [0.0] * size unit[0] = 1.0 return unit def array_get_default(): return [0.0] * size return { "add": array_add, "subtract": array_subtract, "multiply": array_multiply, "divide": array_divide, "mod": lambda a, b: a, "is_divisible": array_is_divisible, "is_prime_like": array_is_prime_like, "get_unit": array_get_unit, "get_default": array_get_default, } def _get_parser_for_type_simple(kececi_type: int) -> Callable[[str], Any]: """ Get parser function for Keçeci type. Uses existing parsers from kececinumbers module. """ # Map type to parser if kececi_type == 1: # Positive Real return _parse_fraction elif kececi_type == 2: # Negative Real return lambda s: -_parse_fraction(s) elif kececi_type == 3: # Complex return _parse_complex elif kececi_type == 4: # Float return _parse_fraction elif kececi_type == 5: # Rational # Try to return as Fraction try: from fractions import Fraction return lambda s: Fraction(_parse_fraction(s)).limit_denominator() except: return _parse_fraction elif kececi_type == 6: # Quaternion return _parse_quaternion elif kececi_type == 7: # Neutrosophic return _parse_neutrosophic elif kececi_type == 8: # Neutrosophic Complex return _parse_neutrosophic_complex elif kececi_type == 9: # Hyperreal return _parse_hyperreal elif kececi_type == 10: # Bicomplex return _parse_bicomplex elif kececi_type == 11: # Neutrosophic Bicomplex return _parse_neutrosophic_bicomplex elif kececi_type == 12: # Octonion return _parse_octonion elif kececi_type == 13: # Sedenion return _parse_sedenion elif kececi_type == 14: # Clifford return _parse_clifford elif kececi_type == 15: # Dual return _parse_dual elif kececi_type == 16: # Split-Complex return _parse_splitcomplex elif kececi_type == 17: # Pathion return _parse_pathion elif kececi_type == 18: # Chingon return _parse_chingon elif kececi_type == 19: # Routon return _parse_routon elif kececi_type == 20: # Voudon return _parse_voudon elif kececi_type == 21: # Superreal return _parse_superreal elif kececi_type == 22: # Ternary return _parse_ternary elif kececi_type == 23: # Hypercomplex return _parse_hypercomplex else: raise ValueError(f"Unsupported type: {kececi_type}") def _generate_sequence_original( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Original ASK algorithm from version 0.8.6. """ # Get operations for this type ops = _get_type_operations(number_type) result = [] current = start_value ask_counter = 0 # 0: +unit, 1: -unit if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: # 1. ADDITION added = ops["add"](current, add_value) next_val = added divided = False # 2. CHECK DIVISIBILITY by 2 or 3 for divisor in [2, 3]: try: if ops["is_divisible"](added, divisor): divided_val = ops["divide"](added, divisor) next_val = divided_val divided = True break except Exception: continue # 3. KECEÇI UNIT adjustment if not divided and prime-like if not divided and ops["is_prime_like"](added): unit = ops["get_unit"](current) direction = 1 if ask_counter == 0 else -1 try: if direction > 0: adjusted = ops["add"](added, unit) else: adjusted = ops["subtract"](added, unit) # Toggle ask counter ask_counter = 1 - ask_counter # Try division again on adjusted value for divisor in [2, 3]: try: if ops["is_divisible"](adjusted, divisor): final_val = ops["divide"](adjusted, divisor) next_val = final_val break except Exception: continue else: # No division successful, use adjusted value next_val = adjusted except Exception: # If unit adjustment fails, keep original pass # Update current value current = next_val # Add to result if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": "step", "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} for type {number_type}: {e}") default_val = ops["get_default"]() if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _generate_sequence_with_operation( start_value: Any, add_value: Any, iterations: int, operation: str, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Generate sequence using standard mathematical operations. """ ops = _get_type_operations(number_type) result = [] current = start_value if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: # Apply operation if operation == "add": current = ops["add"](current, add_value) elif operation == "subtract": current = ops["subtract"](current, add_value) elif operation == "multiply": current = ops["multiply"](current, add_value) elif operation == "divide": current = ops["divide"](current, add_value) elif operation == "mod": current = ops["mod"](current, add_value) elif operation == "power": current = ops["power"](current, add_value) else: # Default to addition current = ops["add"](current, add_value) # Add to result if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": operation, "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error( f"Error at iteration {i} for type {number_type}, operation {operation}: {e}" ) default_val = ops["get_default"]() if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _get_type_operations(number_type: int) -> Dict[str, Callable]: """ Return a dict of operations for the given number_type. Each operation is a callable that accepts (a, b) or (a,) depending on op. Fallbacks try to be consistent and predictable across types. """ # Basic arithmetic wrappers with layered fallbacks def type_add(a, b): try: return a + b except Exception as e: logger.debug("add failed with %s, trying fallbacks", e) # try module-level safe_add if available try: from .kececinumbers import safe_add return safe_add(a, b) except Exception: pass # elementwise fallback when b is scalar if isinstance(a, (list, tuple)) and _is_numeric_scalar(b): return type(a)([x + b for x in a]) raise def type_subtract(a, b): try: return a - b except Exception as e: logger.debug("subtract failed with %s", e) if isinstance(a, (list, tuple)) and _is_numeric_scalar(b): return type(a)([x - b for x in a]) raise def type_multiply(a, b): try: return a * b except Exception as e: logger.debug("multiply failed with %s", e) if isinstance(a, (list, tuple)) and _is_numeric_scalar(b): return type(a)([x * b for x in a]) raise def type_divide(a, b): try: return _safe_divide(a, b) except Exception as e: logger.debug("safe_divide failed with %s", e) try: return a / b except Exception: if isinstance(a, (list, tuple)) and _is_numeric_scalar(b): return type(a)([x / b for x in a]) raise def type_mod(a, b): try: return _safe_mod(a, b) except Exception as e: logger.debug("safe_mod failed with %s", e) try: return a % b except Exception: # If mod not supported, return a unchanged (explicit choice) return a def type_power(a, b): try: return _safe_power(a, b) except Exception as e: logger.debug("safe_power failed with %s", e) try: return a**b except Exception: # sensible fallbacks for common exponents if _is_numeric_scalar(b): if b == 2: return type_multiply(a, a) if b == 1: return a if b == 0: # try to return multiplicative identity for the type try: unit = ops["get_unit"]() return unit if unit is not None else 1 except Exception: return 1 raise # divisibility and primality helpers def type_is_divisible(a, divisor): try: from .kececinumbers import _is_divisible as _mod_check return _mod_check(a, divisor, number_type) except Exception: try: # numeric fallback if _is_numeric_scalar(a) and _is_numeric_scalar(divisor): return abs(a % divisor) < 1e-12 if isinstance(a, complex) and _is_numeric_scalar(divisor): return (abs(a.real % divisor) < 1e-12) and ( abs(a.imag % divisor) < 1e-12 ) # arrays: check first component if isinstance(a, (list, tuple)) and _is_numeric_scalar(divisor): return abs(_coerce_first_component(a) % divisor) < 1e-12 except Exception as e: logger.debug("is_divisible fallback failed %s", e) # conservative default return False def type_is_prime_like(a): try: from .kececinumbers import is_prime_like return is_prime_like(a, number_type) except Exception: # fallback: check primality of magnitude or first component try: from .kececinumbers import is_prime except Exception: is_prime = None try: mag = _coerce_first_component(a) if is_prime: return is_prime(int(abs(mag))) # simple trial division for small integers n = int(abs(mag)) if n < 2: return False if n in (2, 3): return True if n % 2 == 0: return False r = int(math.sqrt(n)) for i in range(3, r + 1, 2): if n % i == 0: return False return True except Exception as e: logger.debug("is_prime_like fallback failed %s", e) return False # unit and default value providers def type_get_unit(sample=None): # try to use centralized helper if available try: from .module_helpers import get_unit_for_type return get_unit_for_type(number_type, sample=sample) except Exception: pass # inline fallbacks if number_type in (1, 4, 5): return 1.0 if number_type == 2: return -1.0 if number_type == 3: return complex(1, 0) if number_type == 6: try: from .kececinumbers import quaternion return quaternion(1, 0, 0, 0) except Exception: return (1.0, 0.0, 0.0, 0.0) if number_type == 7: try: from .kececinumbers import NeutrosophicNumber return NeutrosophicNumber(1.0, 0.0, 0.0) except Exception: return (1.0, 0.0, 0.0) if number_type in (12, 13, 17, 18, 19, 20, 22): sizes = {12: 8, 13: 16, 17: 32, 18: 64, 19: 128, 20: 256, 22: 3} size = sizes.get(number_type, 1) return [1.0] + [0.0] * (size - 1) if number_type == 9: return [1.0, 0.0] if number_type == 10: return complex(1, 0) if number_type == 23: # hypercomplex # infer dimension from sample if provided, default to 8 dim = 8 if isinstance(sample, (list, tuple)): dim = max(1, len(sample)) return [1.0] + [0.0] * (dim - 1) # default return 1.0 def type_get_default(sample=None): try: from .module_helpers import get_default_for_type return get_default_for_type(number_type, sample=sample) except Exception: pass if number_type in (1, 2, 4, 5): return 0.0 if number_type == 3: return complex(0, 0) if number_type == 6: try: from .kececinumbers import quaternion return quaternion(0, 0, 0, 0) except Exception: return (0.0, 0.0, 0.0, 0.0) if number_type == 7: try: from .kececinumbers import NeutrosophicNumber return NeutrosophicNumber(0.0, 0.0, 0.0) except Exception: return (0.0, 0.0, 0.0) if number_type in (12, 13, 17, 18, 19, 20, 22): sizes = {12: 8, 13: 16, 17: 32, 18: 64, 19: 128, 20: 256, 22: 3} size = sizes.get(number_type, 1) return [0.0] * size if number_type == 9: return [0.0, 0.0] if number_type == 10: return complex(0, 0) if number_type == 23: dim = 8 if isinstance(sample, (list, tuple)): dim = max(1, len(sample)) return [0.0] * dim return 0.0 # assemble ops dict; some ops may reference others so create dict first then fill if needed ops = { "add": type_add, "subtract": type_subtract, "multiply": type_multiply, "divide": type_divide, "mod": type_mod, "power": type_power, "is_divisible": type_is_divisible, "is_prime_like": type_is_prime_like, "get_unit": type_get_unit, "get_default": type_get_default, } return ops def _parse_special_type( kececi_type: int, start_input_raw: str, add_input_raw: str ) -> Tuple[Any, Any]: """ Parse values for special Keçeci number types (6-23). """ try: # First try to use the specific parser parser_func = _get_parser_for_type(kececi_type) if parser_func: return parser_func(start_input_raw), parser_func(add_input_raw) except Exception as e: logger.debug(f"Specific parser failed for type {kececi_type}: {e}") # Fallback to generic parsing return _parse_with_generic_fallback(kececi_type, start_input_raw, add_input_raw) def _get_parser_for_type(kececi_type: int) -> Optional[Callable]: """ Get parser function for a specific Keçeci type. """ try: from .kececinumbers import ( _generate_simple_ask_sequence, _parse_bicomplex, _parse_chingon, _parse_clifford, _parse_complex, _parse_complex_like_string, _parse_dual, _parse_engineering_notation, _parse_fraction, _parse_hypercomplex, _parse_hyperreal, _parse_kececi_values, _parse_neutrosophic, _parse_neutrosophic_bicomplex, _parse_neutrosophic_complex, _parse_octonion, _parse_pathion, _parse_quaternion, _parse_quaternion_from_csv, _parse_real, _parse_routon, _parse_sedenion, _parse_splitcomplex, _parse_super_real, _parse_superreal, _parse_ternary, _parse_universal, _parse_voudon, _parse_with_fallback_simple, parse_to_hyperreal, parse_to_neutrosophic, ) parser_map = { 6: _parse_quaternion, 7: _parse_neutrosophic, 8: _parse_neutrosophic_complex, 9: _parse_hyperreal, 10: _parse_bicomplex, 11: _parse_neutrosophic_bicomplex, 12: _parse_octonion, 13: _parse_sedenion, 14: _parse_clifford, 15: _parse_dual, 16: _parse_splitcomplex, 17: _parse_pathion, 18: _parse_chingon, 19: _parse_routon, 20: _parse_voudon, 21: _parse_super_real, 22: _parse_ternary, 23: _parse_hypercomplex, } return parser_map.get(kececi_type) except ImportError: return None # ----------------- Yardımcılar ----------------- def _pad_or_truncate(lst: Iterable[Any], dim: int) -> List[Any]: arr = list(lst) if len(arr) < dim: return arr + [0.0] * (dim - len(arr)) return arr[:dim] def _try_construct(cls, args_list: List[Any], dimension: Optional[int] = None): """ Bir sınıfı farklı constructor imzalarıyla dene: - cls(list, dimension=dim) - cls(*components, dimension=dim) - cls(list) - cls(*components) """ # prefer list + dimension try: if dimension is not None: return cls(args_list, dimension=dimension) except TypeError: pass except Exception as e: logger.debug("Constructor attempt failed (list+dim): %s", e) # try *args + dimension try: if dimension is not None: return cls(*args_list, dimension=dimension) except TypeError: pass except Exception as e: logger.debug("Constructor attempt failed (*args+dim): %s", e) # try list only try: return cls(args_list) except Exception as e: logger.debug("Constructor attempt failed (list): %s", e) # try *args only try: return cls(*args_list) except Exception as e: logger.debug("Constructor attempt failed (*args): %s", e) # all failed raise TypeError("No compatible constructor found for class {}".format(cls)) # ----------------- Ana fonksiyon ----------------- def _parse_with_generic_fallback( kececi_type: int, start_input_raw: Any, add_input_raw: Any ) -> Tuple[Any, Any]: """ Generic fallback parser for special types. - start_input_raw / add_input_raw: string, iterable, scalar accepted. - Returns (start_value, add_value) as either project class instances (if available) or consistent Python fallback structures (tuple/list/complex/float). """ # First try to use project-specific fraction parser if available (keçeci projesi) base_start = None base_add = None try: from .kececinumbers import _parse_fraction as _pf try: base_start = _pf(start_input_raw) except Exception: base_start = None try: base_add = _pf(add_input_raw) except Exception: base_add = None except Exception: base_start = None base_add = None # If project parser didn't produce values, use generic parser if base_start is None: parsed_start = _parse_components(start_input_raw) base_start = parsed_start[0] if parsed_start else 0.0 if base_add is None: parsed_add = _parse_components(add_input_raw) base_add = parsed_add[0] if parsed_add else 0.0 # Helper to attempt class construction with safe logging def _construct_or_fallback( class_name: str, cls_try, args_list, dim=None, fallback_type="list" ): try: inst = _try_construct(cls_try, args_list, dimension=dim) return inst except Exception as e: logger.debug("Could not construct %s: %s", class_name, e) # fallback: return list or tuple depending on fallback_type if fallback_type == "tuple": return tuple(args_list) return list(args_list) # Map types # For scalar-like types we return simple scalars/complex if kececi_type == 6: # Quaternion (4D) quat = (base_start, 0.0, 0.0, 0.0) try: from .kececinumbers import QuaternionNumber return _construct_or_fallback( "QuaternionNumber", QuaternionNumber, list(quat), dim=4, fallback_type="tuple", ), _construct_or_fallback( "QuaternionNumber", QuaternionNumber, list((base_add, 0.0, 0.0, 0.0)), dim=4, fallback_type="tuple", ) except Exception: return tuple(quat), tuple((base_add, 0.0, 0.0, 0.0)) if kececi_type == 7: # Neutrosophic (T,I,F) neutro = (base_start, 0.0, 0.0) try: from .kececinumbers import NeutrosophicNumber return _construct_or_fallback( "NeutrosophicNumber", NeutrosophicNumber, list(neutro), dim=3, fallback_type="tuple", ), _construct_or_fallback( "NeutrosophicNumber", NeutrosophicNumber, list((base_add, 0.0, 0.0)), dim=3, fallback_type="tuple", ) except Exception: return tuple(neutro), tuple((base_add, 0.0, 0.0)) if kececi_type == 8: # Neutrosophic Complex try: from .kececinumbers import NeutrosophicComplexNumber return _construct_or_fallback( "NeutrosophicComplexNumber", NeutrosophicComplexNumber, [base_start, 0.0, 0.0], dim=None, ), _construct_or_fallback( "NeutrosophicComplexNumber", NeutrosophicComplexNumber, [base_add, 0.0, 0.0], dim=None, ) except Exception: return complex(base_start, 0), complex(base_add, 0) if kececi_type == 9: # Hyperreal [finite, infinitesimal] hyper_start = [base_start, 0.0] hyper_add = [base_add, 0.0] try: from .kececinumbers import HyperrealNumber return _construct_or_fallback( "HyperrealNumber", HyperrealNumber, hyper_start, dim=2 ), _construct_or_fallback( "HyperrealNumber", HyperrealNumber, hyper_add, dim=2 ) except Exception: return hyper_start, hyper_add if kececi_type == 10: # Bicomplex bic_start = complex(base_start, 0) bic_add = complex(base_add, 0) try: from .kececinumbers import BicomplexNumber return _construct_or_fallback( "BicomplexNumber", BicomplexNumber, [bic_start] ), _construct_or_fallback("BicomplexNumber", BicomplexNumber, [bic_add]) except Exception: return bic_start, bic_add if kececi_type == 11: # Neutrosophic Bicomplex (fallback to complex) try: from .kececinumbers import NeutrosophicBicomplexNumber return _construct_or_fallback( "NeutrosophicBicomplexNumber", NeutrosophicBicomplexNumber, [base_start] ), _construct_or_fallback( "NeutrosophicBicomplexNumber", NeutrosophicBicomplexNumber, [base_add] ) except Exception: return complex(base_start, 0), complex(base_add, 0) if kececi_type == 12: # Octonion (8D) octo_start = [base_start] + [0.0] * 7 octo_add = [base_add] + [0.0] * 7 try: from .kececinumbers import OctonionNumber return _construct_or_fallback( "OctonionNumber", OctonionNumber, octo_start, dim=8 ), _construct_or_fallback("OctonionNumber", OctonionNumber, octo_add, dim=8) except Exception: return octo_start, octo_add if kececi_type == 13: # Sedenion (16D) sed_start = [base_start] + [0.0] * 15 sed_add = [base_add] + [0.0] * 15 try: from .kececinumbers import SedenionNumber return _construct_or_fallback( "SedenionNumber", SedenionNumber, sed_start, dim=16 ), _construct_or_fallback("SedenionNumber", SedenionNumber, sed_add, dim=16) except Exception: return sed_start, sed_add if kececi_type == 14: # Clifford cliff_start = {"e0": base_start} cliff_add = {"e0": base_add} try: from .kececinumbers import CliffordNumber return _construct_or_fallback( "CliffordNumber", CliffordNumber, [cliff_start] ), _construct_or_fallback("CliffordNumber", CliffordNumber, [cliff_add]) except Exception: return cliff_start, cliff_add if kececi_type == 15: # Dual dual_start = (base_start, 0.0) dual_add = (base_add, 0.0) try: from .kececinumbers import DualNumber return _construct_or_fallback( "DualNumber", DualNumber, list(dual_start), dim=2, fallback_type="tuple" ), _construct_or_fallback( "DualNumber", DualNumber, list(dual_add), dim=2, fallback_type="tuple" ) except Exception: return dual_start, dual_add if kececi_type == 16: # Split-complex split_start = (base_start, 0.0) split_add = (base_add, 0.0) try: from .kececinumbers import SplitcomplexNumber return _construct_or_fallback( "SplitcomplexNumber", SplitcomplexNumber, list(split_start), dim=2, fallback_type="tuple", ), _construct_or_fallback( "SplitcomplexNumber", SplitcomplexNumber, list(split_add), dim=2, fallback_type="tuple", ) except Exception: return split_start, split_add if kececi_type == 17: # Pathion (32D) path_start = [base_start] + [0.0] * 31 path_add = [base_add] + [0.0] * 31 try: from .kececinumbers import PathionNumber return _construct_or_fallback( "PathionNumber", PathionNumber, path_start, dim=32 ), _construct_or_fallback("PathionNumber", PathionNumber, path_add, dim=32) except Exception: return path_start, path_add if kececi_type == 18: # Chingon (64D) ching_start = [base_start] + [0.0] * 63 ching_add = [base_add] + [0.0] * 63 try: from .kececinumbers import ChingonNumber return _construct_or_fallback( "ChingonNumber", ChingonNumber, ching_start, dim=64 ), _construct_or_fallback("ChingonNumber", ChingonNumber, ching_add, dim=64) except Exception: return ching_start, ching_add if kececi_type == 19: # Routon (128D) rout_start = [base_start] + [0.0] * 127 rout_add = [base_add] + [0.0] * 127 try: from .kececinumbers import RoutonNumber return _construct_or_fallback( "RoutonNumber", RoutonNumber, rout_start, dim=128 ), _construct_or_fallback("RoutonNumber", RoutonNumber, rout_add, dim=128) except Exception: return rout_start, rout_add if kececi_type == 20: # Voudon (256D) voud_start = [base_start] + [0.0] * 255 voud_add = [base_add] + [0.0] * 255 try: from .kececinumbers import VoudonNumber return _construct_or_fallback( "VoudonNumber", VoudonNumber, voud_start, dim=256 ), _construct_or_fallback("VoudonNumber", VoudonNumber, voud_add, dim=256) except Exception: return voud_start, voud_add if kececi_type == 21: # Superreal super_start = (base_start, 0.0) super_add = (base_add, 0.0) try: from .kececinumbers import SuperrealNumber return _construct_or_fallback( "SuperrealNumber", SuperrealNumber, list(super_start), dim=2, fallback_type="tuple", ), _construct_or_fallback( "SuperrealNumber", SuperrealNumber, list(super_add), dim=2, fallback_type="tuple", ) except Exception: return super_start, super_add if kececi_type == 22: # Ternary (3D) try: from .kececinumbers import TernaryNumber start_str = str(start_input_raw).strip() add_str = str(add_input_raw).strip() # Eğer string boş veya geçersizse hata ver if not start_str or not all(c in "012" for c in start_str): raise ValueError(f"Geçersiz ternary başlangıç: {start_str}") if not add_str or not all(c in "012" for c in add_str): raise ValueError(f"Geçersiz ternary artış: {add_str}") start_val = TernaryNumber.from_ternary_string(start_str) add_val = TernaryNumber.from_ternary_string(add_str) return start_val, add_val except Exception as e: logger.error(f"Ternary dönüşüm hatası: {e}") # Fallback: sıfır değerinde ternary fallback = TernaryNumber.from_decimal(0) return fallback, fallback """ if kececi_type == 22: # Ternary (3D) parsed_start = _parse_components(start_input_raw) parsed_add = _parse_components(add_input_raw) base_start_comp = float(parsed_start[0]) if parsed_start else 0.0 base_add_comp = float(parsed_add[0]) if parsed_add else 0.0 ternary_start = [base_start_comp, 0.0, 0.0] ternary_add = [base_add_comp, 0.0, 0.0] try: from .kececinumbers import TernaryNumber return _construct_or_fallback("TernaryNumber", TernaryNumber, ternary_start, dim=3), \ _construct_or_fallback("TernaryNumber", TernaryNumber, ternary_add, dim=3) except Exception as e: logger.debug("TernaryNumber import/construct failed: %s", e) return ternary_start, ternary_add """ if kececi_type == 23: # Hypercomplex (variable power-of-two dimension) parsed_start = _parse_components(start_input_raw) parsed_add = _parse_components(add_input_raw) desired_len = max(1, len(parsed_start), len(parsed_add)) dim = _next_power_of_two_at_least(desired_len, max_dim=256) hyper_start_list = _pad_or_truncate(parsed_start, dim) hyper_add_list = _pad_or_truncate(parsed_add, dim) try: from .kececinumbers import HypercomplexNumber as HC try: return _construct_or_fallback( "HypercomplexNumber", HC, hyper_start_list, dim=dim ), _construct_or_fallback( "HypercomplexNumber", HC, hyper_add_list, dim=dim ) except Exception: # last attempt: try without dimension kwarg return _construct_or_fallback( "HypercomplexNumber", HC, hyper_start_list ), _construct_or_fallback("HypercomplexNumber", HC, hyper_add_list) except Exception as e: logger.debug("HypercomplexNumber import/construct failed: %s", e) return hyper_start_list, hyper_add_list # Default fallback: return parsed scalar/fraction results return base_start, base_add def _generate_ask_for_type( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool, number_type: int, ) -> List[Any]: """ Generate ASK sequence for a specific number type. """ # Get appropriate operations for this type operations = _get_operations_for_type(number_type) result = [] current = start_value ask_counter = 0 if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "type": _get_type_name(number_type), "description": f"Start: {current}", } ) else: result.append(current) for i in range(1, iterations): try: # 1. ADD added = operations["add"](current, add_value) # 2. Check division next_val = added divided = False for divisor in [2, 3]: try: if operations["is_divisible"](added, divisor): next_val = operations["divide"](added, divisor) divided = True break except: continue # 3. Keçeci unit adjustment if not divided and operations["is_prime_like"](added): unit = operations["get_unit"](current) if ask_counter == 0: adjusted = operations["add"](added, unit) else: adjusted = operations["subtract"](added, unit) ask_counter = 1 - ask_counter # Try division on adjusted value for divisor in [2, 3]: try: if operations["is_divisible"](adjusted, divisor): next_val = operations["divide"](adjusted, divisor) break except: continue else: next_val = adjusted current = next_val if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": "step", "type": _get_type_name(number_type), "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i} for type {number_type}: {e}") default_val = operations["get_default"]() if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "type": _get_type_name(number_type), "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _get_operations_for_type(number_type: int) -> Dict[str, Callable]: """ Get appropriate operations for a number type. """ # Basic operations that work for most types def basic_add(a, b): try: return a + b except: # Fallback for tuples/lists if isinstance(a, (tuple, list)) and isinstance(b, (int, float)): if isinstance(a, tuple): return tuple(x + b for x in a) return [x + b for x in a] raise def basic_subtract(a, b): try: return a - b except: if isinstance(a, (tuple, list)) and isinstance(b, (int, float)): if isinstance(a, tuple): return tuple(x - b for x in a) return [x - b for x in a] raise def basic_divide(a, divisor): try: return a / divisor except: if isinstance(a, (tuple, list)): if isinstance(a, tuple): return tuple(x / divisor for x in a) return [x / divisor for x in a] raise def basic_is_divisible(a, divisor): try: # For numeric types if hasattr(a, "__mod__"): remainder = a % divisor if hasattr(remainder, "__abs__"): return abs(remainder) < 1e-10 return abs(remainder) < 1e-10 return True except: return True def basic_is_prime_like(a): try: # Try to get a numeric value if isinstance(a, (int, float, complex)): val = abs(a) elif isinstance(a, (tuple, list)): # Use first component val = abs(a[0]) if a else 0 else: val = abs(float(str(a))) # Simple prime check if val < 2: return False for i in range(2, int(val**0.5) + 1): if val % i == 0: return False return True except: return False def basic_get_unit(sample=None): if number_type in [1, 4, 5]: return 1.0 elif number_type == 2: return -1.0 elif number_type == 3: return complex(1, 0) elif number_type == 6: return (1.0, 0.0, 0.0, 0.0) elif number_type == 7: return (1.0, 0.0, 0.0) elif number_type in [12, 13, 17, 18, 19, 20, 22]: # Array types sizes = {12: 8, 13: 16, 17: 32, 18: 64, 19: 128, 20: 256, 22: 3} size = sizes.get(number_type, 1) unit = [0.0] * size unit[0] = 1.0 return unit else: return 1.0 def basic_get_default(): if number_type in [1, 2, 4, 5]: return 0.0 elif number_type == 3: return complex(0, 0) elif number_type == 6: return (0.0, 0.0, 0.0, 0.0) elif number_type == 7: return (0.0, 0.0, 0.0) elif number_type in [12, 13, 17, 18, 19, 20, 22]: sizes = {12: 8, 13: 16, 17: 32, 18: 64, 19: 128, 20: 256, 22: 3} size = sizes.get(number_type, 1) return [0.0] * size else: return 0.0 return { "add": basic_add, "subtract": basic_subtract, "divide": basic_divide, "is_divisible": basic_is_divisible, "is_prime_like": basic_is_prime_like, "get_unit": basic_get_unit, "get_default": basic_get_default, } def _get_type_name(number_type: int) -> str: """Get name for number type.""" names = { 1: "Positive Real", 2: "Negative Real", 3: "Complex", 4: "Float", 5: "Rational", 6: "Quaternion", 7: "Neutrosophic", 8: "Neutrosophic Complex", 9: "Hyperreal", 10: "Bicomplex", 11: "Neutrosophic Bicomplex", 12: "Octonion", 13: "Sedenion", 14: "Clifford", 15: "Dual", 16: "Split-Complex", 17: "Pathion", 18: "Chingon", 19: "Routon", 20: "Voudon", 21: "Superreal", 22: "Ternary", 23: "Hypercomplex", } return names.get(number_type, f"Type {number_type}") def _generate_simple_ask_sequence( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, ) -> List[Any]: """ Simple ASK algorithm implementation. """ result = [] current = start_value if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) else: result.append(current) ask_counter = 0 # 0: add unit, 1: subtract unit for i in range(1, iterations): try: # 1. ADD added = _simple_add(current, add_value) # 2. Check division by 2 or 3 next_val = added divided = False for divisor in [2, 3]: try: if _simple_is_divisible(added, divisor): next_val = _simple_divide(added, divisor) divided = True logger.debug(f"Divided by {divisor}: {added} -> {next_val}") break except Exception as e: logger.debug(f"Division by {divisor} failed: {e}") continue # 3. If not divided, check if prime-like and apply Keçeci unit if not divided: if _simple_is_prime_like(added): # Get appropriate unit unit = _get_simple_unit(number_type, current) # Apply unit based on ask_counter if ask_counter == 0: adjusted = _simple_add(added, unit) logger.debug(f"Added unit {unit}: {added} -> {adjusted}") else: adjusted = _simple_subtract(added, unit) logger.debug(f"Subtracted unit {unit}: {added} -> {adjusted}") # Toggle ask_counter ask_counter = 1 - ask_counter # Try division again on adjusted value for divisor in [2, 3]: try: if _simple_is_divisible(adjusted, divisor): next_val = _simple_divide(adjusted, divisor) logger.debug( f"Divided adjusted by {divisor}: {adjusted} -> {next_val}" ) break except: continue else: # No division successful, use adjusted next_val = adjusted # Update current value current = next_val # Add to result if include_intermediate_steps: result.append( { "step": i, "value": current, "operation": "step", "description": f"Step {i}: {current}", } ) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i}: {e}") default_val = _get_simple_default(number_type) if include_intermediate_steps: result.append( { "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}", } ) else: result.append(default_val) current = default_val return result def _simple_add(a: Any, b: Any) -> Any: """Simple addition.""" try: return a + b except Exception: # For lists/tuples if isinstance(a, (list, tuple)) and isinstance(b, (int, float)): if isinstance(a, tuple): return tuple(x + b for x in a) else: return [x + b for x in a] elif isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)): # Element-wise addition size = max(len(a), len(b)) result = [] for i in range(size): val_a = a[i] if i < len(a) else 0 val_b = b[i] if i < len(b) else 0 result.append(val_a + val_b) if isinstance(a, tuple): return tuple(result) else: return result else: raise def _simple_subtract(a: Any, b: Any) -> Any: """Simple subtraction.""" try: return a - b except Exception: # Similar to _simple_add but for subtraction if isinstance(a, (list, tuple)) and isinstance(b, (int, float)): if isinstance(a, tuple): return tuple(x - b for x in a) else: return [x - b for x in a] elif isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)): size = max(len(a), len(b)) result = [] for i in range(size): val_a = a[i] if i < len(a) else 0 val_b = b[i] if i < len(b) else 0 result.append(val_a - val_b) if isinstance(a, tuple): return tuple(result) else: return result else: raise def _simple_divide(a: Any, divisor: float) -> Any: """Simple division.""" try: return a / divisor except Exception: if isinstance(a, (list, tuple)): if isinstance(a, tuple): return tuple(x / divisor for x in a) else: return [x / divisor for x in a] else: raise def _simple_is_divisible(a: Any, divisor: float) -> bool: """Simple divisibility check.""" try: if isinstance(a, (int, float)): return abs(a % divisor) < 1e-10 elif isinstance(a, complex): return abs(a.real % divisor) < 1e-10 and abs(a.imag % divisor) < 1e-10 elif isinstance(a, (list, tuple)): # Check first element if a: return _simple_is_divisible(a[0], divisor) return True else: return True # Assume divisible for unknown types except: return False def _simple_is_prime_like(a: Any) -> bool: """Simple prime-like check.""" try: # Convert to float for checking if isinstance(a, (int, float)): val = abs(a) elif isinstance(a, complex): val = abs(a) elif isinstance(a, (list, tuple)): # Use first non-zero element for x in a: if abs(x) > 1e-10: val = abs(x) break else: return False else: # Try to get magnitude try: val = abs(a) except: return False # Simple prime check if val < 2: return False if val == 2 or val == 3: return True if val % 2 == 0 or val % 3 == 0: return False i = 5 while i * i <= val: if val % i == 0 or val % (i + 2) == 0: return False i += 6 return True except: return False def _get_simple_unit(number_type: int, sample_value: Any = None) -> Any: """Get simple unit for number type.""" if number_type in [1, 4, 5]: return 1.0 elif number_type == 2: return -1.0 elif number_type == 3: return complex(1, 0) elif number_type == 6: # Quaternion return (1.0, 0.0, 0.0, 0.0) elif number_type == 7: # Neutrosophic return (1.0, 0.0, 0.0) elif number_type in [12, 13, 17, 18, 19, 20, 22]: # Array types if sample_value and hasattr(sample_value, "__len__"): size = len(sample_value) unit = [0.0] * size unit[0] = 1.0 if isinstance(sample_value, tuple): return tuple(unit) return unit return 1.0 else: return 1.0 def _get_simple_default(number_type: int) -> Any: """Get default value for number type.""" if number_type in [1, 2, 4, 5]: return 0.0 elif number_type == 3: return complex(0, 0) elif number_type == 6: return (0.0, 0.0, 0.0, 0.0) elif number_type == 7: return (0.0, 0.0, 0.0) elif number_type in [12, 13, 17, 18, 19, 20, 22]: # Return appropriate sized zero array sizes = { 12: 8, # Octonion 13: 16, # Sedenion 17: 32, # Pathion 18: 64, # Chingon 19: 128, # Routon 20: 256, # Voudon 22: 3, # Ternary } size = sizes.get(number_type, 1) return [0.0] * size else: return 0.0 # ----------------------------- Geliştirilmiş ASK üretici ----------------------------- def _generate_ask_sequence_complete( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1, first_divisor: int = 3, ask_plus_first: bool = True, ) -> List[Any]: """ ASK algoritması – Keçeci dizisi üretir (sadece tip 1 için). - first_divisor: ilk denenmesi gereken bölen (3 veya 2) - ask_plus_first: ASK işaret sırası (True: +, -, +, -; False: -, +, -, +) - include_intermediate_steps: True -> her işlem sözlük, False -> düz liste (nihai değerler) """ if number_type != 1: raise NotImplementedError("Sadece tip 1 (Positive Real) desteklenmektedir.") result = [] current = start_value ask_counter = 0 # 0: ilk yön, 1: ikinci yön primary = first_divisor secondary = 2 if primary == 3 else 3 if include_intermediate_steps: result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) for i in range(1, iterations + 1): # 1. Toplama added = current + add_value if include_intermediate_steps: result.append( { "step": i, "value": added, "operation": "add", "description": f"Add {add_value}: {current} + {add_value} = {added}", } ) next_val = added divided = False # 2. Bölme – önce primary, sonra secondary for divisor in (primary, secondary): if added % divisor == 0: divided_val = added // divisor if include_intermediate_steps: result.append( { "step": i, "value": divided_val, "operation": f"divide by {divisor}", "description": f"Divide by {divisor}: {added} / {divisor} = {divided_val}", } ) next_val = divided_val divided = True if divisor == primary: primary, secondary = secondary, primary break # 3. ASK (bölünmedi ve added asal) if not divided and isprime(int(round(added))): # Yön belirleme if ask_plus_first: delta = 1 if ask_counter == 0 else -1 else: delta = -1 if ask_counter == 0 else 1 adjusted = added + delta if include_intermediate_steps: op_desc = "+1" if delta > 0 else "-1" result.append( { "step": i, "value": adjusted, "operation": "keçeci unit", "description": f"Apply Keçeci unit {op_desc}: {added} {op_desc} = {adjusted}", } ) ask_counter = 1 - ask_counter # ASK sonrası bölme dene (aynı sıra) ask_divided = False for divisor in (primary, secondary): if adjusted % divisor == 0: final_val = adjusted // divisor if include_intermediate_steps: result.append( { "step": i, "value": final_val, "operation": f"divide by {divisor}", "description": f"Divide adjusted by {divisor}: {adjusted} / {divisor} = {final_val}", } ) next_val = final_val ask_divided = True if divisor == primary: primary, secondary = secondary, primary break if not ask_divided: next_val = adjusted # 4. Sonraki adım için güncelle current = next_val if not include_intermediate_steps: result.append(current) return result def _get_default_value_for_type(value: Any) -> Any: """Get default value for a given type.""" if isinstance(value, (int, float)): return 0 elif isinstance(value, complex): return complex(0, 0) elif isinstance(value, tuple): return tuple(0 for _ in value) elif hasattr(value, "__class__"): try: return type(value)() except: return 0 else: return 0 # ------------------------------------------------------------ # 2. YARDIMCI FONKSİYONLAR # ------------------------------------------------------------ def flatten_sequence(seq): if not seq: return [] if isinstance(seq[0], dict): return [item["value"] for item in seq] return seq def find_first_occurrence(flat, block): """Bloğun düz listede ilk görüldüğü indeksi bulur.""" len_block = len(block) for i in range(len(flat) - len_block + 1): if flat[i : i + len_block] == block: return i return -1 def is_prime_value(v): try: iv = int(round(v)) if isinstance(v, float) else int(v) if iv < 2: return False return isprime(iv) except: return False def find_cycle_with_earliest_start(seq, min_repeats=3): """ Kararlı periyot bloğunu bulur (en az min_repeats tekrar). Ardından bu bloğun tüm dönel kaymaları içinde, dizide en küçük başlangıç indeksine sahip olanı döndürür. """ flat = flatten_sequence(seq) n = len(flat) # 1. Kararlı periyot uzunluğunu bul (en küçük periyot) period = None for p in range(1, n // min_repeats + 1): last_block = flat[-p:] ok = True for i in range(1, min_repeats): start = -(i + 1) * p end = -i * p if flat[start:end] != last_block: ok = False break if ok: period = p break if period is None: return None, -1, 0 # 2. Kararlı periyot bloğunu al (dizinin sonundaki blok) stable_block = flat[-period:] # 3. Tüm dönel kaymalarını dene; en küçük başlangıç indeksini bul best_start = n best_block = None for rot in range(period): rotated = stable_block[rot:] + stable_block[:rot] first = find_first_occurrence(flat, rotated) if first != -1 and first < best_start: best_start = first best_block = rotated if best_block is None: return stable_block, find_first_occurrence(flat, stable_block), period return best_block, best_start, period # ------------------------------------------------------------ # 3. ASAL ANALİZ FONKSİYONU (en erken başlangıçlı döngüyü kullanır) # ------------------------------------------------------------ def analyze_kececi_primes(sequence: List[Any]) -> Dict[str, Any]: flat = flatten_sequence(sequence) # Döngü bloğunu ve en erken başlangıç indeksini bul cycle_block, first_cycle_start, period_len = find_cycle_with_earliest_start( sequence ) if cycle_block is None: return { "full_sequence": flat, "first_cycle_start": -1, "period_len": 0, "cycle_block": None, "kpn": None, "first_prime_in_sequence": None, "smallest_prime": None, "largest_prime": None, "most_frequent_prime": (None, 0), "least_frequent_prime": (None, 0), "primes_in_cycle": [], "all_primes_in_sequence": [], "last_prime_in_cycle": None, } # Döngü içindeki asallar cycle_primes = [v for v in cycle_block if is_prime_value(v)] kpn_val = cycle_primes[0] if cycle_primes else None if kpn_val is not None: block_index = cycle_block.index(kpn_val) kpn_idx = first_cycle_start + block_index else: kpn_idx = None last_prime_in_cycle = cycle_primes[-1] if cycle_primes else None primes_in_cycle = sorted(set(cycle_primes)) if cycle_primes else [] # Tüm dizideki asallar all_primes = [] prime_counter = Counter() first_prime_idx = None first_prime_val = None for idx, val in enumerate(flat): if is_prime_value(val): all_primes.append(val) prime_counter[val] += 1 if first_prime_idx is None: first_prime_idx = idx first_prime_val = val smallest_prime = min(all_primes) if all_primes else None largest_prime = max(all_primes) if all_primes else None most_common = prime_counter.most_common(1)[0] if prime_counter else (None, 0) least_common = ( min(prime_counter.items(), key=lambda x: x[1]) if prime_counter else (None, 0) ) all_primes_unique = sorted(set(all_primes)) if all_primes else [] return { "full_sequence": flat, "first_cycle_start": first_cycle_start, "period_len": period_len, "cycle_block": cycle_block, "kpn": (kpn_val, kpn_idx) if kpn_val is not None else None, "first_prime_in_sequence": (first_prime_val, first_prime_idx) if first_prime_val is not None else None, "smallest_prime": smallest_prime, "largest_prime": largest_prime, "most_frequent_prime": (most_common[0], most_common[1]), "least_frequent_prime": (least_common[0], least_common[1]), "primes_in_cycle": primes_in_cycle, "all_primes_in_sequence": all_primes_unique, "last_prime_in_cycle": last_prime_in_cycle, } def find_stable_period(seq, min_repeats=3): """Dizinin sonundan itibaren en az min_repeats kez tekrar eden periyodu bulur.""" flat = flatten_sequence(seq) n = len(flat) for period in range(1, n // min_repeats + 1): last_block = flat[-period:] ok = True for i in range(1, min_repeats): start = -(i + 1) * period end = -i * period if flat[start:end] != last_block: ok = False break if ok: start_idx = n - min_repeats * period return last_block, start_idx, period return None, -1, 0 # ------------------------------------------------------------ # 3. VARYASYON TESTİ (her iki mod için çalışır) # ------------------------------------------------------------ def run_variation_test(include_intermediate_steps=True, steps=100): variations = [ ("V1: Önce 3, ASK +1/-1", 3, True), ("V2: Önce 3, ASK -1/+1", 3, False), ("V3: Önce 2, ASK +1/-1", 2, True), ("V4: Önce 2, ASK -1/+1", 2, False), ] results = [] for name, first_div, ask_plus in variations: seq = _generate_ask_sequence_complete( start_value=0, add_value=9, iterations=steps, include_intermediate_steps=include_intermediate_steps, number_type=1, first_divisor=first_div, ask_plus_first=ask_plus, ) flat = flatten_sequence(seq) # Kararlı periyot bloğunu bul (dizinin sonundaki stabil döngü) period_block, _, period_len = find_stable_period(seq, min_repeats=3) if period_block: # Bloğun dizide ilk görüldüğü yer = döngü başlangıcı cycle_start = find_first_occurrence(flat, period_block) # KPN: sadece döngü bloğu içindeki ilk asal kpn = next( ( v for v in period_block if isinstance(v, (int, float)) and v > 1 and isprime(int(v)) ), None, ) else: period_block = None cycle_start = -1 period_len = 0 kpn = None results.append( { "name": name, "seq": seq, "cycle_start": cycle_start, "period_len": period_len, "period_block": period_block, "kpn": kpn, } ) return results def print_results(results, max_display=60): for res in results: print(f"\n{res['name']}") print("-" * 50) flat = flatten_sequence(res["seq"]) for i, v in enumerate(flat[:max_display]): print(f"{i:3d}: {v}") if len(flat) > max_display: print(f"... (devamı {len(flat) - max_display} adım daha)") def plot_results(results, max_steps=100): fig, axes = plt.subplots(2, 2, figsize=(16, 12)) axes = axes.flatten() for idx, res in enumerate(results): ax = axes[idx] flat = flatten_sequence(res["seq"])[:max_steps] x = np.arange(len(flat)) ax.plot(x, flat, "k-", lw=0.6, alpha=0.4, label="Tüm dizi") if res["cycle_start"] != -1: cs = res["cycle_start"] pl = res["period_len"] end1 = cs + pl end2 = min(end1 + pl, len(flat)) # İlk periyot kırmızı kalın ax.plot(x[cs:end1], flat[cs:end1], "r-", lw=2.5, label="İlk periyot") # Tekrar eden periyot (ikinci periyot) mavi kesik if end2 > end1: ax.plot( x[end1:end2], flat[end1:end2], "b--", lw=2, label="Tekrar eden periyot", ) # Döngü bölgesi arka planı (iki periyot) ax.axvspan(cs, end1 + pl, alpha=0.15, color="red", label="Döngü bölgesi") # KPN yıldızı – döngü bloğunun ilk periyodundaki konumu if res["kpn"] is not None and res["kpn"] in flat: # Döngü bloğunun ilk periyodu flat[cs:cs+pl] içinde ara block = flat[cs : cs + pl] if res["kpn"] in block: idx_kpn = cs + block.index(res["kpn"]) ax.plot( idx_kpn, res["kpn"], "*", color="gold", markersize=14, label=f"KPN={res['kpn']}", ) ax.set_title(res["name"], fontsize=12, fontweight="bold") ax.set_xlabel("Adım") ax.set_ylabel("Değer") ax.grid(True, linestyle=":", alpha=0.4) ax.legend(loc="upper right", fontsize=8) plt.suptitle( "Keçeci Varyasyonları – İlk periyot ve tekrarı (start=0, add=9)", fontsize=16, fontweight="bold", ) plt.tight_layout() plt.show() """ def _generate_ask_sequence_complete_hata( start_value: Any, add_value: Any, iterations: int, include_intermediate_steps: bool = True, number_type: int = 1 ) -> List[Any]: #Complete ASK algorithm implementation for all number types. #Steps: Add, check division by 2/3, apply Keçeci unit if prime-like. # Get appropriate ask_unit for the number type ask_unit = _get_ask_unit_for_type(number_type, start_value) result = [] current = start_value ask_counter = 0 # 0: +ask_unit, 1: -ask_unit if include_intermediate_steps: result.append({ "step": 0, "value": current, "operation": "start", "description": f"Start: {current}" }) # Main ASK loop for i in range(1, iterations): step_log = [] if include_intermediate_steps else None try: # 1. ADDITION added = _safe_add(current, add_value, number_type) if include_intermediate_steps: step_log.append({ "operation": "add", "value": added, "description": f"Add {add_value}: {current} + {add_value} = {added}" }) next_val = added divided = False # 2. CHECK DIVISIBILITY by 2 or 3 for divisor in [2, 3]: try: if _is_divisible_ask(added, divisor, number_type): divided_val = _safe_divide_ask(added, divisor, number_type) if include_intermediate_steps: step_log.append({ "operation": f"divide by {divisor}", "value": divided_val, "description": f"Divide by {divisor}: {added} / {divisor} = {divided_val}" }) next_val = divided_val divided = True break except Exception as e: logger.debug(f"Division by {divisor} failed: {e}") continue # 3. KECEÇI UNIT adjustment if not divided and prime-like if not divided and _is_prime_like_ask(added, number_type): direction = 1 if ask_counter == 0 else -1 try: # Apply Keçeci unit if direction > 0: adjusted = _safe_add(added, ask_unit, number_type) op_desc = f"+{ask_unit}" else: adjusted = _safe_subtract(added, ask_unit, number_type) op_desc = f"-{ask_unit}" if include_intermediate_steps: step_log.append({ "operation": "keçeci unit", "value": adjusted, "description": f"Apply Keçeci unit {op_desc}: {added} {op_desc} = {adjusted}" }) # Toggle ask counter ask_counter = 1 - ask_counter # Try division again on adjusted value for divisor in [2, 3]: try: if _is_divisible_ask(adjusted, divisor, number_type): final_val = _safe_divide_ask(adjusted, divisor, number_type) if include_intermediate_steps: step_log.append({ "operation": f"divide by {divisor}", "value": final_val, "description": f"Divide adjusted by {divisor}: {adjusted} / {divisor} = {final_val}" }) next_val = final_val break except Exception as e: logger.debug(f"Division on adjusted value failed: {e}") continue else: # No division successful, use adjusted value next_val = adjusted except Exception as e: logger.debug(f"Keçeci unit adjustment failed: {e}") # Keep original added value # Update current value current = next_val # Add to result if include_intermediate_steps: # Add all intermediate steps for step in step_log: result.append({ "step": i, "value": step["value"], "operation": step["operation"], "description": step["description"] }) # Add final value for this iteration result.append({ "step": i, "value": current, "operation": "final", "description": f"Iteration {i} final: {current}" }) else: result.append(current) except Exception as e: logger.error(f"Error at iteration {i}: {e}") default_val = _get_default_value_for_type(current, number_type) if include_intermediate_steps: result.append({ "step": i, "value": default_val, "operation": "error", "description": f"ERROR: {e}" }) else: result.append(default_val) current = default_val return result """ def _safe_add(a: Any, b: Any, number_type: int) -> Any: """Safe addition for all types.""" try: return a + b except Exception: # Try alternative methods if hasattr(a, "add"): return a.add(b) elif hasattr(a, "__add__"): return a.__add__(b) else: # For array types if isinstance(a, (list, tuple)) and isinstance(b, (int, float)): return type(a)([x + b for x in a]) elif isinstance(b, (list, tuple)) and isinstance(a, (int, float)): return type(b)([a + x for x in b]) elif isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)): # Element-wise addition size = max(len(a), len(b)) result = [] for i in range(size): val_a = a[i] if i < len(a) else 0 val_b = b[i] if i < len(b) else 0 result.append(val_a + val_b) return type(a)(result) else: raise def _safe_subtract(a: Any, b: Any, number_type: int) -> Any: """Safe subtraction for all types.""" try: return a - b except Exception: if hasattr(a, "subtract"): return a.subtract(b) elif hasattr(a, "__sub__"): return a.__sub__(b) else: # Similar logic to _safe_add but for subtraction if isinstance(a, (list, tuple)) and isinstance(b, (int, float)): return type(a)([x - b for x in a]) elif isinstance(b, (list, tuple)) and isinstance(a, (int, float)): return type(b)([a - x for x in b]) elif isinstance(a, (list, tuple)) and isinstance(b, (list, tuple)): size = max(len(a), len(b)) result = [] for i in range(size): val_a = a[i] if i < len(a) else 0 val_b = b[i] if i < len(b) else 0 result.append(val_a - val_b) return type(a)(result) else: raise def _safe_divide_ask(a: Any, divisor: int, number_type: int) -> Any: """Safe division for ASK algorithm.""" try: return a / divisor except Exception: # Try alternative division methods if hasattr(a, "__truediv__"): return a.__truediv__(divisor) elif hasattr(a, "divide"): return a.divide(divisor) else: # For array types if isinstance(a, (list, tuple)): return type(a)([x / divisor for x in a]) else: # Try to convert to float try: return type(a)(float(a) / divisor) except: raise def _is_divisible_ask(value: Any, divisor: int, number_type: int) -> bool: """ Check divisibility for ASK algorithm. """ try: if isinstance(value, (int, float)): # Check remainder is close to zero remainder = value % divisor return abs(remainder) < 1e-10 elif isinstance(value, complex): # Check both real and imaginary parts real_rem = value.real % divisor imag_rem = value.imag % divisor return abs(real_rem) < 1e-10 and abs(imag_rem) < 1e-10 elif isinstance(value, (list, tuple)): # For array types, check first element as representative if value: return _is_divisible_ask(value[0], divisor, number_type) else: return True elif isinstance(value, tuple) and len(value) == 3: # Neutrosophic # Check all components return all(_is_divisible_ask(v, divisor, number_type) for v in value) else: # For other types, assume divisible return True except Exception: # If check fails, assume not divisible return False def _is_prime_like_ask(value: Any, number_type: int) -> bool: """ Check if value is prime-like for ASK algorithm. """ try: if isinstance(value, (int, float)): v = abs(value) # Simple prime check if v < 2: return False if v == 2 or v == 3: return True if v % 2 == 0 or v % 3 == 0: return False # Check up to sqrt(v) i = 5 while i * i <= v: if v % i == 0 or v % (i + 2) == 0: return False i += 6 return True elif isinstance(value, complex): # Check magnitude mag = abs(value) return _is_prime_like_ask(mag, number_type) elif isinstance(value, (list, tuple)): # For array types, check first non-zero element for v in value: if abs(v) > 1e-10: return _is_prime_like_ask(v, number_type) return False elif isinstance(value, tuple) and len(value) == 3: # Neutrosophic # Check truth component return _is_prime_like_ask(value[0], number_type) else: # For other types, use string representation try: s = str(value) # Extract numbers from string import re numbers = re.findall(r"\d+\.?\d*", s) if numbers: return _is_prime_like_ask(float(numbers[0]), number_type) return False except: return False except Exception: return False """ # Ayrıca, get_with_params fonksiyonunuzu da güncelleyin: def get_with_params( kececi_type_choice: int, iterations: int = 10, start_value_raw: Union[str, float, int] = "0", add_value_raw: Union[str, float, int] = "1.0", operation: str = "ask", # Default ASK algoritması include_intermediate_steps: bool = True, custom_parser: Optional[Callable] = None, ) -> List[Any]: #Unified entry point for generating Keçeci numbers. #Default operation: "ask" (ASK algoritması) logger.info("Generating Keçeci Sequence: Type %s, Steps %s", kececi_type_choice, iterations) logger.debug("Start: %r, Operation: %r with value: %r", start_value_raw, operation, add_value_raw) # Basic input sanitation if start_value_raw is None: start_value_raw = "0" if add_value_raw is None: add_value_raw = "1" # Convert to strings start_str = str(start_value_raw) if not isinstance(start_value_raw, str) else start_value_raw add_str = str(add_value_raw) if not isinstance(add_value_raw, str) else add_value_raw try: # unified_generator'ı operation parametresi ile çağır generated_sequence = unified_generator( kececi_type=kececi_type_choice, start_input_raw=start_str, add_input_raw=add_str, iterations=iterations, include_intermediate_steps=include_intermediate_steps, operation=operation # Operation parametresini ekle ) if not generated_sequence: logger.warning("Sequence generation failed or returned empty for type %s with start=%r add=%r", kececi_type_choice, start_value_raw, add_value_raw) return [] logger.info("Generated %d numbers for type %s", len(generated_sequence), kececi_type_choice) # Preview preview_size = min(5, len(generated_sequence)) if preview_size > 0: preview_start = [str(x) for x in generated_sequence[:preview_size]] logger.debug("First %d: %s", preview_size, preview_start) if len(generated_sequence) > preview_size * 2: preview_end = [str(x) for x in generated_sequence[-preview_size:]] logger.debug("Last %d: %s", preview_size, preview_end) # Keçeci Prime Number check try: kpn = find_kececi_prime_number(generated_sequence) if kpn is not None: logger.info("Keçeci Prime Number (KPN) found: %s", kpn) else: logger.debug("No Keçeci Prime Number found in the sequence.") except Exception as e: logger.debug(f"KPN check skipped or failed: {e}") return generated_sequence except Exception as e: logger.exception("ERROR during sequence generation: %s", e) raise """ """ # Sorunsuz çalışıyor def get_with_params( kececi_type_choice: int, iterations: int, start_value_raw: str, add_value_raw: str, include_intermediate_steps: bool = True ) -> List[Any]: #Common entry point: validates inputs early, logs info instead of printing. from fractions import Fraction logger.info("Generating Keçeci Sequence: Type %s, Steps %s", kececi_type_choice, iterations) logger.debug("Start: %r, Addition: %r, Include intermediate: %s", start_value_raw, add_value_raw, include_intermediate_steps) # Basic input sanitation if start_value_raw is None: start_value_raw = "0" if add_value_raw is None: # choose a conservative default for increment add_value_raw = "1" try: generated_sequence = unified_generator( kececi_type=kececi_type_choice, start_input_raw=start_value_raw, add_input_raw=add_value_raw, iterations=iterations, include_intermediate_steps=include_intermediate_steps ) if not generated_sequence: logger.warning("Sequence generation failed or returned empty for type %s with start=%r add=%r", kececi_type_choice, start_value_raw, add_value_raw) return [] logger.info("Generated %d numbers for type %s", len(generated_sequence), kececi_type_choice) # preview preview_start = [str(x) for x in generated_sequence[:5]] preview_end = [str(x) for x in generated_sequence[-5:]] if len(generated_sequence) > 5 else [] logger.debug("First 5: %s", preview_start) if preview_end: logger.debug("Last 5: %s", preview_end) # Keçeci Prime Number check kpn = find_kececi_prime_number(generated_sequence) if kpn is not None: logger.info("Keçeci Prime Number (KPN) found: %s", kpn) else: logger.info("No Keçeci Prime Number found in the sequence.") return generated_sequence except Exception as e: logger.exception("ERROR during sequence generation: %s", e) return [] """ def generate_kececi_sequence( start_value=0, add_value=9, iterations=100, include_intermediate_steps=True, first_divisor=3, ask_plus_first=True, ) -> List[Any]: """ DÜZELTİLMİŞ Keçeci üretici – sadece tip 1 (Positive Real) için. isprime çağrısı önce int'e çevrilir. """ flat_seq = [start_value] current = start_value asal_count = 0 primary = first_divisor secondary = 2 if primary == 3 else 3 for _ in range(iterations): added = current + add_value if include_intermediate_steps: flat_seq.append(added) val = added divided = False for divisor in (primary, secondary): if val % divisor == 0: val //= divisor if include_intermediate_steps: flat_seq.append(val) divided = True if divisor == primary: primary, secondary = secondary, primary break # DÜZELTME: float'ı int'e çevir if not divided and isprime(int(round(val))): asal_count += 1 if ask_plus_first: delta = 1 if asal_count % 2 == 1 else -1 else: delta = -1 if asal_count % 2 == 1 else 1 val += delta if include_intermediate_steps: flat_seq.append(val) # ASK sonrası bölme dene for divisor in (primary, secondary): if val % divisor == 0: val //= divisor if include_intermediate_steps: flat_seq.append(val) if divisor == primary: primary, secondary = secondary, primary break current = val if not include_intermediate_steps: flat_seq.append(current) return flat_seq """ def generate_kececi_sequence( start_value_raw=0, add_value_raw=9, iterations=100, include_intermediate_steps=False, first_divisor=3, ask_plus_first=True ) -> List[Any]: DÜZELTİLMİŞ Keçeci üretici – sadece tip 1 (Positive Real) için. isprime çağrısı önce int'e çevrilir. flat_seq = [start_value_raw] current = start_value_raw asal_count = 0 primary = first_divisor secondary = 2 if primary == 3 else 3 for _ in range(iterations): added = current + add_value_raw if include_intermediate_steps: flat_seq.append(added) val = added divided = False for divisor in (primary, secondary): if val % divisor == 0: val //= divisor if include_intermediate_steps: flat_seq.append(val) divided = True if divisor == primary: primary, secondary = secondary, primary break # DÜZELTME: float'ı int'e çevir if not divided and isprime(int(round(val))): asal_count += 1 if ask_plus_first: delta = 1 if asal_count % 2 == 1 else -1 else: delta = -1 if asal_count % 2 == 1 else 1 val += delta if include_intermediate_steps: flat_seq.append(val) # ASK sonrası bölme dene for divisor in (primary, secondary): if val % divisor == 0: val //= divisor if include_intermediate_steps: flat_seq.append(val) if divisor == primary: primary, secondary = secondary, primary break current = val if not include_intermediate_steps: flat_seq.append(current) return flat_seq """ """ def generate_kececi_sequence( start_value: Any = 0, add_value: Any = 9, iterations: int = 100, include_intermediate_steps: bool = True, first_divisor: int = 3, ask_plus_first: bool = True ) -> List[Any]: Keçeci dizisi üretir. - include_intermediate_steps=True: her işlem (toplama, bölme, ASK) ayrı sözlük - include_intermediate_steps=False: sadece nihai değerler (düz liste) def add(a, b): return a + b def div(a, d): return a // d def is_divisible(a, d): return a % d == 0 ask_unit = 1 result = [] current = start_value ask_counter = 0 primary = first_divisor secondary = 2 if primary == 3 else 3 if include_intermediate_steps: result.append({ "step": 0, "value": current, "operation": "start", "description": f"Start: {current}" }) for i in range(1, iterations + 1): added = current + add_value if include_intermediate_steps: result.append({ "step": i, "value": added, "operation": "add", "description": f"Add {add_value}: {current} + {add_value} = {added}" }) next_val = added divided = False for divisor in [primary, secondary]: if is_divisible(added, divisor): divided_val = div(added, divisor) if include_intermediate_steps: result.append({ "step": i, "value": divided_val, "operation": f"divide by {divisor}", "description": f"Divide by {divisor}: {added} / {divisor} = {divided_val}" }) next_val = divided_val divided = True if divisor == primary: primary, secondary = secondary, primary break if not divided and isprime(added): if ask_plus_first: delta = 1 if ask_counter == 0 else -1 else: delta = -1 if ask_counter == 0 else 1 adjusted = added + delta * ask_unit if include_intermediate_steps: op_desc = f"+{ask_unit}" if delta > 0 else f"-{ask_unit}" result.append({ "step": i, "value": adjusted, "operation": "keçeci unit", "description": f"Apply Keçeci unit {op_desc}: {added} {op_desc} = {adjusted}" }) ask_counter = 1 - ask_counter ask_divided = False for divisor in [primary, secondary]: if is_divisible(adjusted, divisor): final_val = div(adjusted, divisor) if include_intermediate_steps: result.append({ "step": i, "value": final_val, "operation": f"divide by {divisor}", "description": f"Divide adjusted by {divisor}: {adjusted} / {divisor} = {final_val}" }) next_val = final_val ask_divided = True if divisor == primary: primary, secondary = secondary, primary break if not ask_divided: next_val = adjusted if not include_intermediate_steps: result.append(next_val) current = next_val return result """ def generate_kececi_sequence0( start_value: Any, add_value: Any, iterations: int, operation: str, include_intermediate_steps: bool = True, number_type: str = "Unknown", first_divisor: int = 3, ask_plus_first: bool = True, ) -> List[Any]: # Generate sequence for Keçeci numbers with proper operation handling. if include_intermediate_steps: # Detailed output with steps result = [] current = start_value # Add initial state result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) for i in range(1, iterations): previous = current try: current = _apply_kececi_operation( current, add_value, operation, number_type ) result.append( { "step": i, "value": current, "operation": operation, "previous": previous, "description": f"Step {i}: {previous} {_get_operation_symbol(operation)} {add_value} = {current}", } ) except Exception as e: logger.error(f"Error at step {i}: {e}") result.append( { "step": i, "value": current, "operation": operation, "error": str(e), "description": f"Step {i}: ERROR - {e}", } ) break return result else: # Simple list output result = [start_value] current = start_value for i in range(1, iterations): try: current = _apply_kececi_operation( current, add_value, operation, number_type ) result.append(current) except Exception as e: logger.error(f"Error at iteration {i}: {e}") # Try to continue with a default value default_val = _get_default_value_for_type(current) result.append(default_val) current = default_val return result # get_with_params içinde kullanmak için:
[docs] def get_with_params( kececi_type_choice: int, iterations: int, start_value_raw: str, add_value_raw: str, include_intermediate_steps: bool = True, first_divisor: int = 3, # yeni parametre ask_plus_first: bool = True, # yeni parametre ) -> List[Any]: """ Keçeci sayıları serisi üretir. Args: kececi_type_choice: 1-23 arası tip numarası iterations: adım sayısı start_value_raw: başlangıç değeri (string) add_value_raw: artım değeri (string) include_intermediate_steps: ara adımlar dahil mi? first_divisor: ilk bölen sayısı (varsayılan 3) ask_plus_first: ASK işleminde önce +1 mi? (True=+1 önce, False=-1 önce) Returns: Seri listesi """ return unified_generator( kececi_type=kececi_type_choice, start_input_raw=start_value_raw, add_input_raw=add_value_raw, iterations=iterations, include_intermediate_steps=include_intermediate_steps, first_divisor=first_divisor, ask_plus_first=ask_plus_first, )
""" def get_with_params( kececi_type_choice: int, iterations: int, start_value_raw: str, add_value_raw: str, include_intermediate_steps: bool = True ) -> List[Any]: if kececi_type_choice == 1: # Positive Real start = float(start_value_raw) add = float(add_value_raw) #return generate_kececi_sequence( return _generate_ask_sequence_complete( start_value=start, add_value=add, iterations=iterations, include_intermediate_steps=include_intermediate_steps, first_divisor=3, ask_plus_first=True ) else: # Diğer tipler için mevcut unified_generator'ınızı çağırın return unified_generator(kececi_type_choice, start_value_raw, add_value_raw, iterations, include_intermediate_steps, first_divisor, ask_plus_first) """ """ def get_with_params( kececi_type_choice: int, iterations: int, start_value: str, add_value: str, include_intermediate_steps: bool = True ) -> List[Any]: logger.info("Generating Keçeci Sequence: Type %s, Steps %s", kececi_type_choice, iterations) logger.debug("Start: %r, Addition: %r, Include intermediate: %s", start_value, add_value, include_intermediate_steps) # Basic input sanitation if start_value is None: start_value = "0" if add_value is None: add_value = "1" if kececi_type_choice == TYPE_POSITIVE_REAL: return _generate_ask_sequence_complete( #return generate_kececi_sequence( start_value=float(start_value), add_value=float(add_value), iterations=iterations, include_intermediate_steps=include_intermediate_steps, first_divisor=3, # veya değişken yapın ask_plus_first=True ) else: if not generated_sequence: logger.warning("Sequence generation failed or returned empty for type %s with start=%r add=%r", kececi_type_choice, start_value, add_value) return [] logger.info("Generated %d numbers for type %s", len(generated_sequence), kececi_type_choice) # Preview preview_start = [str(x) for x in generated_sequence[:5]] preview_end = [str(x) for x in generated_sequence[-5:]] if len(generated_sequence) > 5 else [] logger.debug("First 5: %s", preview_start) if preview_end: logger.debug("Last 5: %s", preview_end) # Keçeci Prime Number check kpn = find_kececi_prime_number(generated_sequence) if kpn is not None: logger.info("Keçeci Prime Number (KPN) found: %s", kpn) else: logger.info("No Keçeci Prime Number found in the sequence.") return _generate_ask_sequence_complete """ """ def get_with_params( kececi_type_choice: int, iterations: int, start_value_raw: str, add_value_raw: str, include_intermediate_steps: bool = True ) -> List[Any]: #Common entry point: validates inputs early, logs info instead of printing. logger.info("Generating Keçeci Sequence: Type %s, Steps %s", kececi_type_choice, iterations) logger.debug("Start: %r, Addition: %r, Include intermediate: %s", start_value_raw, add_value_raw, include_intermediate_steps) # Basic input sanitation if start_value_raw is None: start_value_raw = "0" if add_value_raw is None: add_value_raw = "1" try: generated_sequence = unified_generator( kececi_type=kececi_type_choice, start_input_raw=start_value_raw, add_input_raw=add_value_raw, iterations=iterations, include_intermediate_steps=include_intermediate_steps ) if not generated_sequence: logger.warning("Sequence generation failed or returned empty for type %s with start=%r add=%r", kececi_type_choice, start_value_raw, add_value_raw) return [] logger.info("Generated %d numbers for type %s", len(generated_sequence), kececi_type_choice) # Preview preview_start = [str(x) for x in generated_sequence[:5]] preview_end = [str(x) for x in generated_sequence[-5:]] if len(generated_sequence) > 5 else [] logger.debug("First 5: %s", preview_start) if preview_end: logger.debug("Last 5: %s", preview_end) # Keçeci Prime Number check kpn = find_kececi_prime_number(generated_sequence) if kpn is not None: logger.info("Keçeci Prime Number (KPN) found: %s", kpn) else: logger.info("No Keçeci Prime Number found in the sequence.") return generated_sequence except Exception as e: logger.exception("ERROR during sequence generation: %s", e) return [] """ """ def get_with_params( kececi_type_choice: int, iterations: int = 10, start_value_raw: Union[str, float, int] = "0", add_value_raw: Union[str, float, int] = "1.0", operation: str = "add", include_intermediate_steps: bool = True, custom_parser: Optional[Any] = None, ) -> List[Any]: #Unified entry point for generating Keçeci numbers based on specified parameters. logger.info("Generating Keçeci Sequence: Type %s, Steps %s", kececi_type_choice, iterations) logger.debug("Start: %r, Operation: %r with value: %r, Include intermediate: %s", start_value_raw, operation, add_value_raw, include_intermediate_steps) # Basic input sanitation if start_value_raw is None: start_value_raw = "0" if add_value_raw is None: add_value_raw = "1" # Convert to strings for unified_generator start_str = str(start_value_raw) if not isinstance(start_value_raw, str) else start_value_raw add_str = str(add_value_raw) if not isinstance(add_value_raw, str) else add_value_raw try: # unified_generator'ı operation parametresi ile çağır generated_sequence = unified_generator( kececi_type=kececi_type_choice, start_input_raw=start_str, add_input_raw=add_str, iterations=iterations, include_intermediate_steps=include_intermediate_steps, operation=operation # operation parametresini ekle ) if not generated_sequence: logger.warning("Sequence generation failed or returned empty for type %s with start=%r add=%r", kececi_type_choice, start_value_raw, add_value_raw) return [] logger.info("Generated %d numbers for type %s", len(generated_sequence), kececi_type_choice) # Preview preview_size = min(5, len(generated_sequence)) if preview_size > 0: preview_start = [str(x) for x in generated_sequence[:preview_size]] logger.debug("First %d: %s", preview_size, preview_start) if len(generated_sequence) > preview_size * 2: preview_end = [str(x) for x in generated_sequence[-preview_size:]] logger.debug("Last %d: %s", preview_size, preview_end) # Keçeci Prime Number check try: kpn = find_kececi_prime_number(generated_sequence) if kpn is not None: logger.info("Keçeci Prime Number (KPN) found: %s", kpn) else: logger.debug("No Keçeci Prime Number found in the sequence.") except Exception as e: logger.debug(f"KPN check skipped or failed: {e}") return generated_sequence except Exception as e: logger.exception("ERROR during sequence generation: %s", e) raise """ """ # 2. tray bloğu ask kurallarını uygulamıyor def get_with_params( kececi_type_choice: int, iterations: int = 10, start_value_raw: Union[str, float, int] = "0", add_value_raw: Union[str, float, int] = "1.0", operation: str = "add", include_intermediate_steps: bool = True, custom_parser: Optional[Callable] = None, ) -> List[Any]: #Unified entry point for generating Keçeci numbers based on specified parameters. from fractions import Fraction # Log the start of generation logger.info( "Generating Keçeci Sequence: Type %s, Steps %s", kececi_type_choice, iterations ) logger.debug( "Start: %r, Operation: %r with value: %r, Include intermediate: %s", start_value_raw, operation, add_value_raw, include_intermediate_steps, ) # Basic input sanitation and type conversion if start_value_raw is None: start_value_raw = "0" if add_value_raw is None: if operation == "add": add_value_raw = "1" elif operation == "multiply": add_value_raw = "2" else: add_value_raw = "1" # Validate operation valid_operations = ["add", "multiply", "subtract", "divide", "mod", "power"] if operation not in valid_operations: raise ValueError( f"Invalid operation: {operation}. Must be one of {valid_operations}" ) # Validate iterations if iterations < 1: logger.warning(f"Invalid iterations value: {iterations}, using default 10") iterations = 10 try: generated_sequence = unified_generator( kececi_type=kececi_type_choice, start_input_raw=start_value_raw, add_input_raw=add_value_raw, iterations=iterations, include_intermediate_steps=include_intermediate_steps ) if not generated_sequence: logger.warning("Sequence generation failed or returned empty for type %s with start=%r add=%r", kececi_type_choice, start_value_raw, add_value_raw) return [] logger.info("Generated %d numbers for type %s", len(generated_sequence), kececi_type_choice) # preview preview_start = [str(x) for x in generated_sequence[:5]] preview_end = [str(x) for x in generated_sequence[-5:]] if len(generated_sequence) > 5 else [] logger.debug("First 5: %s", preview_start) if preview_end: logger.debug("Last 5: %s", preview_end) # Keçeci Prime Number check kpn = find_kececi_prime_number(generated_sequence) if kpn is not None: logger.info("Keçeci Prime Number (KPN) found: %s", kpn) else: logger.info("No Keçeci Prime Number found in the sequence.") return generated_sequence except Exception as e: logger.exception("ERROR during sequence generation: %s", e) return [] """ """ try: # Import parsers and number classes try: from .kececinumbers import ( # Parsers _parse_bicomplex, _parse_chingon, _parse_clifford, _parse_complex, _parse_complex_like_string, _parse_dual, _parse_engineering_notation, _parse_fraction, _parse_hyperreal, _parse_neutrosophic, _parse_neutrosophic_bicomplex, _parse_neutrosophic_complex, _parse_octonion, _parse_pathion, _parse_quaternion, _parse_quaternion_from_csv, _parse_real, _parse_routon, _parse_sedenion, _parse_splitcomplex, _parse_super_real, _parse_superreal, _parse_ternary, _parse_hypercomplex, _parse_universal, _parse_voudon, _generate_simple_ask_sequence, _parse_with_fallback_simple, _parse_kececi_values, parse_to_hyperreal, parse_to_neutrosophic, ) parsers_available = True except ImportError as e: logger.warning(f"Import error: {e}. Using fallback parsers") parsers_available = False # FIX: Define _parse_complex properly before using it def _parse_complex(s: Union[str, float, int]) -> complex: #Fallback complex parser that handles strings like '2+3j'. if isinstance(s, complex): return s if isinstance(s, (int, float)): return complex(s) s_str = str(s).strip() try: # Try Python's built-in complex parser first return complex(s_str) except ValueError: # Try alternative formats s_str = s_str.replace('i', 'j').replace('J', 'j') # Handle format: "real,imag" if ',' in s_str: parts = s_str.split(',') if len(parts) == 2: try: return complex(float(parts[0]), float(parts[1])) except: pass # Handle format: "real+imagj" if '+' in s_str and 'j' in s_str: # Remove any spaces s_str = s_str.replace(' ', '') if 'j' in s_str: # Split by '+' but be careful with signs parts = s_str.split('+') if len(parts) == 2: try: real_part = parts[0] imag_part = parts[1] # Remove 'j' from imag part if imag_part.endswith('j'): imag_part = imag_part[:-1] return complex(float(real_part), float(imag_part)) except: pass # If all else fails, try to parse as float for real part try: return complex(float(s_str), 0) except: return complex(0, 0) # Define _parse_fraction with complex handling def _parse_fraction(s: Union[str, float, int]) -> float: #Fallback fraction parser that handles complex numbers if isinstance(s, (int, float)): return float(s) s_str = str(s).strip() if not s_str: return 0.0 # First, try to handle complex numbers try: # Use our _parse_complex function c = _parse_complex(s_str) if c.imag != 0: logger.warning(f"Complex number {s_str} for fraction parsing; using real part only.") return float(c.real) else: return float(c.real) except: pass # Try as float try: return float(s_str) except ValueError: pass # Try fractions if '/' in s_str: try: num, den = s_str.split('/') return float(num) / float(den) if float(den) != 0 else float('inf') except: pass # Last resort try: return float(s_str) except: raise ValueError(f"Could not parse as number: {s_str}") # Simple fallbacks for other types _parse_neutrosophic = lambda s: (_parse_fraction(s), 0.0, 0.0) _parse_bicomplex = lambda s: complex(_parse_fraction(s), 0) _parse_neutrosophic_complex = lambda s: complex(_parse_fraction(s), 0) _parse_neutrosophic_bicomplex = lambda s: complex(_parse_fraction(s), 0) _parse_quaternion = lambda s: _parse_fraction(s) _parse_octonion = lambda s: _parse_fraction(s) _parse_sedenion = lambda s: _parse_fraction(s) _parse_clifford = lambda s: _parse_fraction(s) _parse_dual = lambda s: _parse_fraction(s) _parse_splitcomplex = lambda s: _parse_fraction(s) _parse_pathion = lambda s: _parse_fraction(s) _parse_chingon = lambda s: _parse_fraction(s) _parse_routon = lambda s: _parse_fraction(s) _parse_voudon = lambda s: _parse_fraction(s) _parse_super_real = lambda s: _parse_fraction(s) _parse_ternary = lambda s: _parse_fraction(s) _parse_hyperreal = lambda s: _parse_fraction(s) # Map type choices to parsers type_to_parser = { 1: {"parser": _parse_fraction, "name": "Positive Real"}, 2: {"parser": lambda s: -_parse_fraction(s), "name": "Negative Real"}, 3: {"parser": _parse_complex, "name": "Complex"}, 4: {"parser": _parse_fraction, "name": "Float"}, 5: {"parser": _parse_fraction, "name": "Rational"}, 6: {"parser": _parse_quaternion, "name": "Quaternion"}, 7: {"parser": _parse_neutrosophic, "name": "Neutrosophic"}, 8: {"parser": _parse_neutrosophic_complex, "name": "Neutrosophic Complex"}, 9: {"parser": _parse_hyperreal, "name": "Hyperreal"}, 10: {"parser": _parse_bicomplex, "name": "Bicomplex"}, 11: {"parser": _parse_neutrosophic_bicomplex, "name": "Neutrosophic Bicomplex"}, 12: {"parser": _parse_octonion, "name": "Octonion"}, 13: {"parser": _parse_sedenion, "name": "Sedenion"}, 14: {"parser": _parse_clifford, "name": "Clifford"}, 15: {"parser": _parse_dual, "name": "Dual"}, 16: {"parser": _parse_splitcomplex, "name": "Split-Complex"}, 17: {"parser": _parse_pathion, "name": "Pathion"}, 18: {"parser": _parse_chingon, "name": "Chingon"}, 19: {"parser": _parse_routon, "name": "Routon"}, 20: {"parser": _parse_voudon, "name": "Voudon"}, 21: {"parser": _parse_super_real, "name": "Super Real"}, 22: {"parser": _parse_ternary, "name": "Ternary"}, } # Add custom parser if provided if custom_parser is not None: logger.debug("Using custom parser provided by user") parser_func = cast(Callable[[Any], Any], custom_parser) type_name = "Custom" else: if kececi_type_choice not in type_to_parser: raise ValueError( f"Invalid type choice: {kececi_type_choice}. Must be 1-22" ) type_info = type_to_parser[kececi_type_choice] parser_func = cast(Callable[[Any], Any], type_info["parser"]) type_name = cast(str, type_info["name"]) logger.info(f"Generating {type_name} numbers (type {kececi_type_choice})") # Parse start and add values try: # Debug logging logger.debug(f"Parsing start_value_raw: {repr(start_value_raw)} with parser {parser_func.__name__ if hasattr(parser_func, '__name__') else type(parser_func).__name__}") logger.debug(f"Parsing add_value_raw: {repr(add_value_raw)}") start_value = parser_func(start_value_raw) add_value = parser_func(add_value_raw) logger.debug( f"Parsed start value: {repr(start_value)} (type: {type(start_value)})" ) logger.debug( f"Parsed operation value: {repr(add_value)} (type: {type(add_value)})" ) except Exception as e: logger.error( f"Parsing failed. Start type: {type(start_value_raw)}, Start value: {repr(start_value_raw)}" ) logger.error( f"Parsing failed. Add type: {type(add_value_raw)}, Add value: {repr(add_value_raw)}" ) raise ValueError( f"Failed to parse values. Start: '{start_value_raw}', Add: '{add_value_raw}'. Error: {str(e)}" ) # Generate the sequence result = _generate_kececi_sequence( start_value=start_value, add_value=add_value, iterations=iterations, operation=operation, include_intermediate_steps=include_intermediate_steps, number_type=type_name ) if not result: logger.warning("Sequence generation failed or returned empty") return [] # Log generation results logger.info(f"Generated {len(result)} numbers for type {type_name}") # Preview first and last few elements preview_size = min(3, len(result)) if preview_size > 0: preview_start = [ str(x)[:50] + "..." if len(str(x)) > 50 else str(x) for x in result[:preview_size] ] logger.debug(f"First {preview_size}: {preview_start}") if len(result) > preview_size * 2: preview_end = [ str(x)[:50] + "..." if len(str(x)) > 50 else str(x) for x in result[-preview_size:] ] logger.debug(f"Last {preview_size}: {preview_end}") # Keçeci Prime Number check try: kpn = _find_kececi_prime_number(result) if kpn is not None: logger.info(f"Keçeci Prime Number (KPN) found: {kpn}") else: logger.debug("No Keçeci Prime Number found in the sequence.") except Exception as e: logger.debug(f"KPN check skipped or failed: {e}") return result except Exception as e: logger.exception(f"ERROR during sequence generation: {e}") raise """ # Yardımcı fonksiyonlar def _generate_kececi_sequence( start_value: Any, add_value: Any, iterations: int, operation: str, include_intermediate_steps: bool = True, number_type: str = "Unknown", ) -> List[Any]: """ Generate sequence for Keçeci numbers with proper operation handling. """ if include_intermediate_steps: # Detailed output with steps result = [] current = start_value # Add initial state result.append( { "step": 0, "value": current, "operation": "start", "description": f"Start: {current}", } ) for i in range(1, iterations): previous = current try: current = _apply_kececi_operation( current, add_value, operation, number_type ) result.append( { "step": i, "value": current, "operation": operation, "previous": previous, "description": f"Step {i}: {previous} {_get_operation_symbol(operation)} {add_value} = {current}", } ) except Exception as e: logger.error(f"Error at step {i}: {e}") result.append( { "step": i, "value": current, "operation": operation, "error": str(e), "description": f"Step {i}: ERROR - {e}", } ) break return result else: # Simple list output result = [start_value] current = start_value for i in range(1, iterations): try: current = _apply_kececi_operation( current, add_value, operation, number_type ) result.append(current) except Exception as e: logger.error(f"Error at iteration {i}: {e}") # Try to continue with a default value default_val = _get_default_value_for_type(current) result.append(default_val) current = default_val return result def _get_default_value_for_type(value: Any) -> Any: """Get default value for a given type.""" if isinstance(value, (int, float)): return 0 elif isinstance(value, complex): return complex(0, 0) elif isinstance(value, tuple): return tuple(0 for _ in value) elif hasattr(value, "__class__"): try: return type(value)() except: return 0 else: return 0 # Örnek: farklı boyutlarda hypercomplex default stringleri def hypercomplex_str(dim, first=1.0, rest=0.0, complex_components=False): """ dim: bileşen sayısı first: ilk bileşen değeri rest: diğer bileşenlerin değeri complex_components: True ise bileşenleri 'a+bj' formatında üretir (örnek) """ comps = [] for i in range(dim): if i == 0: v = first else: v = rest if complex_components: # örnek: ilk iki bileşeni karmaşık yap if i % 2 == 0: comps.append(f"{float(v)}+{float(v) / 10}j") else: comps.append(f"{float(v)}") else: comps.append(str(float(v))) return ",".join(comps) # Kullanım örnekleri hc8 = hypercomplex_str(8, first=1.0, rest=0.0) # "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0" hc16 = hypercomplex_str(16, first=1.0, rest=0.0) hc256 = hypercomplex_str(256, first=1.0, rest=0.0) hc8_complex = hypercomplex_str(8, first=1.0, rest=0.0, complex_components=True) import logging logger = logging.getLogger(__name__)
[docs] def get_interactive( auto_values: Optional[Dict[str, str]] = None, ) -> Tuple[List[Any], Dict[str, Any]]: """ Interactively (or programmatically via auto_values) gets parameters to generate a Keçeci sequence. """ def _ask(key: str, prompt: str, default: str) -> str: if auto_values and key in auto_values: return str(auto_values[key]) try: return input(prompt).strip() or default except Exception: logger.debug( "input() failed for prompt %r — using default %r", prompt, default ) return default interactive_mode = auto_values is None logger.info( "Keçeci Numbers Interactive Generator (interactive=%s)", interactive_mode ) if interactive_mode: menu_lines = [ " 1: Positive Real 2: Negative Real 3: Complex", " 4: Float 5: Rational 6: Quaternion", " 7: Neutrosophic 8: Neutro-Complex 9: Hyperreal", " 10: Bicomplex 11: Neutro-Bicomplex 12: Octonion", " 13: Sedenion 14: Clifford 15: Dual", " 16: Split-Complex 17: Pathion 18: Chingon", " 19: Routon 20: Voudon 21: SuperReal", " 22: Ternary 23: Hypercomplex", # düzeltilmiş satır ] logger.info("Available Keçeci Number Types:") for line in menu_lines: logger.info(line) DEFAULT_TYPE = 1 DEFAULT_STEPS = 30 DEFAULT_SHOW_DETAILS = "yes" default_start_values = { 1: "0", 2: "-5.0", 3: "1+1j", 4: "3.14", 5: "3.5", 6: "1.0,0.0,0.0,0.0", 7: "0.6,0.2,0.1", 8: "1+1j", 9: "1.0", 10: "1.34,2.55,0.25,4.61", 11: "2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 12: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 13: "1.0" + ",0.0" * 15, 14: "1.0+2.0e1+3.0e12", 15: "1.0,0.1", 16: "1.0,0.5", 17: "1.0" + ",0.0" * 31, 18: "1.0" + ",0.0" * 63, 19: "1.0" + ",0.0" * 127, 20: "1.0" + ",0.0" * 255, 21: "12.85,0.08", 22: "11", 23: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0", } default_add_values = { 1: "9", 2: "-0.5", 3: "0.1+0.1j", 4: "0.1", 5: "0.1", 6: "0.1,0.0,0.0,0.0", 7: "0.1,0.0,0.0", 8: "0.1+0.1j", 9: "2.0", 10: "0.08,0.0,0.0,0.0", 11: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 12: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 13: "0.1" + ",0.0" * 15, 14: "0.1+0.2e1", 15: "0.1,0.0", 16: "0.1,0.0", 17: "1.0" + ",0.0" * 31, 18: "1.0" + ",0.0" * 63, 19: "1.0" + ",0.0" * 127, 20: "1.0" + ",0.0" * 255, 21: "0.56,1.7", 22: "22", 23: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0", } type_input_raw = _ask( "type_choice", f"Select Keçeci Number Type (1-23) [default: {DEFAULT_TYPE}]: ", str(DEFAULT_TYPE), ) try: type_choice = int(type_input_raw) if not (1 <= type_choice <= 23): logger.warning( "Invalid type_choice %r, using default %s", type_choice, DEFAULT_TYPE ) type_choice = DEFAULT_TYPE except Exception: logger.warning( "Could not parse type_choice %r, using default %s", type_input_raw, DEFAULT_TYPE, ) type_choice = DEFAULT_TYPE start_prompt = _ask( "start_val", f"Enter start value [default: {default_start_values[type_choice]}]: ", default_start_values[type_choice], ) add_prompt = _ask( "add_val", f"Enter increment value [default: {default_add_values[type_choice]}]: ", default_add_values[type_choice], ) steps_raw = _ask( "steps", f"Enter number of Keçeci steps [default: {DEFAULT_STEPS}]: ", str(DEFAULT_STEPS), ) try: num_kececi_steps = int(steps_raw) if num_kececi_steps <= 0: logger.warning( "Non-positive steps %r, using default %d", num_kececi_steps, DEFAULT_STEPS, ) num_kececi_steps = DEFAULT_STEPS except Exception: logger.warning( "Could not parse steps %r, using default %d", steps_raw, DEFAULT_STEPS ) num_kececi_steps = DEFAULT_STEPS show_detail_raw = _ask( "show_details", f"Include intermediate steps? (y/n) [default: {DEFAULT_SHOW_DETAILS}]: ", DEFAULT_SHOW_DETAILS, ) show_details = str(show_detail_raw).strip().lower() in ["y", "yes"] # Bu çağrı, daha önce patchlediğimiz unified_generator'ı kullanır sequence = get_with_params( kececi_type_choice=type_choice, iterations=num_kececi_steps, start_value_raw=start_prompt, add_value_raw=add_prompt, include_intermediate_steps=show_details, ) params = { "type_choice": type_choice, "start_val": start_prompt, "add_val": add_prompt, "steps": num_kececi_steps, "detailed_view": show_details, } logger.info( "Using parameters: Type=%s, Start=%r, Add=%r, Steps=%s, Details=%s", type_choice, start_prompt, add_prompt, num_kececi_steps, show_details, ) return sequence, params
""" def get_interactive( auto_values: Optional[Dict[str, str]] = None, ) -> Tuple[List[Any], Dict[str, Any]]: Interactively (or programmatically via auto_values) gets parameters to generate a Keçeci sequence. If auto_values is provided, keys can include: 'type_choice' (int or str), 'start_val' (str), 'add_val' (str), 'steps' (int or str), 'show_details' ('y'/'n'). If auto_values is None, function behaves interactively and prints a type menu. # Local prompt function: use auto_values if present otherwise input() def _ask(key: str, prompt: str, default: str) -> str: if auto_values and key in auto_values: return str(auto_values[key]) try: return input(prompt).strip() or default except Exception: # In non-interactive contexts where input is not available, use default logger.debug( "input() failed for prompt %r — using default %r", prompt, default ) return default interactive_mode = auto_values is None logger.info( "Keçeci Numbers Interactive Generator (interactive=%s)", interactive_mode ) # If interactive, present the full menu of type options so users see 1-22 choices if interactive_mode: menu_lines = [ " 1: Positive Real 2: Negative Real 3: Complex", " 4: Float 5: Rational 6: Quaternion", " 7: Neutrosophic 8: Neutro-Complex 9: Hyperreal", " 10: Bicomplex 11: Neutro-Bicomplex 12: Octonion", " 13: Sedenion 14: Clifford 15: Dual", " 16: Split-Complex 17: Pathion 18: Chingon", " 19: Routon 20: Voudon 21: SuperReal", " 22: Ternary, 23: Hypercomplex", ] logger.info("Available Keçeci Number Types:") for line in menu_lines: logger.info(line) # Defaults DEFAULT_TYPE = 1 DEFAULT_STEPS = 30 DEFAULT_SHOW_DETAILS = "yes" default_start_values = { 1: "0", 2: "-5.0", 3: "1+1j", 4: "3.14", 5: "3.5", # 1: "2.5" 6: "1.0,0.0,0.0,0.0", 7: "0.6,0.2,0.1", 8: "1+1j", 9: "1.0", 10: "1.34,2.55,0.25,4.61", 11: "2.5,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 12: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 13: "1.0" + ",0.0" * 15, 14: "1.0+2.0e1+3.0e12", 15: "1.0,0.1", 16: "1.0,0.5", 17: "1.0" + ",0.0" * 31, 18: "1.0" + ",0.0" * 63, 19: "1.0" + ",0.0" * 127, 20: "1.0" + ",0.0" * 255, 21: "12.85,0.08", 22: "11", 23: "1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0", } default_add_values = { 1: "9", 2: "-0.5", 3: "0.1+0.1j", 4: "0.1", 5: "0.1", # 1: "0.5" 6: "0.1,0.0,0.0,0.0", 7: "0.1,0.0,0.0", 8: "0.1+0.1j", 9: "2.0", 10: "0.08,0.0,0.0,0.0", 11: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 12: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0", 13: "0.1" + ",0.0" * 15, 14: "0.1+0.2e1", 15: "0.1,0.0", 16: "0.1,0.0", 17: "1.0" + ",0.0" * 31, 18: "1.0" + ",0.0" * 63, 19: "1.0" + ",0.0" * 127, 20: "1.0" + ",0.0" * 255, 21: "0.56,1.7", 22: "22", 23: "0.1,0.0,0.0,0.0,0.0,0.0,0.0,0.0", } # Ask for inputs (uses _ask which respects auto_values when provided) type_input_raw = _ask( "type_choice", f"Select Keçeci Number Type (1-23) [default: {DEFAULT_TYPE}]: ", str(DEFAULT_TYPE), ) try: type_choice = int(type_input_raw) if not (1 <= type_choice <= 23): logger.warning( "Invalid type_choice %r, using default %s", type_choice, DEFAULT_TYPE ) type_choice = DEFAULT_TYPE except Exception: logger.warning( "Could not parse type_choice %r, using default %s", type_input_raw, DEFAULT_TYPE, ) type_choice = DEFAULT_TYPE start_prompt = _ask( "start_val", f"Enter start value [default: {default_start_values[type_choice]}]: ", default_start_values[type_choice], ) add_prompt = _ask( "add_val", f"Enter increment value [default: {default_add_values[type_choice]}]: ", default_add_values[type_choice], ) steps_raw = _ask( "steps", f"Enter number of Keçeci steps [default: {DEFAULT_STEPS}]: ", str(DEFAULT_STEPS), ) try: num_kececi_steps = int(steps_raw) if num_kececi_steps <= 0: logger.warning( "Non-positive steps %r, using default %d", num_kececi_steps, DEFAULT_STEPS, ) num_kececi_steps = DEFAULT_STEPS except Exception: logger.warning( "Could not parse steps %r, using default %d", steps_raw, DEFAULT_STEPS ) num_kececi_steps = DEFAULT_STEPS show_detail_raw = _ask( "show_details", f"Include intermediate steps? (y/n) [default: {DEFAULT_SHOW_DETAILS}]: ", DEFAULT_SHOW_DETAILS, ) show_details = str(show_detail_raw).strip().lower() in ["y", "yes"] sequence = get_with_params( kececi_type_choice=type_choice, iterations=num_kececi_steps, start_value_raw=start_prompt, add_value_raw=add_prompt, include_intermediate_steps=show_details, ) params = { "type_choice": type_choice, "start_val": start_prompt, "add_val": add_prompt, "steps": num_kececi_steps, "detailed_view": show_details, } logger.info( "Using parameters: Type=%s, Start=%r, Add=%r, Steps=%s, Details=%s", type_choice, start_prompt, add_prompt, num_kececi_steps, show_details, ) return sequence, params """ # ============================================================================== # --- ANALYSIS AND PLOTTING --- # ============================================================================== def find_period(sequence: List[Any], min_repeats: int = 3) -> Optional[List[Any]]: """ Checks if the end of a sequence has a repeating cycle (period). Args: sequence: The list of numbers to check. min_repeats: How many times the cycle must repeat to be considered stable. Returns: The repeating cycle as a list if found, otherwise None. """ if len(sequence) < 4: # Çok kısa dizilerde periyot aramak anlamsız return None # Olası periyot uzunluklarını dizinin yarısına kadar kontrol et for p_len in range(1, len(sequence) // min_repeats): # Dizinin sonundan potansiyel döngüyü al candidate_cycle = sequence[-p_len:] # Döngünün en az `min_repeats` defa tekrar edip etmediğini kontrol et is_periodic = True for i in range(1, min_repeats): start_index = -(i + 1) * p_len end_index = -i * p_len # Dizinin o bölümünü al previous_block = sequence[start_index:end_index] # Eğer bloklar uyuşmuyorsa, bu periyot değildir if candidate_cycle != previous_block: is_periodic = False break # Eğer döngü tüm kontrollerden geçtiyse, periyodu bulduk demektir if is_periodic: return candidate_cycle # Hiçbir periyot bulunamadı return None def is_quaternion_like(obj): if isinstance(obj, quaternion): return True if hasattr(obj, "components"): comp = np.array(obj.components) return comp.size == 4 if all(hasattr(obj, attr) for attr in ["w", "x", "y", "z"]): return True if ( hasattr(obj, "scalar") and hasattr(obj, "vector") and isinstance(obj.vector, (list, np.ndarray)) and len(obj.vector) == 3 ): return True return False def is_neutrosophic_like(obj): """NeutrosophicNumber gibi görünen objeleri tanır (t,i,f veya a,b vs.)""" return ( (hasattr(obj, "t") and hasattr(obj, "i") and hasattr(obj, "f")) or (hasattr(obj, "a") and hasattr(obj, "b")) or (hasattr(obj, "value") and hasattr(obj, "indeterminacy")) or (hasattr(obj, "determinate") and hasattr(obj, "indeterminate")) ) # Yardımcı fonksiyon: Bileşen dağılımı grafiği def _plot_component_distribution(ax, elem, all_keys, seq_length=1): """Bileşen dağılımını gösterir""" if seq_length == 1: # Tek veri noktası için bileşen değerleri components = [] values = [] for key in all_keys: if key == "": components.append("Scalar") else: components.append(f"e{key}") values.append(elem.basis.get(key, 0.0)) bars = ax.bar(components, values, alpha=0.7, color="tab:blue") ax.set_title("Component Values") ax.tick_params(axis="x", rotation=45) for bar in bars: height = bar.get_height() if height != 0: ax.text( bar.get_x() + bar.get_width() / 2.0, height, f"{height:.2f}", ha="center", va="bottom", ) else: # Çoklu veri ama PCA yapılamıyor ax.text( 0.5, 0.5, f"Need ≥2 data points and ≥2 features\n(Current: {seq_length} points, {len(all_keys)} features)", ha="center", va="center", transform=ax.transAxes, fontsize=11, ) ax.set_title("Insufficient for PCA") def plot_octonion_3d(octonion_sequence, title="3D Octonion Trajectory"): """ Plots the trajectory of octonion numbers in 3D space using the first three imaginary components (x, y, z). Args: octonion_sequence (list): List of OctonionNumber objects. title (str): Title of the plot. """ if not octonion_sequence: print("Empty sequence. Nothing to plot.") return fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection="3d") # Octonion bileşenlerini ayıkla (w: gerçek, x/y/z: ilk üç sanal bileşen) x = [o.x for o in octonion_sequence] y = [o.y for o in octonion_sequence] z = [o.z for o in octonion_sequence] # 3D uzayda çiz ax.plot(x, y, z, "b-", linewidth=2, alpha=0.7, label="Trajectory") ax.scatter(x[0], y[0], z[0], c="g", s=100, label="Start", depthshade=True) ax.scatter(x[-1], y[-1], z[-1], c="r", s=100, label="End", depthshade=True) # Eksen etiketleri ve başlık ax.set_xlabel("X (i)") ax.set_ylabel("Y (j)") ax.set_zlabel("Z (k)") ax.set_title(title) # Legend ve grid ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() plt.show() # Otomatik Periyot Tespiti ve Keçeci Asal Analizi def analyze_kececi_sequence(sequence, kececi_type): """ Analyzes a Keçeci sequence for periodicity and Keçeci Prime Numbers (KPN). Args: sequence (list): List of Keçeci numbers. kececi_type (int): Type of Keçeci number (e.g., TYPE_OCTONION). Returns: dict: Analysis results including periodicity and KPNs. """ results = {"periodicity": None, "kececi_primes": [], "prime_indices": []} # Periyot tespiti for window in range(2, len(sequence) // 2): is_periodic = True for i in range(len(sequence) - window): if sequence[i] != sequence[i + window]: is_periodic = False break if is_periodic: results["periodicity"] = window break # Keçeci Asal sayıları tespit et for idx, num in enumerate(sequence): if is_prime_like(num, kececi_type): integer_rep = _get_integer_representation(num) if integer_rep is not None and sympy.isprime(integer_rep): results["kececi_primes"].append(integer_rep) results["prime_indices"].append(idx) return results # Makine Öğrenimi Entegrasyonu: PCA ve Kümelenme Analizi def apply_pca_clustering(sequence, n_components=2): """ Applies PCA and clustering to a Keçeci sequence for dimensionality reduction and pattern discovery. Args: sequence (list): List of Keçeci numbers. n_components (int): Number of PCA components. Returns: tuple: (pca_result, clusters) - PCA-transformed data and cluster labels. """ # Sayıları sayısal vektörlere dönüştür vectors = [] for num in sequence: if isinstance(num, OctonionNumber): vectors.append(num.coeffs) elif isinstance(num, Fraction): vectors.append([float(num)]) else: vectors.append([float(num)]) # PCA uygula pca = PCA(n_components=n_components) pca_result = pca.fit_transform(vectors) # Kümelenme (K-Means) kmeans = KMeans(n_clusters=3, random_state=42) clusters = kmeans.fit_predict(pca_result) return pca_result, clusters # Etkileşimli Görselleştirme (Plotly DASH) def generate_interactive_plot(sequence, kececi_type): """ Generates an interactive 3D plot using Plotly for Keçeci sequences. Args: sequence (list): List of Keçeci numbers. kececi_type (int): Type of Keçeci number. """ import plotly.graph_objects as go if kececi_type == TYPE_OCTONION: x = [num.x for num in sequence] y = [num.y for num in sequence] z = [num.z for num in sequence] elif kececi_type == TYPE_COMPLEX: x = [num.real for num in sequence] y = [num.imag for num in sequence] z = [0] * len(sequence) else: x = range(len(sequence)) y = [float(num) for num in sequence] z = [0] * len(sequence) fig = go.Figure( data=[ go.Scatter3d( x=x, y=y, z=z, mode="lines+markers", marker=dict(size=5, color=z, colorscale="Viridis"), line=dict(width=2), ) ] ) fig.update_layout( title=f"Interactive 3D Plot: Keçeci Type {kececi_type}", scene=dict(xaxis_title="X", yaxis_title="Y", zaxis_title="Z"), margin=dict(l=0, r=0, b=0, t=30), ) fig.show() # Keçeci Varsayımı Test Aracı def test_kececi_conjecture( sequence: List[Any], add_value: Any, kececi_type: Optional[int] = None, max_steps: int = 1000, ) -> bool: """ Tests the Keçeci Conjecture for a given starting `sequence`. - sequence: initial list-like of Keçeci numbers (will be copied). - add_value: typed increment (must be of compatible type with elements). - kececi_type: optional type constant (used by is_prime_like); if None, fallback to is_prime. - max_steps: maximum additional steps to try. Returns True if a Keçeci-prime is reached within max_steps, otherwise False. """ traj = list(sequence) if not traj: raise ValueError("sequence must contain at least one element") for step in range(max_steps): last = traj[-1] # Check prime-like condition try: if kececi_type is not None: if is_prime_like(last, kececi_type): return True else: # fallback: try is_prime on integer rep if is_prime(last): return True except Exception: # If prime test fails, continue attempts pass # Compute next element: prefer safe_add, else try native addition next_val = None try: next_val = safe_add(last, add_value, +1) except Exception: try: next_val = last + add_value except Exception: # cannot add -> abort return False traj.append(next_val) return False def format_fraction(value): """Fraction nesnelerini güvenli bir şekilde formatlar.""" if isinstance(value, Fraction): return float(value) # veya str(value) return value def plot_octonion_3d(octonion_sequence, title="3D Octonion Trajectory"): """ Plots the trajectory of octonion numbers in 3D space using the first three imaginary components (x, y, z). Args: octonion_sequence (list): List of OctonionNumber objects. title (str): Title of the plot. """ if not octonion_sequence: print("Empty sequence. Nothing to plot.") return fig = plt.figure(figsize=(10, 8)) ax = fig.add_subplot(111, projection="3d") # Octonion bileşenlerini ayıkla (w: gerçek, x/y/z: ilk üç sanal bileşen) x = [o.x for o in octonion_sequence] y = [o.y for o in octonion_sequence] z = [o.z for o in octonion_sequence] # 3D uzayda çiz ax.plot(x, y, z, "b-", linewidth=2, alpha=0.7, label="Trajectory") ax.scatter(x[0], y[0], z[0], c="g", s=100, label="Start", depthshade=True) ax.scatter(x[-1], y[-1], z[-1], c="r", s=100, label="End", depthshade=True) # Eksen etiketleri ve başlık ax.set_xlabel("X (i)") ax.set_ylabel("Y (j)") ax.set_zlabel("Z (k)") ax.set_title(title) # Legend ve grid ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() plt.show() # ======================== # Güvenli grafik çizme fonksiyonu (plot_numbers yerine) # ======================== def safe_plot_numbers(sequence, title): """sequence içindeki sayıların gerçel kısımlarını (veya ilk bileşenini) çiz.""" values = [] for x in sequence: try: # Gerçel kısım veya ilk bileşen if hasattr(x, "real"): # real property veya attribute r = x.real if not callable(x.real) else x.real() v = float(r) elif hasattr(x, "a"): # NeutrosophicBicomplex vs. v = float(x.a) elif isinstance(x, (int, float, complex)): v = float(x.real) if isinstance(x, complex) else float(x) elif isinstance(x, (list, tuple)) and len(x) > 0: v = float(x[0]) elif hasattr(x, "coeffs"): # coeffs property veya metot coeffs = x.coeffs if not callable(x.coeffs) else x.coeffs() if coeffs and len(coeffs) > 0: v = float(coeffs[0]) else: v = 0.0 else: v = 0.0 except Exception: v = 0.0 values.append(v) plt.figure(figsize=(10, 6)) plt.plot(values, "o-", color="tab:blue") plt.title(title) plt.xlabel("Step") plt.ylabel("Value (real part / first component)") plt.grid(True, alpha=0.3) plt.show() # Etkileşimli Görselleştirme (Plotly DASH) def generate_interactive_plot(sequence, kececi_type): """ Generates an interactive 3D plot using Plotly for Keçeci sequences. Args: sequence (list): List of Keçeci numbers. kececi_type (int): Type of Keçeci number. """ import plotly.graph_objects as go if kececi_type == TYPE_OCTONION: x = [num.x for num in sequence] y = [num.y for num in sequence] z = [num.z for num in sequence] elif kececi_type == TYPE_COMPLEX: x = [num.real for num in sequence] y = [num.imag for num in sequence] z = [0] * len(sequence) else: x = range(len(sequence)) y = [float(num) for num in sequence] z = [0] * len(sequence) fig = go.Figure( data=[ go.Scatter3d( x=x, y=y, z=z, mode="lines+markers", marker=dict(size=5, color=z, colorscale="Viridis"), line=dict(width=2), ) ] ) fig.update_layout( title=f"Interactive 3D Plot: Keçeci Type {kececi_type}", scene=dict(xaxis_title="X", yaxis_title="Y", zaxis_title="Z"), margin=dict(l=0, r=0, b=0, t=30), ) fig.show() # Keçeci Varsayımı Test Aracı def test_kececi_conjecture( sequence: List[Any], add_value: Any, kececi_type: Optional[int] = None, max_steps: int = 1000, ) -> bool: """ Tests the Keçeci Conjecture for a given starting `sequence`. - sequence: initial list-like of Keçeci numbers (will be copied). - add_value: typed increment (must be of compatible type with elements). - kececi_type: optional type constant (used by is_prime_like); if None, fallback to is_prime. - max_steps: maximum additional steps to try. Returns True if a Keçeci-prime is reached within max_steps, otherwise False. """ traj = list(sequence) if not traj: raise ValueError("sequence must contain at least one element") for step in range(max_steps): last = traj[-1] # Check prime-like condition try: if kececi_type is not None: if is_prime_like(last, kececi_type): return True else: # fallback: try is_prime on integer rep if is_prime(last): return True except Exception: # If prime test fails, continue attempts pass # Compute next element: prefer safe_add, else try native addition next_val = None try: next_val = safe_add(last, add_value, +1) except Exception: try: next_val = last + add_value except Exception: # cannot add -> abort return False traj.append(next_val) return False def format_fraction(value): """Fraction nesnelerini güvenli bir şekilde formatlar.""" if isinstance(value, Fraction): return float(value) # veya str(value) return value # Veri çıkarma fonksiyonu def extract_neutro_components(sequence): real_parts, imag_parts, indeter_parts = [], [], [] for i, x in enumerate(sequence): if isinstance(x, NeutrosophicComplexNumber): real_parts.append(x.real) imag_parts.append(x.imag) indeter_parts.append(x.indeterminacy) elif isinstance(x, (tuple, list)): # Tuple yapısını varsay: (real, imag, indeterminacy) veya (real, imag) real_parts.append(x[0] if len(x) > 0 else 0) imag_parts.append(x[1] if len(x) > 1 else 0) indeter_parts.append(x[2] if len(x) > 2 else 0) else: real_parts.append(0) imag_parts.append(0) indeter_parts.append(0) return real_parts, imag_parts, indeter_parts def plot_neutrosophic_complex(sequence, start_input_raw, add_input_raw, fig): print("DEBUG: Sequence uzunluk:", len(sequence)) # Tuple yapısından Neutro-complex'leri çıkar all_real_parts = [] all_imag_parts = [] all_indeter_parts = [] current_pos = 0 step_count = 0 while current_pos < len(sequence[0]) and step_count < 41: # Max 41 adım # Her Neutro-complex 3 eleman: (real, imag, indeterminacy) if current_pos + 2 < len(sequence[0]): real_val = sequence[0][current_pos] imag_val = sequence[0][current_pos + 1] indeter_val = sequence[0][current_pos + 2] all_real_parts.append(real_val) all_imag_parts.append(imag_val) all_indeter_parts.append(indeter_val) print(f"Adım {step_count}: ({real_val}, {imag_val}, {indeter_val})") current_pos += 3 step_count += 1 else: break # Eğer veri azsa doldur while len(all_real_parts) < 40: all_real_parts.append(all_real_parts[-1] if all_real_parts else 0) all_imag_parts.append(all_imag_parts[-1] if all_imag_parts else 0) all_indeter_parts.append(all_indeter_parts[-1] if all_indeter_parts else 0) magnitudes_z = [abs(complex(r, i)) for r, i in zip(all_real_parts, all_imag_parts)] print(f"Veri aralığı - Real: {min(all_real_parts):.2f}-{max(all_real_parts):.2f}") print(f"Veri aralığı - Imag: {min(all_imag_parts):.2f}-{max(all_imag_parts):.2f}") gs = GridSpec(2, 2, figure=fig) # 1. Complex Plane ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(all_real_parts, all_imag_parts, ".-", alpha=0.7, linewidth=2) ax1.scatter( all_real_parts[0], all_imag_parts[0], c="green", s=150, label="Başlangıç", zorder=5, ) ax1.scatter( all_real_parts[-1], all_imag_parts[-1], c="red", s=150, label="Bitiş", zorder=5 ) ax1.set_title("Karmaşık Düzlem") ax1.set_xlabel("Re(z)") ax1.set_ylabel("Im(z)") ax1.legend() ax1.grid(True, alpha=0.3) ax1.axis("equal") # 2. Belirsizlik Zaman Üzerinde ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(all_indeter_parts, "o-", color="purple", markersize=6) ax2.set_title("Belirsizlik Seviyesi") ax2.set_xlabel("Adım") ax2.set_ylabel("I") ax2.grid(True, alpha=0.3) # 3. |z| vs Belirsizlik ax3 = fig.add_subplot(gs[1, 0]) sc = ax3.scatter( magnitudes_z, all_indeter_parts, c=range(len(magnitudes_z)), cmap="viridis", s=50, edgecolors="white", linewidth=0.5, ) ax3.set_title("Büyüklük vs Belirsizlik") ax3.set_xlabel("|z|") ax3.set_ylabel("I") plt.colorbar(sc, ax=ax3, label="Adım") ax3.grid(True, alpha=0.3) # 4. Re vs Im (I'ye göre renklendirilmiş) ax4 = fig.add_subplot(gs[1, 1]) sc2 = ax4.scatter( all_real_parts, all_imag_parts, c=all_indeter_parts, cmap="plasma", s=60, edgecolors="white", linewidth=0.5, ) ax4.set_title("Re vs Im (I renklendirme)") ax4.set_xlabel("Re(z)") ax4.set_ylabel("Im(z)") plt.colorbar(sc2, ax=ax4, label="Belirsizlik (I)") ax4.grid(True, alpha=0.3) plt.tight_layout()
[docs] def plot_numbers(sequence: List[Any], title: str = "Keçeci Number Sequence Analysis"): """ Tüm 23 Keçeci Sayı türü için detaylı görselleştirme sağlar. """ if not sequence: print("Sequence is empty. Nothing to plot.") return # Ensure numpy is available for plotting functions try: import numpy as np except ImportError: print("Numpy not installed. Cannot plot effectively.") return try: from sklearn.decomposition import PCA use_pca = True except ImportError: use_pca = False print("scikit-learn kurulu değil. PCA olmadan çizim yapılıyor...") # --- helpers used in these branches --- def _pca_var_sum(pca_obj) -> float: try: arr = getattr(pca_obj, "explained_variance_ratio_", None) if arr is None: return 0.0 arr = np.asarray(arr, dtype=float) s = float(np.nansum(arr)) return s if np.isfinite(s) else 0.0 except Exception: return 0.0 def _ensure_fig(): try: _ = fig except NameError: return plt.figure(figsize=(12, 8), constrained_layout=True) else: try: fig.set_constrained_layout(True) except Exception: pass return fig fig = plt.figure(figsize=(18, 14), constrained_layout=True) fig.suptitle(title, fontsize=18, fontweight="bold") # `sequence` is the iterable you want to visualise first_elem = sequence[0] # --- 1. Fraction (Rational) if isinstance(first_elem, Fraction): # Tüm elemanları Fraction'a çevir (zaten Fraction ise aynı kalır) frac_vals = [Fraction(x) for x in sequence] numerators = [x.numerator for x in frac_vals] denominators = [x.denominator for x in frac_vals] # Float değerler (grafik için) float_vals = [float(x) for x in frac_vals] gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(float_vals, "o-", color="tab:blue") ax1.set_title("Fraction as Float") ax1.set_ylabel("Value") ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(numerators, "s-", label="Numerator", color="tab:orange") ax2.plot(denominators, "^-", label="Denominator", color="tab:green") ax2.set_title("Numerator & Denominator") ax2.legend() ax3 = fig.add_subplot(gs[1, 0]) ratios = [n / d for n, d in zip(numerators, denominators)] ax3.plot(ratios, "o-", color="tab:purple") ax3.set_title("Numerator/Denominator Ratio") ax3.set_ylabel("n/d") ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( numerators, denominators, c=range(len(sequence)), cmap="plasma", s=30 ) ax4.set_title("Numerator vs Denominator Trajectory") ax4.set_xlabel("Numerator") ax4.set_ylabel("Denominator") plt.colorbar(sc, ax=ax4, label="Step") """ if isinstance(first_elem, Fraction): # Tüm elemanları `float` olarak dönüştür float_vals = [float(x) for x in sequence] # float_vals = [float(x) if isinstance(x, (int, float, Fraction)) else float(x.value) for x in sequence] # Pay ve paydaları ayrı ayrı al numerators = [x.numerator for x in sequence] denominators = [x.denominator for x in sequence] # GridSpec ile 4 alt grafik oluştur gs = GridSpec(2, 2, figure=fig) # 1. Grafik: Float değerleri ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(float_vals, 'o-', color='tab:blue') ax1.set_title("Fraction as Float") ax1.set_ylabel("Value") # 2. Grafik: Pay ve payda değerleri ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(numerators, 's-', label='Numerator', color='tab:orange') ax2.plot(denominators, '^-', label='Denominator', color='tab:green') ax2.set_title("Numerator & Denominator") ax2.legend() # 3. Grafik: Pay/Payda oranı ax3 = fig.add_subplot(gs[1, 0]) ratios = [n / d for n, d in zip(numerators, denominators)] ax3.plot(ratios, 'o-', color='tab:purple') ax3.set_title("Numerator/Denominator Ratio") ax3.set_ylabel("n/d") # 4. Grafik: Pay vs Payda dağılımı ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter(numerators, denominators, c=range(len(sequence)), cmap='plasma', s=30) ax4.set_title("Numerator vs Denominator Trajectory") ax4.set_xlabel("Numerator") ax4.set_ylabel("Denominator") plt.colorbar(sc, ax=ax4, label="Step") """ # --- 2. int, float (Positive/Negative Real, Float) elif isinstance(first_elem, (int, float)): ax = fig.add_subplot(1, 1, 1) ax.plot([float(x) for x in sequence], "o-", color="tab:blue", markersize=5) ax.set_title("Real Number Sequence") ax.set_xlabel("Iteration") ax.set_ylabel("Value") ax.grid(True, alpha=0.3) # --- 3. Complex elif isinstance(first_elem, complex): real_parts = [z.real for z in sequence] imag_parts = [z.imag for z in sequence] magnitudes = [abs(z) for z in sequence] gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(real_parts, "o-", color="tab:blue") ax1.set_title("Real Part") ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(imag_parts, "o-", color="tab:red") ax2.set_title("Imaginary Part") ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:purple") ax3.set_title("Magnitude |z|") ax4 = fig.add_subplot(gs[1, 1]) ax4.plot(real_parts, imag_parts, ".-", alpha=0.7) ax4.scatter(real_parts[0], imag_parts[0], c="g", s=100, label="Start") ax4.scatter(real_parts[-1], imag_parts[-1], c="r", s=100, label="End") ax4.set_title("Complex Plane") ax4.set_xlabel("Re(z)") ax4.set_ylabel("Im(z)") ax4.legend() ax4.axis("equal") ax4.grid(True, alpha=0.3) # --- 4. quaternion # Check for numpy-quaternion's quaternion type, or a custom one with 'components' or 'w,x,y,z': çıkarıldı: and len(getattr(first_elem, 'components', [])) == 4) or \ """ elif isinstance(first_elem, quaternion) or (hasattr(first_elem, 'components') == 4) or \ (hasattr(first_elem, 'w') and hasattr(first_elem, 'x') and hasattr(first_elem, 'y') and hasattr(first_elem, 'z')): try: comp = np.array([ (q.w, q.x, q.y, q.z) if hasattr(q, 'w') else q.components for q in sequence ]) """ elif isinstance(first_elem, quaternion) or ( hasattr(first_elem, "w") and hasattr(first_elem, "x") and hasattr(first_elem, "y") and hasattr(first_elem, "z") ): try: # Bileşenleri güvenli şekilde al def get_comps(q): if hasattr(q, "components"): comps = ( q.components if not callable(q.components) else q.components() ) return ( comps[:4] if len(comps) >= 4 else comps + [0.0] * (4 - len(comps)) ) else: return [q.w, q.x, q.y, q.z] comp = np.array([get_comps(q) for q in sequence]) w, x, y, z = comp.T magnitudes = np.linalg.norm(comp, axis=1) fig = plt.figure(figsize=(10, 8)) gs = GridSpec(2, 2, figure=fig) # Component time‑series ax1 = fig.add_subplot(gs[0, 0]) labels = ["w", "x", "y", "z"] for i, label in enumerate(labels): ax1.plot(comp[:, i], label=label, alpha=0.8) ax1.set_title("Quaternion Components") ax1.legend() # Magnitude plot ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(magnitudes, "o-", color="tab:purple") ax2.set_title("Magnitude |q|") # 3‑D trajectory of the vector part (x, y, z) ax3 = fig.add_subplot(gs[1, :], projection="3d") ax3.plot(x, y, z, alpha=0.7) ax3.scatter(x[0], y[0], z[0], c="g", s=100, label="Start") ax3.scatter(x[-1], y[-1], z[-1], c="r", s=100, label="End") ax3.set_title("3D Trajectory (x,y,z)") ax3.set_xlabel("x") ax3.set_ylabel("y") ax3.set_zlabel("z") ax3.legend() except Exception as e: ax = fig.add_subplot(1, 1, 1) ax.text(0.5, 0.5, f"Quaternion plot error: {e}", ha="center", va="center") # --- 5. OctonionNumber elif isinstance(first_elem, OctonionNumber): coeffs = np.array([x.coeffs for x in sequence]) magnitudes = np.linalg.norm(coeffs, axis=1) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(4): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.7) ax1.set_title("e0-e3 Components") ax1.legend(ncol=2) ax2 = fig.add_subplot(gs[0, 1]) for i in range(4, 8): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.7) ax2.set_title("e4-e7 Components") ax2.legend(ncol=2) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:purple") ax3.set_title("Magnitude |o|") ax4 = fig.add_subplot(gs[1, 1], projection="3d") ax4.plot(coeffs[:, 1], coeffs[:, 2], coeffs[:, 3], alpha=0.7) ax4.set_title("3D (e1,e2,e3)") ax4.set_xlabel("e1") ax4.set_ylabel("e2") ax4.set_zlabel("e3") # --- 6. SedenionNumber elif isinstance(first_elem, SedenionNumber): coeffs = np.array([x.coeffs for x in sequence]) magnitudes = np.linalg.norm(coeffs, axis=1) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(8): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.8) ax1.set_title("Sedenion e0-e7") ax1.legend(ncol=2, fontsize=6) ax2 = fig.add_subplot(gs[0, 1]) for i in range(8, 16): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.8) ax2.set_title("e8-e15") ax2.legend(ncol=2, fontsize=6) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:purple") ax3.set_title("Magnitude |s|") # Local safe PCA variance helper (ensure available in this scope) def _pca_var_sum(pca_obj) -> float: try: arr = getattr(pca_obj, "explained_variance_ratio_", None) if arr is None: return 0.0 arr = np.asarray(arr, dtype=float) s = float(np.nansum(arr)) return s if np.isfinite(s) else 0.0 except Exception: return 0.0 if use_pca: try: pca = PCA(n_components=2) if len(sequence) > 2: proj = pca.fit_transform(coeffs) ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="viridis", s=25 ) var_sum = _pca_var_sum(pca) ax4.set_title(f"PCA Projection (Var: {var_sum:.3f})") plt.colorbar(sc, ax=ax4, label="Iteration") except Exception as e: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=10 ) else: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, "Install sklearn\nfor PCA", ha="center", va="center", fontsize=10, ) # --- 7. CliffordNumber elif isinstance(first_elem, CliffordNumber): all_keys = sorted(first_elem.basis.keys(), key=lambda x: (len(x), x)) values = {k: [elem.basis.get(k, 0.0) for elem in sequence] for k in all_keys} scalar = values.get("", [0] * len(sequence)) vector_keys = [k for k in all_keys if len(k) == 1] # GERÇEK özellik sayısını hesapla (sıfır olmayan bileşenler) non_zero_features = 0 for key in all_keys: if any(abs(elem.basis.get(key, 0.0)) > 1e-10 for elem in sequence): non_zero_features += 1 # Her zaman 2x2 grid kullan fig = plt.figure(figsize=(12, 10)) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) ax2 = fig.add_subplot(gs[0, 1]) ax3 = fig.add_subplot(gs[1, :]) # 1. Grafik: Skaler ve Vektör Bileşenleri ax1.plot(scalar, "o-", label="Scalar", color="black", linewidth=2) # Sadece sıfır olmayan vektör bileşenlerini göster visible_vectors = 0 for k in vector_keys: if any(abs(v) > 1e-10 for v in values[k]): ax1.plot(values[k], "o-", label=f"Vec {k}", alpha=0.7, linewidth=1.5) visible_vectors += 1 if visible_vectors >= 3: break ax1.set_title("Scalar & Vector Components Over Time") ax1.legend() ax1.grid(True, alpha=0.3) # 2. Grafik: Bivector Magnitude bivector_mags = [ sum(v**2 for k, v in elem.basis.items() if len(k) == 2) ** 0.5 for elem in sequence ] ax2.plot( bivector_mags, "o-", color="tab:green", linewidth=2, label="Bivector Magnitude", ) ax2.set_title("Bivector Magnitude Over Time") ax2.legend() ax2.grid(True, alpha=0.3) # 3. Grafik: PCA if use_pca and len(sequence) >= 2 and non_zero_features >= 2: try: # Tüm bileşenleri içeren matris oluştur matrix_data = [] for elem in sequence: row = [] for key in all_keys: row.append(elem.basis.get(key, 0.0)) matrix_data.append(row) matrix = np.array(matrix_data) # PCA uygula pca = PCA(n_components=min(2, matrix.shape[1])) proj = pca.fit_transform(matrix) sc = ax3.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="plasma", s=50, alpha=0.8, ) ax3.set_title( f"PCA Projection ({non_zero_features} features)\nVariance: {pca.explained_variance_ratio_[0]:.3f}, {pca.explained_variance_ratio_[1]:.3f}" ) cbar = plt.colorbar(sc, ax=ax3) cbar.set_label("Time Step") ax3.plot(proj[:, 0], proj[:, 1], "gray", linestyle="--", alpha=0.5) ax3.grid(True, alpha=0.3) except Exception as e: ax3.text( 0.5, 0.5, f"PCA Error: {str(e)[:30]}", ha="center", va="center", transform=ax3.transAxes, ) else: # PCA yapılamazsa bilgi göster ax3.text( 0.5, 0.5, f"Need ≥2 data points and ≥2 features\n(Current: {len(sequence)} points, {non_zero_features} features)", ha="center", va="center", transform=ax3.transAxes, ) if not use_pca: ax3.text( 0.5, 0.65, "Install sklearn for PCA", ha="center", va="center", transform=ax3.transAxes, ) ax3.set_title("Insufficient for PCA") # --- 8. DualNumber elif isinstance(first_elem, DualNumber): real_vals = [x.real for x in sequence] dual_vals = [x.dual for x in sequence] gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(real_vals, "o-", color="tab:blue") ax1.set_title("Real Part") ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(dual_vals, "o-", color="tab:orange") ax2.set_title("Dual Part (ε)") ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(real_vals, dual_vals, ".-") ax3.set_title("Real vs Dual") ax3.set_xlabel("Real") ax3.set_ylabel("Dual") ax4 = fig.add_subplot(gs[1, 1]) ratios = [d / r if r != 0 else 0 for r, d in zip(real_vals, dual_vals)] ax4.plot(ratios, "o-", color="tab:purple") ax4.set_title("Dual/Real Ratio") # --- 9. SplitcomplexNumber elif isinstance(first_elem, SplitcomplexNumber): real_vals = [x.real for x in sequence] split_vals = [x.split for x in sequence] u_vals = [r + s for r, s in zip(real_vals, split_vals)] v_vals = [r - s for r, s in zip(real_vals, split_vals)] gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(real_vals, "o-", color="tab:green") ax1.set_title("Real Part") ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(split_vals, "o-", color="tab:brown") ax2.set_title("Split Part (j)") ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(real_vals, split_vals, ".-") ax3.set_title("Trajectory (Real vs Split)") ax3.grid(True, alpha=0.3) ax4 = fig.add_subplot(gs[1, 1]) ax4.plot(u_vals, label="u = r+j") ax4.plot(v_vals, label="v = r-j") ax4.set_title("Light-Cone Coordinates") ax4.legend() # --- 10. NeutrosophicNumber elif isinstance(first_elem, NeutrosophicNumber): # NeutrosophicNumber sınıfının arayüzünü biliyoruz, hasattr gerekmez # Sınıfın public attribute'larına doğrudan erişim try: t_vals = [x.t for x in sequence] i_vals = [x.i for x in sequence] f_vals = [x.f for x in sequence] except AttributeError: # Eğer attribute yoksa, alternatif arayüzleri deneyebiliriz # Veya hata fırlatabiliriz try: t_vals = [x.a for x in sequence] i_vals = [x.b for x in sequence] f_vals = [0] * len(sequence) # f yoksa sıfır except AttributeError: try: t_vals = [x.value for x in sequence] i_vals = [x.indeterminacy for x in sequence] f_vals = [0] * len(sequence) except AttributeError: # Hiçbiri yoksa boş liste t_vals = i_vals = f_vals = [] gs = GridSpec(2, 2, figure=fig) # 1. t, i, f zaman içinde ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(t_vals, "o-", label="Truth (t)", color="tab:blue") ax1.plot(i_vals, "s-", label="Indeterminacy (i)", color="tab:orange") ax1.plot(f_vals, "^-", label="Falsity (f)", color="tab:red") ax1.set_title("Neutrosophic Components") ax1.set_xlabel("Iteration") ax1.set_ylabel("Value") ax1.legend() ax1.grid(True, alpha=0.3) # 2. t vs i ax2 = fig.add_subplot(gs[0, 1]) ax2.scatter(t_vals, i_vals, c=range(len(t_vals)), cmap="viridis", s=30) ax2.set_title("t vs i Trajectory") ax2.set_xlabel("Truth (t)") ax2.set_ylabel("Indeterminacy (i)") plt.colorbar(ax2.collections[0], ax=ax2, label="Step") # 3. t vs f ax3 = fig.add_subplot(gs[1, 0]) ax3.scatter(t_vals, f_vals, c=range(len(t_vals)), cmap="plasma", s=30) ax3.set_title("t vs f Trajectory") ax3.set_xlabel("Truth (t)") ax3.set_ylabel("Falsity (f)") plt.colorbar(ax3.collections[0], ax=ax3, label="Step") # 4. Magnitude (t² + i² + f²) magnitudes = [ np.sqrt(t**2 + i**2 + f**2) for t, i, f in zip(t_vals, i_vals, f_vals) ] ax4 = fig.add_subplot(gs[1, 1]) ax4.plot(magnitudes, "o-", color="tab:purple") ax4.set_title("Magnitude √(t²+i²+f²)") ax4.set_ylabel("|n|") # --- 11. NeutrosophicComplexNumber (duck-typed, güvenli plotting) --- # --- 11. NeutrosophicComplexNumber (eski tarz, basit) --- elif isinstance(first_elem, NeutrosophicComplexNumber): try: # Basit, güvenli veri çıkarımı: önce attribute, sonra to_list/to_components/coeffs, son olarak tuple/list fallback real_parts = [] imag_parts = [] indet_parts = [] for x in sequence: # 1) doğrudan attribute/property r = getattr(x, "real", None) im = getattr(x, "imag", None) ind = getattr(x, "indeterminacy", None) # 2) fallback: to_list / to_components / coeffs if r is None or im is None or ind is None: """ if hasattr(x, "to_list") and callable(getattr(x, "to_list")): try: comps = list(x.to_list()) except Exception: comps = [] """ # to_list veya coeffs çağrılarını düzelt: if hasattr(x, "to_list") and callable(getattr(x, "to_list")): comps = list(x.to_list()) elif hasattr(x, "coeffs"): c = x.coeffs if not callable(x.coeffs) else x.coeffs() comps = list(c) elif hasattr(x, "to_components") and callable( getattr(x, "to_components") ): try: comps = list(x.to_components()) except Exception: comps = [] elif hasattr(x, "coeffs"): try: c = ( x.coeffs() if callable(getattr(x, "coeffs")) else x.coeffs ) comps = list(c) except Exception: comps = [] else: comps = [] if r is None and len(comps) >= 1: r = comps[0] if im is None and len(comps) >= 2: im = comps[1] if ind is None and len(comps) >= 3: ind = comps[2] # 3) son fallback: tuple/list pozisyonel if (r is None or im is None or ind is None) and isinstance( x, (tuple, list) ): if r is None and len(x) > 0: r = x[0] if im is None and len(x) > 1: im = x[1] if ind is None and len(x) > 2: ind = x[2] # 4) numeric dönüşümler (güvenli) try: real_parts.append(float(r) if r is not None else 0.0) except Exception: real_parts.append(0.0) try: imag_parts.append( float(im.real) if isinstance(im, complex) else float(im) if im is not None else 0.0 ) except Exception: imag_parts.append(0.0) try: indet_parts.append(float(ind) if ind is not None else 0.0) except Exception: indet_parts.append(0.0) # magnitude hesapla magnitudes = [abs(complex(r, i)) for r, i in zip(real_parts, imag_parts)] # figür oluştur / yeniden kullan try: _ = fig except NameError: fig = plt.figure(figsize=(11, 7), constrained_layout=True) gs = GridSpec(2, 2, figure=fig) # 1) Complex plane ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(real_parts, imag_parts, ".-", alpha=0.8) if real_parts: ax1.scatter(real_parts[0], imag_parts[0], c="g", s=80, label="Start") ax1.scatter(real_parts[-1], imag_parts[-1], c="r", s=80, label="End") ax1.set_title("Neutrosophic Complex Plane") ax1.set_xlabel("Re(z)") ax1.set_ylabel("Im(z)") ax1.legend() ax1.axis("equal") ax1.grid(alpha=0.25) # 2) Indeterminacy over time ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(indet_parts, "o-", color="purple") ax2.set_title("Indeterminacy Level") ax2.set_ylabel("I") ax2.grid(alpha=0.25) # 3) |z| vs Indeterminacy ax3 = fig.add_subplot(gs[1, 0]) sc = ax3.scatter( magnitudes, indet_parts, c=np.arange(len(magnitudes)), cmap="viridis", s=30, ) ax3.set_title("Magnitude vs Indeterminacy") ax3.set_xlabel("|z|") ax3.set_ylabel("I") try: cbar = fig.colorbar(sc, ax=ax3, fraction=0.046, pad=0.04) cbar.ax.tick_params(labelsize=8) except Exception: pass ax3.grid(alpha=0.25) # 4) Real vs Imag colored by I ax4 = fig.add_subplot(gs[1, 1]) sc2 = ax4.scatter( real_parts, imag_parts, c=indet_parts, cmap="plasma", s=40 ) ax4.set_title("Real vs Imag (colored by I)") ax4.set_xlabel("Re(z)") ax4.set_ylabel("Im(z)") try: cbar2 = fig.colorbar(sc2, ax=ax4, fraction=0.046, pad=0.04) cbar2.ax.tick_params(labelsize=8) except Exception: pass ax4.grid(alpha=0.25) return fig except Exception as e: try: _ = fig except NameError: fig = plt.figure(figsize=(8, 4), constrained_layout=True) ax = fig.add_subplot(1, 1, 1) ax.text( 0.5, 0.5, f"NeutrosophicComplex plot error: {e}", ha="center", va="center", color="red", ) ax.set_xticks([]) ax.set_yticks([]) logger.exception("NeutrosophicComplex plotting failed") return fig """ # sorunsuz çalışıyor elif isinstance(first_elem, NeutrosophicComplexNumber): print("FIRST TYPE:", type(first_elem)) print("MODULE:", first_elem.__class__.__module__) print("DEBUG: NeutrosophicComplex plotting - Universal handler") def safe_extract_real(obj): #Her türden real çıkarır if hasattr(obj, 'real'): return float(obj.real) return 0.0 def safe_extract_imag(obj): #Her türden imag çıkarır if hasattr(obj, 'imag'): return float(obj.imag) return 0.0 def safe_extract_indet(obj): #Her türden indeterminacy çıkarır if hasattr(obj, 'NeutrosophicComplexNumber'): return float(obj.NeutrosophicComplexNumber) return 0.0 # Sequence'den verileri çıkar (PlotNeutroComplex + diğer tipler) real_parts = [safe_extract_real(x) for x in sequence] imag_parts = [safe_extract_imag(x) for x in sequence] indeter_parts = [safe_extract_indet(x) for x in sequence] magnitudes_z = [abs(complex(r, i)) for r, i in zip(real_parts, imag_parts)] # 4 grafik - %100 sorunsuz gs = GridSpec(2, 2, figure=fig) # 1. Complex Plane ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(real_parts, imag_parts, ".-", alpha=0.7) ax1.scatter(real_parts[0], imag_parts[0], c="g", s=100, label="Start") ax1.scatter(real_parts[-1], imag_parts[-1], c="r", s=100, label="End") ax1.set_title("Neutrosophic Complex Plane") ax1.legend(); ax1.axis("equal") # 2. Indeterminacy ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(indeter_parts, "o-", color="purple") ax2.set_title("NeutrosophicComplexNumber (NCN)") # 3. Magnitude vs I ax3 = fig.add_subplot(gs[1, 0]) sc = ax3.scatter(magnitudes_z, indeter_parts, c=range(len(sequence)), cmap="viridis", s=30) ax3.set_title("|z| vs I"); plt.colorbar(sc, ax=ax3, label="Step") # 4. Real-Imag colored by I ax4 = fig.add_subplot(gs[1, 1]) sc2 = ax4.scatter(real_parts, imag_parts, c=indeter_parts, cmap="plasma", s=40) ax4.set_title("Re-Im (by I)"); plt.colorbar(sc2, ax=ax4) """ # --- 12. HyperrealNumber (eski tarz, basit) elif isinstance(first_elem, HyperrealNumber): try: # Her elemandan .sequence veya to_list/coeffs ile bileşenleri al """ rows = [] for x in sequence: if hasattr(x, "sequence"): seq_vals = list(getattr(x, "sequence")) elif hasattr(x, "to_list") and callable(getattr(x, "to_list")): seq_vals = list(x.to_list()) elif hasattr(x, "coeffs"): c = x.coeffs() if callable(getattr(x, "coeffs")) else x.coeffs seq_vals = list(c) elif hasattr(x, "__iter__") and not isinstance(x, (str, bytes)): seq_vals = list(x) else: try: seq_vals = [float(x)] except Exception: seq_vals = [0.0] rows.append(seq_vals) """ rows = [] for x in sequence: if hasattr(x, "sequence"): seq_vals = x.sequence if not callable(x.sequence) else x.sequence() elif hasattr(x, "to_list") and callable(getattr(x, "to_list")): seq_vals = x.to_list() elif hasattr(x, "coeffs"): c = x.coeffs if not callable(x.coeffs) else x.coeffs() seq_vals = list(c) else: try: seq_vals = [float(x)] except: seq_vals = [0.0] rows.append(seq_vals) # seq_len: her satırın minimum uzunluğu, en fazla 5 min_len = min(len(r) for r in rows) if rows else 0 seq_len = min(5, max(1, min_len)) # pad/truncate data = np.array( [(r + [0.0] * seq_len)[:seq_len] for r in rows], dtype=float ) # fig oluştur / yeniden kullan try: _ = fig except NameError: fig = plt.figure(figsize=(12, 8), constrained_layout=True) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(seq_len): ax1.plot(data[:, i], label=f"ε^{i}", alpha=0.8) ax1.set_title("Hyperreal Components") ax1.legend(ncol=2) ax1.grid(alpha=0.25) ax2 = fig.add_subplot(gs[0, 1]) magnitudes = np.linalg.norm(data, axis=1) ax2.plot(magnitudes, "o-", color="tab:purple") ax2.set_title("Magnitude") ax2.grid(alpha=0.25) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(data[:, 0], "o-", label="Standard Part") ax3.set_title("Standard Part (ε⁰)") ax3.legend() ax3.grid(alpha=0.25) ax4 = fig.add_subplot(gs[1, 1]) y2 = data[:, 1] if data.shape[1] > 1 else np.zeros(len(data)) sc = ax4.scatter(data[:, 0], y2, c=np.arange(len(data)), cmap="viridis") ax4.set_title("Standard vs Infinitesimal") ax4.set_xlabel("Standard") ax4.set_ylabel("ε¹") try: cbar = fig.colorbar(sc, ax=ax4, fraction=0.046, pad=0.04) cbar.ax.tick_params(labelsize=8) except Exception: pass return fig except Exception as e: try: _ = fig except NameError: fig = plt.figure(figsize=(8, 4), constrained_layout=True) ax = fig.add_subplot(1, 1, 1) ax.text( 0.5, 0.5, f"Hyperreal plot error: {e}", ha="center", va="center", color="red", ) ax.set_xticks([]) ax.set_yticks([]) logger.exception("Hyperreal plotting failed") return fig # --- 13. BicomplexNumber (eski tarz, basit) elif isinstance(first_elem, BicomplexNumber): try: z1_real = [] z1_imag = [] z2_real = [] z2_imag = [] """ for x in sequence: z1 = getattr(x, "z1", None) z2 = getattr(x, "z2", None) if z1 is None or z2 is None: if hasattr(x, "to_components") and callable(getattr(x, "to_components")): comps = x.to_components() if len(comps) >= 2: z1 = comps[0]; z2 = comps[1] elif hasattr(x, "to_list") and callable(getattr(x, "to_list")): comps = x.to_list() if len(comps) >= 2: z1 = comps[0]; z2 = comps[1] elif hasattr(x, "coeffs"): c = x.coeffs() if callable(getattr(x, "coeffs")) else x.coeffs c = list(c) if len(c) >= 2: z1 = c[0]; z2 = c[1] """ for x in sequence: z1 = getattr(x, "z1", None) z2 = getattr(x, "z2", None) if z1 is None or z2 is None: if hasattr(x, "to_components") and callable( getattr(x, "to_components") ): comps = x.to_components() elif hasattr(x, "coeffs"): c = x.coeffs if not callable(x.coeffs) else x.coeffs() comps = list(c) else: comps = [0, 0] if len(comps) >= 2: z1, z2 = comps[0], comps[1] try: zr = complex(z1).real if z1 is not None else 0.0 zi = complex(z1).imag if z1 is not None else 0.0 except Exception: zr, zi = 0.0, 0.0 try: wr = complex(z2).real if z2 is not None else 0.0 wi = complex(z2).imag if z2 is not None else 0.0 except Exception: wr, wi = 0.0, 0.0 z1_real.append(zr) z1_imag.append(zi) z2_real.append(wr) z2_imag.append(wi) try: _ = fig except NameError: fig = plt.figure(figsize=(12, 8), constrained_layout=True) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(z1_real, label="Re(z1)") ax1.plot(z1_imag, label="Im(z1)") ax1.set_title("Bicomplex z1") ax1.legend() ax1.grid(alpha=0.25) ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(z2_real, label="Re(z2)") ax2.plot(z2_imag, label="Im(z2)") ax2.set_title("Bicomplex z2") ax2.legend() ax2.grid(alpha=0.25) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(z1_real, z1_imag, ".-") ax3.set_title("z1 Trajectory") ax3.set_xlabel("Re(z1)") ax3.set_ylabel("Im(z1)") ax3.grid(alpha=0.25) ax4 = fig.add_subplot(gs[1, 1]) ax4.plot(z2_real, z2_imag, ".-") ax4.set_title("z2 Trajectory") ax4.set_xlabel("Re(z2)") ax4.set_ylabel("Im(z2)") ax4.grid(alpha=0.25) return fig except Exception as e: try: _ = fig except NameError: fig = plt.figure(figsize=(8, 4), constrained_layout=True) ax = fig.add_subplot(1, 1, 1) ax.text( 0.5, 0.5, f"Bicomplex plot error: {e}", ha="center", va="center", color="red", ) ax.set_xticks([]) ax.set_yticks([]) logger.exception("Bicomplex plotting failed") return fig # --- 14. NeutrosophicBicomplexNumber (eski tarz, basit) elif isinstance(first_elem, NeutrosophicBicomplexNumber): try: """ comps = [] for x in sequence: vals = [] ok = True for attr in ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']: if hasattr(x, attr): try: vals.append(float(getattr(x, attr))) except Exception: vals.append(0.0) else: ok = False break if not ok: if hasattr(x, "to_components") and callable(getattr(x, "to_components")): comps_list = x.to_components() elif hasattr(x, "to_list") and callable(getattr(x, "to_list")): comps_list = x.to_list() elif hasattr(x, "coeffs"): c = x.coeffs() if callable(getattr(x, "coeffs")) else x.coeffs comps_list = list(c) else: try: comps_list = list(x) except Exception: comps_list = [0.0]*8 comps_list = (list(comps_list) + [0.0]*8)[:8] vals = [] for v in comps_list[:8]: try: vals.append(float(v)) except Exception: vals.append(0.0) comps.append(vals) """ comps = [] for x in sequence: if hasattr(x, "coeffs"): c = x.coeffs if not callable(x.coeffs) else x.coeffs() vals = list(c)[:8] elif hasattr(x, "to_components") and callable( getattr(x, "to_components") ): vals = x.to_components()[:8] else: # attribute a,b,c,d,e,f,g,h vals = [ getattr(x, attr, 0.0) for attr in ["a", "b", "c", "d", "e", "f", "g", "h"] ] comps.append([float(v) for v in vals]) comps = np.array(comps, dtype=float) magnitudes = np.linalg.norm(comps, axis=1) try: _ = fig except NameError: fig = plt.figure(figsize=(12, 8), constrained_layout=True) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i, label in enumerate(["a", "b", "c", "d"]): ax1.plot(comps[:, i], label=label, alpha=0.7) ax1.set_title("First 4 Components") ax1.legend() ax1.grid(alpha=0.25) ax2 = fig.add_subplot(gs[0, 1]) for i, label in enumerate(["e", "f", "g", "h"]): ax2.plot(comps[:, i + 4], label=label, alpha=0.7) ax2.set_title("Last 4 Components") ax2.legend() ax2.grid(alpha=0.25) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:purple") ax3.set_title("Magnitude") ax3.grid(alpha=0.25) ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( comps[:, 0], comps[:, 1], c=np.arange(len(comps)), cmap="plasma" ) ax4.set_title("a vs b Trajectory") ax4.set_xlabel("a") ax4.set_ylabel("b") try: cbar = fig.colorbar(sc, ax=ax4, fraction=0.046, pad=0.04) cbar.ax.tick_params(labelsize=8) except Exception: pass return fig except Exception as e: try: _ = fig except NameError: fig = plt.figure(figsize=(8, 4), constrained_layout=True) ax = fig.add_subplot(1, 1, 1) ax.text( 0.5, 0.5, f"NeutrosophicBicomplex plot error: {e}", ha="center", va="center", color="red", ) ax.set_xticks([]) ax.set_yticks([]) logger.exception("NeutrosophicBicomplex plotting failed") return fig # --- 15. Pathion elif isinstance(first_elem, PathionNumber): coeffs = np.array([x.coeffs for x in sequence]) magnitudes = np.linalg.norm(coeffs, axis=1) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(8): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.8) ax1.set_title("PathionNumber e0-e7") ax1.legend(ncol=2, fontsize=6) ax2 = fig.add_subplot(gs[0, 1]) for i in range(8, 16): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.8) ax2.set_title("e8-e15") ax2.legend(ncol=2, fontsize=6) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:red") ax3.set_title("Magnitude |p|") if use_pca: try: pca = PCA(n_components=2) if len(sequence) > 2: proj = pca.fit_transform(coeffs) ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="viridis", s=25 ) var_sum = _pca_var_sum(pca) ax4.set_title(f"PCA Projection (Var: {var_sum:.3f})") plt.colorbar(sc, ax=ax4, label="Iteration") except Exception as e: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=10 ) else: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, "Install sklearn\nfor PCA", ha="center", va="center", fontsize=10, ) # --- 16. Chingon elif isinstance(first_elem, ChingonNumber): coeffs = np.array([x.coeffs for x in sequence]) magnitudes = np.linalg.norm(coeffs, axis=1) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(16): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.5) ax1.set_title("ChingonNumber e0-e15") ax1.legend(ncol=4, fontsize=4) ax2 = fig.add_subplot(gs[0, 1]) for i in range(16, 32): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.5) ax2.set_title("e16-e31") ax2.legend(ncol=4, fontsize=4) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:green") ax3.set_title("Magnitude |c|") if use_pca: try: pca = PCA(n_components=2) if len(sequence) > 2: proj = pca.fit_transform(coeffs) ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="viridis", s=25 ) var_sum = _pca_var_sum(pca) ax4.set_title(f"PCA Projection (Var: {var_sum:.3f})") plt.colorbar(sc, ax=ax4, label="Iteration") except Exception as e: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=10 ) else: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, "Install sklearn\nfor PCA", ha="center", va="center", fontsize=10, ) # --- 17. Routon elif isinstance(first_elem, RoutonNumber): coeffs = np.array([x.coeffs for x in sequence]) magnitudes = np.linalg.norm(coeffs, axis=1) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(32): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.3) ax1.set_title("RoutonNumber e0-e31") ax1.legend(ncol=4, fontsize=3) ax2 = fig.add_subplot(gs[0, 1]) for i in range(32, 64): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.3) ax2.set_title("e32-e63") ax2.legend(ncol=4, fontsize=3) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:blue") ax3.set_title("Magnitude |r|") if use_pca: try: pca = PCA(n_components=2) if len(sequence) > 2: proj = pca.fit_transform(coeffs) ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="viridis", s=25 ) var_sum = _pca_var_sum(pca) ax4.set_title(f"PCA Projection (Var: {var_sum:.3f})") plt.colorbar(sc, ax=ax4, label="Iteration") except Exception as e: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=10 ) else: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, "Install sklearn\nfor PCA", ha="center", va="center", fontsize=10, ) # --- 18. Voudon elif isinstance(first_elem, VoudonNumber): coeffs = np.array([x.coeffs for x in sequence]) magnitudes = np.linalg.norm(coeffs, axis=1) gs = GridSpec(2, 2, figure=fig) ax1 = fig.add_subplot(gs[0, 0]) for i in range(64): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.2) ax1.set_title("VoudonNumber e0-e63") ax1.legend(ncol=4, fontsize=2) ax2 = fig.add_subplot(gs[0, 1]) for i in range(64, 128): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.2) ax2.set_title("e64-e127") ax2.legend(ncol=4, fontsize=2) ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:orange") ax3.set_title("Magnitude |v|") if use_pca: try: pca = PCA(n_components=2) if len(sequence) > 2: proj = pca.fit_transform(coeffs) ax4 = fig.add_subplot(gs[1, 1]) sc = ax4.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="viridis", s=25 ) var_sum = _pca_var_sum(pca) ax4.set_title(f"PCA Projection (Var: {var_sum:.3f})") plt.colorbar(sc, ax=ax4, label="Iteration") except Exception as e: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=10 ) else: ax4 = fig.add_subplot(gs[1, 1]) ax4.text( 0.5, 0.5, "Install sklearn\nfor PCA", ha="center", va="center", fontsize=10, ) # --- 21. Super Real elif isinstance(first_elem, SuperrealNumber): # Extract real and split components robustly (support attributes or methods) def _get_attr_or_callable(obj, name): if hasattr(obj, name): attr = getattr(obj, name) return attr() if callable(attr) else attr return None reals_list = [] splits_list = [] for x in sequence: # try common attribute names / callables r = _get_attr_or_callable(x, "real") s = _get_attr_or_callable(x, "split") # fallback: try to_list / coeffs if available (some implementations) if r is None or s is None: if hasattr(x, "to_list") and callable(getattr(x, "to_list")): comps = x.to_list() if r is None and len(comps) >= 1: r = comps[0] if s is None and len(comps) >= 2: s = comps[1] elif hasattr(x, "coeffs"): c = x.coeffs() if callable(getattr(x, "coeffs")) else x.coeffs c = list(c) if r is None and len(c) >= 1: r = c[0] if s is None and len(c) >= 2: s = c[1] # final fallbacks to numeric zero try: reals_list.append(float(r) if r is not None else 0.0) except Exception: reals_list.append(0.0) try: splits_list.append(float(s) if s is not None else 0.0) except Exception: splits_list.append(0.0) reals = np.asarray(reals_list, dtype=float) splits = np.asarray(splits_list, dtype=float) # create figure and grid try: _ = fig except NameError: fig = plt.figure(figsize=(10, 6), constrained_layout=True) gs = GridSpec(2, 2, figure=fig) # Real component plot ax1 = fig.add_subplot(gs[0, 0]) ax1.plot(reals, "o-", color="tab:blue", label="Real") ax1.set_title("Real Component") ax1.set_xlabel("Iteration") ax1.set_ylabel("Value") ax1.grid(alpha=0.25) ax1.legend() # Split component plot ax2 = fig.add_subplot(gs[1, 0]) ax2.plot(splits, "o-", color="tab:red", label="Split") ax2.set_title("Split Component") ax2.set_xlabel("Iteration") ax2.set_ylabel("Value") ax2.grid(alpha=0.25) ax2.legend() # Local safe PCA variance helper (ensure available in this scope) def _pca_var_sum(pca_obj) -> float: try: arr = getattr(pca_obj, "explained_variance_ratio_", None) if arr is None: return 0.0 arr = np.asarray(arr, dtype=float) s = float(np.nansum(arr)) return s if np.isfinite(s) else 0.0 except Exception: return 0.0 # PCA panel (right column spanning both rows) axp = fig.add_subplot(gs[:, 1]) if use_pca and len(sequence) > 2: try: # prepare data matrix (samples x features) data = np.column_stack((reals, splits)) if data.shape[0] < 3: axp.text( 0.5, 0.5, "Need ≥3 samples for PCA", ha="center", va="center", fontsize=10, ) axp.set_title("PCA Projection (Not enough samples)") else: # filter finite rows mask = np.all(np.isfinite(data), axis=1) data_clean = data[mask] if data_clean.shape[0] < 3: axp.text( 0.5, 0.5, "Insufficient finite data for PCA", ha="center", va="center", fontsize=10, ) axp.set_title("PCA Projection (Insufficient data)") else: try: from sklearn.decomposition import ( PCA as _PCA, ) # local import to avoid global dependency pca = _PCA(n_components=2) proj = pca.fit_transform(data_clean) sc = axp.scatter( proj[:, 0], proj[:, 1], c=np.arange(len(proj)), cmap="viridis", s=25, ) var_sum = _pca_var_sum(pca) axp.set_title(f"PCA Projection (Var: {var_sum:.3f})") axp.set_xlabel("PC1") axp.set_ylabel("PC2") try: cbar = fig.colorbar( sc, ax=axp, fraction=0.046, pad=0.04 ) cbar.ax.tick_params(labelsize=8) except Exception: # fallback: no colorbar pass except Exception as e: logger.exception("PCA failed for Superreal data: %s", e) axp.text( 0.5, 0.5, f"PCA Error: {str(e)[:120]}", ha="center", va="center", fontsize=10, ) axp.set_title("PCA Projection (Error)") except Exception as e: logger.exception("PCA preparation failed: %s", e) axp.text( 0.5, 0.5, f"PCA Error: {str(e)[:120]}", ha="center", va="center", fontsize=10, ) axp.set_title("PCA Projection (Error)") else: axp.text( 0.5, 0.5, "Install sklearn\nfor PCA", ha="center", va="center", fontsize=12, ) axp.set_title("PCA Projection (Unavailable)") return fig # --- 22. TernaryNumber------- # TernaryNumber için özel grafik (plot_numbers içinde) elif isinstance(first_elem, TernaryNumber): # Tüm digits listelerini topla all_digits = [] for x in sequence: if isinstance(x, TernaryNumber): all_digits.append(x.digits.copy()) elif isinstance(x, list) and all( isinstance(d, int) and 0 <= d <= 2 for d in x ): all_digits.append(x.copy()) else: all_digits.append([int(x)] if isinstance(x, (int, float)) else [0]) max_len = max(len(d) for d in all_digits) if all_digits else 1 padded = [d + [0] * (max_len - len(d)) for d in all_digits] digits = np.array(padded, dtype=float) gs = GridSpec(2, 2, figure=fig) # 1. Rakam grafiği ax1 = fig.add_subplot(gs[0, 0]) for i in range(digits.shape[1]): ax1.plot(digits[:, i], "o-", alpha=0.6, label=f"digit {i}") ax1.set_title("Ternary Digits") ax1.legend(ncol=4, fontsize=6) # 2. Ondalık değerler decimal_values = [convert_to_float(x) for x in sequence] ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(decimal_values, "o-", color="tab:green") ax2.set_title("Decimal Values") # 3. PCA – sadece yeterli özellik varsa if use_pca and len(sequence) > 2 and max_len >= 2: try: from sklearn.decomposition import PCA # n_components = min(2, max_len, n_samples-1) n_comp = min(2, digits.shape[1], digits.shape[0] - 1) pca = PCA(n_components=n_comp, svd_solver="auto") proj = pca.fit_transform(digits) ax3 = fig.add_subplot(gs[1, :]) if n_comp == 2: sc = ax3.scatter( proj[:, 0], proj[:, 1], c=range(len(proj)), cmap="viridis", s=25 ) ax3.set_title( f"PCA (Var: {sum(pca.explained_variance_ratio_):.3f})" ) plt.colorbar(sc, ax=ax3, label="Iteration") else: # Tek bileşen durumunda 1D projeksiyon çiz ax3.plot(proj, "o-", color="purple") ax3.set_title("PCA (1 component)") except Exception as e: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, f"PCA Error: {e}", ha="center", va="center") else: ax3 = fig.add_subplot(gs[1, :]) if max_len < 2: ax3.text( 0.5, 0.5, "Not enough digits for PCA (need at least 2 digits)", ha="center", va="center", ) else: ax3.text( 0.5, 0.5, "Install sklearn or increase sequence length for PCA", ha="center", va="center", ) """ elif isinstance(first_elem, TernaryNumber): # Tüm nesnelerin digits'lerini al (TernaryNumber veya liste) all_digits = [] for x in sequence: if isinstance(x, TernaryNumber): all_digits.append(x.digits.copy()) # rakam listesi elif isinstance(x, list) and all(isinstance(d, int) and 0<=d<=2 for d in x): all_digits.append(x.copy()) else: # scalar fallback (nadir) all_digits.append([int(x)] if isinstance(x, (int,float)) else [0]) # Maksimum uzunluğa göre padding (rakamların basamak sayısı) max_len = max(len(d) for d in all_digits) if all_digits else 1 padded = [] for d in all_digits: padded.append(d + [0]*(max_len - len(d))) digits = np.array(padded, dtype=float) # Grid oluştur (2 satır, 2 sütun) gs = GridSpec(2, 2, figure=fig) # 1. Rakam grafiği ax1 = fig.add_subplot(gs[0, 0]) for i in range(digits.shape[1]): ax1.plot(digits[:, i], 'o-', alpha=0.6, label=f'digit {i}') ax1.set_title("Ternary Digits") ax1.legend(ncol=4, fontsize=6) # 2. Ondalık değer grafiği (convert_to_float kullan) decimal_values = [convert_to_float(x) for x in sequence] ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(decimal_values, 'o-', color='tab:green') ax2.set_title("Decimal Values") # 3. PCA (isteğe bağlı) if use_pca and len(sequence) > 2: try: from sklearn.decomposition import PCA pca = PCA(n_components=2) proj = pca.fit_transform(digits) ax3 = fig.add_subplot(gs[1, :]) sc = ax3.scatter(proj[:, 0], proj[:, 1], c=range(len(proj)), cmap='viridis', s=25) ax3.set_title(f"PCA (Var: {sum(pca.explained_variance_ratio_):.3f})") plt.colorbar(sc, ax=ax3, label="Iteration") except Exception as e: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, f"PCA Error: {e}", ha='center', va='center') else: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, "Install sklearn or increase sequence length for PCA", ha='center', va='center') """ """ elif isinstance(first_elem, TernaryNumber): digits_list = [] for x in sequence: if isinstance(x, TernaryNumber): digits = x.digits # property veya attribute elif isinstance(x, list): digits = x else: digits = [int(x)] # scalar fallback digits_list.append(digits) max_len = max(len(d) for d in digits_list) padded = [d + [0]*(max_len - len(d)) for d in digits_list] digits = np.array(padded, dtype=float) #elif isinstance(first_elem, (TernaryNumber, list)): #ERNARY grafik - list uyumlu # ✅ SORUN: x.digits → list fallback kontrolü def safe_digits(obj): #TernaryNumber veya list → digits listesi if isinstance(obj, list): return obj # Direkt list kullan try: return obj.digits # TernaryNumber.digits except: return [float(obj)] # Scalar fallback # Tüm nesnelerin digits uzunluğunu belirle all_digits = [safe_digits(x) for x in sequence] max_length = max(len(d) for d in all_digits) # Padding yap padded_digits = [] for d in all_digits: padded = d + [0.0] * (max_length - len(d)) padded_digits.append(padded) digits = np.array(padded_digits) gs = GridSpec(2, 2, figure=fig) # 1. Ternary digits çizimi ax1 = fig.add_subplot(gs[0, 0]) for i in range(digits.shape[1]): ax1.plot(digits[:, i], 'o-', alpha=0.6, label=f'digit {i}') ax1.set_title("Ternary Digits") ax1.legend(ncol=4, fontsize=6) # 2. Ondalık değerler ax2 = fig.add_subplot(gs[0, 1]) def safe_decimal(obj): #TernaryNumber.to_decimal() veya list → float if isinstance(obj, list): return sum(obj) # Basit toplam try: return obj.to_decimal() except: return float(obj) decimal_values = np.array([safe_decimal(x) for x in sequence]) ax2.plot(decimal_values, 'o-', color='tab:green') ax2.set_title("Decimal Values") # 3. PCA (opsiyonel) if use_pca and len(sequence) > 2: try: from sklearn.decomposition import PCA pca = PCA(n_components=2) proj = pca.fit_transform(digits) ax3 = fig.add_subplot(gs[1, :]) sc = ax3.scatter(proj[:, 0], proj[:, 1], c=range(len(proj)), cmap='viridis', s=25) ax3.set_title(f"PCA (Var: {sum(pca.explained_variance_ratio_):.3f})") plt.colorbar(sc, ax=ax3, label="Iteration") except ImportError: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, "sklearn yok\npip install scikit-learn", ha='center', va='center', fontsize=10) except Exception as e: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, f"PCA Error: {str(e)[:30]}", ha='center', va='center', fontsize=10) else: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, "PCA için 3+ örnek\nveya sklearn kurun", ha='center', va='center', fontsize=10) """ """ elif isinstance(first_elem, TernaryNumber): # Tüm TernaryNumber nesnelerinin digits uzunluğunu belirle max_length = max(len(x.digits) for x in sequence) # Her bir TernaryNumber nesnesinin digits listesini max_length uzunluğuna tamamla padded_digits = [] for x in sequence: padded_digit = x.digits + [0] * (max_length - len(x.digits)) padded_digits.append(padded_digit) # NumPy dizisine dönüştür digits = np.array(padded_digits) gs = GridSpec(2, 2, figure=fig) # 2 satır, 2 sütun # Her bir rakamın dağılımını çizdir ax1 = fig.add_subplot(gs[0, 0]) for i in range(digits.shape[1]): ax1.plot(digits[:, i], 'o-', alpha=0.6, label=f'digit {i}') ax1.set_title("Ternary Digits") ax1.legend(ncol=4, fontsize=6) # Üçlü sayı sistemindeki değerleri ondalık sisteme çevirip çizdir decimal_values = np.array([x.to_decimal() for x in sequence]) ax2 = fig.add_subplot(gs[0, 1]) ax2.plot(decimal_values, 'o-', color='tab:green') ax2.set_title("Decimal Values") if use_pca and len(sequence) > 2: try: # PCA için veriyi hazırla pca = PCA(n_components=2) proj = pca.fit_transform(digits) # PCA projeksiyonunu çizdir ax3 = fig.add_subplot(gs[1, :]) # 2. satırın tamamını kullan sc = ax3.scatter(proj[:, 0], proj[:, 1], c=range(len(proj)), cmap='viridis', s=25) ax3.set_title(f"PCA Projection (Var: {sum(pca.explained_variance_ratio_):.3f})") plt.colorbar(sc, ax=ax3, label="Iteration") except Exception as e: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, f"PCA Error: {e}", ha='center', va='center', fontsize=10) else: ax3 = fig.add_subplot(gs[1, :]) ax3.text(0.5, 0.5, "Install sklearn\nfor PCA", ha='center', va='center', fontsize=10) """ # --- 23. HypercomplexNumber elif isinstance(first_elem, HypercomplexNumber): # try to extract coefficient array from sequence of HypercomplexNumber-like objects def _extract_coeffs_list(seq, complex_mode="real"): out = [] for v in seq: try: if hasattr(v, "to_list") and callable(v.to_list): comps = v.to_list() elif hasattr(v, "coeffs"): c = v.coeffs if not callable(v.coeffs) else v.coeffs() comps = list(c) elif hasattr(v, "components"): c = ( v.components if not callable(v.components) else v.components() ) comps = list(c) elif hasattr(v, "__iter__") and not isinstance(v, (str, bytes)): comps = list(v) else: comps = [v] # normalize norm = [] for c in comps: if isinstance(c, complex): val = ( float(abs(c)) if complex_mode == "magnitude" else float(c.real) ) else: val = float(c) norm.append(val) out.append(norm) except: out.append([0.0]) return out # HypercomplexNumber için coeffs_list oluşturulduktan sonra: coeffs_list = _extract_coeffs_list(sequence, complex_mode="real") # Her satır aynı uzunlukta mı? Değilse padding yap max_dim = max(len(row) for row in coeffs_list) if coeffs_list else 1 padded = [row + [0.0] * (max_dim - len(row)) for row in coeffs_list] coeffs = np.array(padded, dtype=float) # Tüm satırları aynı uzunluğa getir (padding) if coeffs_list: max_len = max(len(row) for row in coeffs_list) padded = [row + [0.0] * (max_len - len(row)) for row in coeffs_list] coeffs = np.array(padded, dtype=float) else: coeffs = np.array([]) # Eğer hiç veri yoksa veya boyutlar uygun değilse hata mesajı göster if coeffs.size == 0 or coeffs.ndim < 2: ax = fig.add_subplot(1, 1, 1) ax.text( 0.5, 0.5, "No valid coefficient data for HypercomplexNumber", ha="center", va="center", ) return fig n_samples, dim = coeffs.shape """ try: def _extract_coeffs_list(seq, complex_mode='real'): seq: iterable of values (HypercomplexNumber or lists or scalars) complex_mode: 'real' | 'magnitude' (how to handle complex components) Returns: list of lists (samples x components) as floats out = [] for v in seq: try: # Prefer explicit conversion helpers if present if hasattr(v, 'to_list') and callable(getattr(v, 'to_list')): comps = v.to_list() elif hasattr(v, 'to_components') and callable(getattr(v, 'to_components')): comps = v.to_components() elif hasattr(v, 'coeffs'): c = v.coeffs() if callable(getattr(v, 'coeffs')) else v.coeffs comps = list(c) elif hasattr(v, 'components'): c = v.components() if callable(getattr(v, 'components')) else v.components comps = list(c) elif hasattr(v, '__iter__') and not isinstance(v, (str, bytes)): comps = list(v) else: comps = [v] # normalize components to floats norm = [] for c in comps: if isinstance(c, complex): if complex_mode == 'magnitude': norm.append(float(abs(c))) else: # default: real part norm.append(float(c.real)) else: try: norm.append(float(c)) except Exception: # non-numeric component -> 0.0 norm.append(0.0) out.append(norm) except Exception as e: logger.debug("extract coeffs failed for %r: %s", v, e) out.append([0.0]) return out except Exception as e: # if extraction fails, show a message on the figure and bail out gracefully ax = fig.add_subplot(111) ax.text(0.5, 0.5, f"Coefficient extraction failed:\n{e}", ha='center', va='center', fontsize=10) logger.exception("Coefficient extraction failed") return fig """ def _pca_var_sum(pca_obj) -> float: """ Safely return sum of PCA explained variance ratio. - Uses pca_obj.explained_variance_ratio_ when available. - Returns 0.0 for missing, NaN, infinite or invalid values. """ try: arr = getattr(pca_obj, "explained_variance_ratio_", None) if arr is None: return 0.0 arr = np.asarray(arr, dtype=float) s = float(np.nansum(arr)) return s if np.isfinite(s) else 0.0 except Exception: return 0.0 # coeffs_list = _extract_coeffs_list(sequence, complex_mode='real') # coeffs = np.array(coeffs_list, dtype=float) # dimensions and magnitudes n_samples, dim = coeffs.shape magnitudes = np.linalg.norm(coeffs, axis=1) # Create or reuse figure with constrained_layout to avoid tight_layout/colorbar conflicts try: _ = fig # reuse existing fig if present except NameError: fig = plt.figure(figsize=(12, 8), constrained_layout=True) else: try: fig.set_constrained_layout(True) except Exception: pass # layout decisions based on dimension if dim <= 16: cols = 4 rows = int(np.ceil(dim / cols)) # Reserve an extra row for magnitude / PCA gs = GridSpec(rows + 1, cols, figure=fig, height_ratios=[1] * rows + [0.8]) axes = [] for i in range(dim): r = i // cols c = i % cols ax = fig.add_subplot(gs[r, c]) ax.plot(coeffs[:, i], "-", linewidth=0.8, alpha=0.8) ax.set_title(f"e{i}", fontsize=8) axes.append(ax) # magnitude plot in the first slot of the last row axm = fig.add_subplot(gs[rows, 0]) axm.plot(magnitudes, "o-", color="tab:orange") axm.set_title("Magnitude |v|", fontsize=9) axm.set_xlabel("Iteration") axm.set_ylabel("|v|") # PCA panel if requested if use_pca: try: if PCA is None: raise RuntimeError("sklearn not available for PCA") if n_samples > 2: pca = PCA(n_components=2) proj = pca.fit_transform(coeffs) axp = fig.add_subplot(gs[rows, 1]) sc = axp.scatter( proj[:, 0], proj[:, 1], c=np.arange(n_samples), cmap="viridis", s=20, ) var_sum = _pca_var_sum(pca) axp.set_title(f"PCA (Var: {var_sum:.3f})", fontsize=9) try: cbar = fig.colorbar(sc, ax=axp, fraction=0.046, pad=0.02) cbar.ax.tick_params(labelsize=8) except Exception as e: logger.debug("PCA colorbar failed: %s", e) else: axp = fig.add_subplot(gs[rows, 1]) axp.text( 0.5, 0.5, "Not enough samples for PCA", ha="center", va="center", ) except Exception as e: axp = fig.add_subplot(gs[rows, 1]) axp.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=8, ) logger.debug("PCA error: %s", e) else: # high-dimensional case: show first 64 components in two panels, heatmap for all components, magnitude and PCA gs = GridSpec(3, 2, figure=fig, height_ratios=[1, 1, 0.6]) # panel 1: components 0..min(63, dim-1) ax1 = fig.add_subplot(gs[0, 0]) max_plot = min(64, dim) for i in range(0, max_plot): ax1.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.4) ax1.set_title(f"Components e0-e{max_plot - 1}", fontsize=9) ax1.legend(ncol=4, fontsize=6, loc="upper right") # panel 2: components 64..127 if available ax2 = fig.add_subplot(gs[0, 1]) if dim > 64: max_plot2 = min(128, dim) for i in range(64, max_plot2): ax2.plot(coeffs[:, i], label=f"e{i}", alpha=0.6, linewidth=0.4) ax2.set_title(f"Components e64-e{max_plot2 - 1}", fontsize=9) ax2.legend(ncol=4, fontsize=6, loc="upper right") else: ax2.text( 0.5, 0.5, "No components 64+", ha="center", va="center", fontsize=10 ) # panel 3: magnitude ax3 = fig.add_subplot(gs[1, 0]) ax3.plot(magnitudes, "o-", color="tab:orange") ax3.set_title("Magnitude |v|", fontsize=9) # panel 4: heatmap of coefficients (samples x components) but downsample if huge ax4 = fig.add_subplot(gs[1, 1]) try: # downsample rows if too many samples for display display_coeffs = coeffs if n_samples > 500: idx = np.linspace(0, n_samples - 1, 500).astype(int) display_coeffs = coeffs[idx, :] # downsample columns if too many components if dim > 1024: cidx = np.linspace(0, dim - 1, 1024).astype(int) display_coeffs = display_coeffs[:, cidx] im = ax4.imshow( display_coeffs.T, aspect="auto", cmap="RdBu_r", origin="lower" ) ax4.set_title("Coefficient heatmap (components x samples)", fontsize=9) try: cbar = fig.colorbar(im, ax=ax4, fraction=0.046, pad=0.04) cbar.ax.tick_params(labelsize=8) except Exception as e: logger.debug("Heatmap colorbar failed: %s", e) except Exception as e: ax4.text( 0.5, 0.5, f"Heatmap Error: {e}", ha="center", va="center", fontsize=8, ) logger.debug("Heatmap error: %s", e) # PCA row below if use_pca: try: if PCA is None: raise RuntimeError("sklearn not available for PCA") if n_samples > 2: pca = PCA(n_components=2) proj = pca.fit_transform(coeffs) axp = fig.add_subplot(gs[2, :]) sc = axp.scatter( proj[:, 0], proj[:, 1], c=np.arange(n_samples), cmap="viridis", s=18, ) var_sum = _pca_var_sum(pca) axp.set_title( f"PCA Projection (Var: {var_sum:.3f})", fontsize=9 ) try: cbar2 = fig.colorbar(sc, ax=axp, fraction=0.046, pad=0.02) cbar2.ax.tick_params(labelsize=8) except Exception as e: logger.debug("PCA colorbar failed: %s", e) else: axp = fig.add_subplot(gs[2, :]) axp.text( 0.5, 0.5, "Not enough samples for PCA", ha="center", va="center", ) except Exception as e: axp = fig.add_subplot(gs[2, :]) axp.text( 0.5, 0.5, f"PCA Error: {e}", ha="center", va="center", fontsize=10, ) logger.debug("PCA error: %s", e) else: axp = fig.add_subplot(gs[2, :]) axp.text( 0.5, 0.5, "Install sklearn for PCA", ha="center", va="center", fontsize=10, ) # final: do not call tight_layout when constrained_layout=True # return the figure to caller return fig # --- 24. Bilinmeyen tip else: ax = fig.add_subplot(1, 1, 1) type_name = type(first_elem).__name__ ax.text( 0.5, 0.5, f"Plotting not implemented\nfor '{type_name}'", ha="center", va="center", fontsize=14, fontweight="bold", color="red", ) ax.set_xticks([]) ax.set_yticks([]) plt.show()
# Test kodu def test_division(): test_cases = [ (10, 2, 5.0), (10, 0, float("inf")), (complex(10, 0), 2, complex(5, 0)), (Fraction(10, 1), 2, Fraction(5, 1)), (-10, 2, -5.0), (10, -2, -5.0), ] for a, b, expected in test_cases: try: result = _safe_divide(a, b) print( f"{a} / {b} = {result} (expected: {expected}) - {'✓' if str(result) == str(expected) else '✗'}" ) except Exception as e: print(f"{a} / {b} = ERROR: {e}") # ==================== TEST YÜRÜTÜCÜ ==================== def run_cramer_test( type_num, start, add, iterations=1000, first_divisor=3, ask_plus_first=True ): seq = None try: seq = get_with_params( kececi_type_choice=type_num, iterations=iterations, start_value_raw=str(start), add_value_raw=str(add), # include_intermediate_steps=True, ternaryyi bulamıyor include_intermediate_steps=False, first_divisor=first_divisor, ask_plus_first=ask_plus_first, ) if not seq or len(seq) < 20: return {"success": False, "reason": "SHORT_SEQUENCE"} kpn, method = find_kpn(seq) if kpn is None: return {"success": False, "reason": "NO_KPN"} positions = [i for i, x in enumerate(seq) if robust_int(x) == kpn] if len(positions) < 2: return {"success": False, "reason": "TOO_FEW_KPN"} gaps = np.diff(positions) max_gap = float(np.max(gaps)) n_total = len(seq) bound = (math.log(max(n_total, 100))) ** 2 * 0.5 ratio = max_gap / bound if bound > 0 else float("inf") if ratio >= 1: return {"success": False, "reason": f"RATIO_EXCEEDED ({ratio:.4f})"} return { "success": True, "type": type_num, "type_name": TYPE_NAMES.get(type_num, str(type_num)), "start": start, "add": add, "kpn": kpn, "kpn_count": len(positions), "kpn_freq": len(positions) / n_total, "max_gap": max_gap, "n_total": n_total, "ratio": ratio, "method": method, "first_divisor": first_divisor, "ask_plus_first": ask_plus_first, } except Exception as e: return {"success": False, "reason": f"EXCEPTION: {str(e)[:80]}"} finally: if seq is not None: del seq # Eğer çok büyük dizilerle çalışıyorsanız ve bellek sorunu yaşıyorsanız, aşağıdaki satırı açabilirsiniz: # import gc; gc.collect() def run_test( type_num, start, add, iterations=1000, first_divisor=3, ask_plus_first=True ): seq = None try: seq = get_with_params( kececi_type_choice=type_num, iterations=iterations, start_value_raw=str(start), add_value_raw=str(add), # include_intermediate_steps=True, ternaryyi bulamıyor include_intermediate_steps=False, first_divisor=first_divisor, ask_plus_first=ask_plus_first, ) if not seq or len(seq) < 20: return {"success": False, "reason": "SHORT_SEQUENCE"} kpn, method = find_kpn(seq) if kpn is None: return {"success": False, "reason": "NO_KPN"} positions = [i for i, x in enumerate(seq) if robust_int(x) == kpn] if len(positions) < 2: return {"success": False, "reason": "TOO_FEW_KPN"} gaps = np.diff(positions) max_gap = float(np.max(gaps)) n_total = len(seq) bound = (math.log(max(n_total, 100))) ** 2 * 0.5 ratio = max_gap / bound if bound > 0 else float("inf") if ratio >= 1: return {"success": False, "reason": f"RATIO_EXCEEDED ({ratio:.4f})"} return { "success": True, "type": type_num, "type_name": TYPE_NAMES.get(type_num, str(type_num)), "start": start, "add": add, "kpn": kpn, "kpn_count": len(positions), "kpn_freq": len(positions) / n_total, "max_gap": max_gap, "n_total": n_total, "ratio": ratio, "method": method, "first_divisor": first_divisor, "ask_plus_first": ask_plus_first, } except Exception as e: return {"success": False, "reason": f"EXCEPTION: {str(e)[:80]}"} finally: if seq is not None: del seq """ def run_test(type_num, start, add, iterations=1000): seq = None try: # Daha az bellek için 1000 adım seq = get_with_params( kececi_type_choice=type_num, iterations=iterations//10, start_value_raw=start, add_value_raw=add, include_intermediate_steps=True ) if not seq or len(seq) < 100: return {'success': False, 'reason': 'SHORT_SEQUENCE'} kpn = safe_find_kpn(seq, type_num) if kpn is None: return {'success': False, 'reason': 'NO_KPN'} positions = [] for i, x in enumerate(seq): try: if robust_int(x) == kpn: # Yumuşak kontrol positions.append(i) except: continue if len(positions) < 2: return {'success': False, 'reason': 'TOO_FEW_KPN'} gaps = np.diff(positions) max_gap = float(np.max(gaps)) n_total = len(seq) bound = (math.log(max(n_total, 100))) ** 2 * 0.5 ratio = max_gap / bound if ratio >= 1: return {'success': False, 'reason': f'RATIO_EXCEEDED ({ratio:.4f})'} return { 'success': True, 'type': type_num, 'type_name': TYPE_NAMES[type_num], 'start': start, 'add': add, 'kpn': kpn, 'kpn_count': len(positions), 'kpn_freq': len(positions)/n_total, 'max_gap': max_gap, 'n_total': n_total, 'ratio': ratio } except Exception as e: return {'success': False, 'reason': f'EXCEPTION: {str(e)[:80]}'} finally: del seq gc.collect() """ # -------------------- Kuantum API -------------------- def get_quantum_random_numbers( length: int = 1, min_val: int = 0, max_val: int = 100, verbose: bool = False ): """ ANU Quantum Random Numbers API'den istenen sayıda rastgele sayı alır. Büyük istekleri otomatik olarak parçalara böler. """ CHUNK_SIZE = 1000 source = "api" all_numbers = [] for i in range(0, length, CHUNK_SIZE): chunk_length = min(CHUNK_SIZE, length - i) url = f"https://qrng.anu.edu.au/API/jsonI.php?length={chunk_length}&type=uint16" try: response = requests.get(url, timeout=15) if response.status_code == 200: data = response.json() raw = data.get("data", []) if len(raw) >= chunk_length: scaled = [ int(min_val + (x / 65535) * (max_val - min_val)) for x in raw[:chunk_length] ] all_numbers.extend(scaled) if verbose: print( f"✅ API'den {len(scaled)} adet rastgele sayı alındı (parça {i // CHUNK_SIZE + 1}/{(length - 1) // CHUNK_SIZE + 1})." ) else: if verbose: print( f"⚠️ API yetersiz veri döndü. ({len(raw)} < {chunk_length})" ) return _fallback_random_numbers(length, min_val, max_val, verbose) else: if verbose: print(f"⚠️ API yanıt kodu: {response.status_code}") return _fallback_random_numbers(length, min_val, max_val, verbose) except Exception as e: if verbose: print(f"⚠️ API bağlantı hatası: {e}") return _fallback_random_numbers(length, min_val, max_val, verbose) return all_numbers, "api" def _fallback_random_numbers(length, min_val, max_val, verbose): if verbose: print("↳ Sistemin güvenli rastgele üretecine geçiliyor (SystemRandom).") system_random = random.SystemRandom() numbers = [system_random.randint(min_val, max_val) for _ in range(length)] return numbers, "system_random" def get_quantum_random_numbers_with_retry(length, max_retries=3): for attempt in range(max_retries): nums, src = get_quantum_random_numbers(length, verbose=True) if src == "api": return nums, src print(f"Deneme {attempt + 1} başarısız, 120 saniye bekleniyor...") time.sleep(120) # Hala olmazsa fallback return get_quantum_random_numbers( length, verbose=False ) # tekrar dene ama bu sefer sessiz # -------------------- Tekrar Eden Kalıp Bulma -------------------- def find_repeating_pattern(sequence): n = len(sequence) best_pattern = None max_repetitions = 1 best_start_index = 0 for pattern_length in range(1, n // 2 + 1): for i in range(n - 2 * pattern_length + 1): pattern = sequence[i : i + pattern_length] repetitions = 1 k = 1 while i + (k + 1) * pattern_length <= n: if ( sequence[i + k * pattern_length : i + (k + 1) * pattern_length] == pattern ): repetitions += 1 k += 1 else: break if repetitions > max_repetitions: max_repetitions = repetitions best_pattern = pattern best_start_index = i if best_pattern and max_repetitions > 1: return best_pattern, best_start_index else: return None, None # -------------------- Yardımcı: Ternary Dönüşüm -------------------- def to_ternary(num): if num == 0: return "0" digits = [] n = abs(num) while n > 0: digits.append(str(n % 3)) n //= 3 return "".join(reversed(digits)) def shorten_string(s, max_len=30): s = str(s) return s[:max_len] + "..." if len(s) > max_len else s def ternary_to_decimal(s: str) -> int: """Ternary string'i 10 tabanına çevirir.""" try: return int(s, 3) except ValueError: return 0 def extract_numericval(v): if hasattr(v, "real"): return v.real if hasattr(v, "value"): return extract_numericval(v.value) if isinstance(v, (int, float)): return v if isinstance(v, (tuple, list)): return extract_numericval(v[0]) if len(v) > 0 else 0 s = str(v) if "TernaryNumber" in s or "Ternary" in s: match = re.search(r"\(([^)]+)\)", s) if match: return ternary_to_decimal(match.group(1).strip()) digits = re.findall(r"\d+", s) if digits: return ternary_to_decimal(digits[0]) return 0 nums = re.findall(r"[-+]?\d*\.?\d+", s) if nums: return float(nums[0]) return 0 # -------------------- Grafik Çizimi -------------------- def plot_kececi_with_pattern(sequence, title, filename, kpn=None, intermediate=True): if sequence and isinstance(sequence[0], dict): values = [item["value"] for item in sequence] else: values = sequence # Tüm değerleri float'a çevir (Fraction, ... için) numeric_values = [] for v in values: try: val = extract_numericval(v) numeric_values.append(float(val)) except: numeric_values.append(0.0) print(f" İlk 10 sayısal değer: {numeric_values[:10]}") if numeric_values: print(f" Min: {min(numeric_values)}, Max: {max(numeric_values)}") plt.figure(figsize=(14, 7), facecolor="#f0f0f0") plt.plot( numeric_values, marker="o", linestyle="-", color="#2980b9", markersize=5, linewidth=2.5, label="Dizi Değerleri", zorder=2, ) pattern, start_idx = find_repeating_pattern(numeric_values) if pattern: pattern_length = len(pattern) plt.axvspan( start_idx, start_idx + pattern_length, facecolor="#f39c12", alpha=0.3, label="Tekrarlayan Alan", zorder=0, ) print( f" Tekrarlayan kalıp bulundu: başlangıç indeksi={start_idx}, uzunluk={pattern_length}" ) else: print(" Tekrarlayan kalıp bulunamadı.") if numeric_values: y_min = min(numeric_values) - 1 y_max = max(numeric_values) + 1 plt.ylim(y_min, y_max) kpn_str = f"KPN={kpn}" if kpn else "KPN=Bulunamadı" ara_str = "Ara Adım: Var" if intermediate else "Ara Adım: Yok" full_title = f"{title}\n{kpn_str} | {ara_str}" plt.xlabel("Adım Sayısı", fontsize=14) plt.ylabel("Değer", fontsize=14) plt.title(full_title, fontsize=16, fontweight="bold") plt.grid(True, linestyle="--", alpha=0.6) plt.legend() plt.tight_layout() plt.savefig(filename, dpi=150, bbox_inches="tight") plt.close() def kececi_numbers_complex(start, add_value, iterations, random_source="classical"): """ Gerçek Keçeci Sayıları'nı kompleks sayılarla hesaplar. """ sequence = [start + 1j * start] # Başlangıç sayısı kompleks current = start + 1j * start last_divisor = None ask_counter = 0 for _ in range(iterations): added = current + add_value + 1j * add_value # Gerçek ve sanal kısım eşit sequence.append(added) if last_divisor is None: intended = 3 elif last_divisor == 3: intended = 2 elif last_divisor == 2: intended = 3 alternative = 2 if intended == 3 else 3 if added.real % intended == 0: result = added / intended last_divisor = intended elif added.real % alternative == 0: result = added / alternative last_divisor = alternative else: if is_prime(abs(added.real)): if ask_counter == 0: modified = added + 1 + 1j # Kompleks bileşeni de artır ask_counter = 1 else: modified = added - 1 - 1j # Kompleks bileşeni de azalt ask_counter = 0 sequence.append(modified) if modified.real % intended == 0: result = modified / intended last_divisor = intended elif modified.real % alternative == 0: result = modified / alternative last_divisor = alternative else: result = modified else: result = added sequence.append(result) current = result return sequence def kececi_to_color(kececi_number): """Klasik rastgelelikle Keçeci sayısını RGB değerlerine dönüştürür.""" r = int((abs(kececi_number.real) * random.random()) % 256) g = int((abs(kececi_number.imag) * random.random()) % 256) b = int(((r + g) * random.random()) % 256) return (r, g, b) def generate_geometric_kececi_art( start, add_value, width, height, shape_type="square", random_source="classical", filename="geometric_kececi_art.png", ): """Keçeci Sayıları'nı kullanarak geometrik şekillerden oluşan sanatsal bir görüntü oluşturur.""" iterations = 75 # Şekil sayısı sequence = kececi_numbers_complex(start, add_value, iterations, random_source) img = Image.new("RGB", (width, height), color="white") draw = ImageDraw.Draw(img) # Eğer kaynak "quantum" ise, toplu olarak rastgele sayıları API'den al quantum_numbers = None q_source = None if random_source == "quantum": # Her şekil için 5 sayı: R,G,B,x,y # total_needed = iterations * 5 total_needed = len(sequence) * 5 q_numbers, q_source = get_quantum_random_numbers( total_needed, min_val=0, max_val=65535, verbose=True ) # Eğer q_source "system_random" veya "hybrid" ise, aslında klasik de kullanıldı, bunu not edelim if q_source in ("system_random", "hybrid", "partial_api"): print( f"⚠️ Kuantum kaynağı tam kullanılamadı, kaynak: {q_source}. Bazı sayılar klasik (SystemRandom) ile tamamlandı." ) quantum_numbers = q_numbers # liste # Güvenlik: quantum_numbers boyutunu kontrol et if len(quantum_numbers) < total_needed: print( f"⚠️ Uyarı: Beklenen {total_needed} sayı yerine {len(quantum_numbers)} sayı alındı. Eksikler fallback ile doldurulacak." ) # Bu durum get_quantum_random_numbers içinde zaten tamamlanmış olmalı, ama tekrar kontrol while len(quantum_numbers) < total_needed: quantum_numbers.append(random.SystemRandom().randint(0, 65535)) idx = 0 for i, kececi_number in enumerate(sequence): if ( random_source == "quantum" and quantum_numbers is not None and idx + 4 < len(quantum_numbers) ): # Kuantumdan alınan sayıları kullan r = int(quantum_numbers[idx] * 255 / 65535) idx += 1 g = int(quantum_numbers[idx] * 255 / 65535) idx += 1 b = int(quantum_numbers[idx] * 255 / 65535) idx += 1 x = int(quantum_numbers[idx] * width / 65535) idx += 1 y = int(quantum_numbers[idx] * height / 65535) idx += 1 color = (r, g, b) else: # Klasik: mevcut yöntem (eğer quantum seçili ama sayılar bittiyse de buraya düşer) if random_source == "quantum" and quantum_numbers is not None: # Eğer idx listenin dışına çıktıysa, tekrar başa sar veya mevcut değerleri kullan print( f"⚠️ Kuantum sayıları bitti, {i}. adımda klasik yönteme geçiliyor." ) # Basitçe mevcut kececi_number'dan renk üret color = kececi_to_color(kececi_number) # Konum için de kececi_number'ı kullan x = int((kececi_number.real * i) % width) y = int((kececi_number.imag * i) % height) else: color = kececi_to_color(kececi_number) x = int((kececi_number.real * i) % width) y = int((kececi_number.imag * i) % height) size = int((abs(kececi_number.real) + abs(kececi_number.imag)) % 50) + 10 if shape_type == "square": draw.rectangle((x, y, x + size, y + size), fill=color) elif shape_type == "circle": draw.ellipse((x, y, x + size, y + size), fill=color) elif shape_type == "triangle": points = [(x, y), (x + size // 2, y + size), (x + size, y)] draw.polygon(points, fill=color) else: # Default square draw.rectangle((x, y, x + size, y + size), fill=color) img.save(filename) if random_source == "quantum" and quantum_numbers is not None: if q_source in ("api", "hybrid", "partial_api", "system_random"): source_text = f"Kuantum (kaynak: {q_source})" else: source_text = ( "Kuantum (API)" if q_source == "api" else "Klasik (SystemRandom fallback)" ) else: source_text = "Klasik (random)" print( f"Geometrik Keçeci sanatı '{filename}' oluşturuldu. Kullanılan kaynak: {source_text}" ) # ============================================================================== # --- MAIN EXECUTION BLOCK --- # ============================================================================== if __name__ == "__main__": # If user runs module directly, configure basic logging to console for demonstration. logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") logger.info("Keçeci Numbers Module - Demonstration") logger.info( "This script demonstrates the generation of various Keçeci Number types." ) STEPS = 30 START_VAL = "2.5" ADD_VAL = 3.0 all_types = { "Positive Real": TYPE_POSITIVE_REAL, "Negative Real": TYPE_NEGATIVE_REAL, "Complex": TYPE_COMPLEX, "Float": TYPE_FLOAT, "Rational": TYPE_RATIONAL, "Quaternion": TYPE_QUATERNION, "Neutrosophic": TYPE_NEUTROSOPHIC, "Neutrosophic Complex": TYPE_NEUTROSOPHIC_COMPLEX, "Hyperreal": TYPE_HYPERREAL, "Bicomplex": TYPE_BICOMPLEX, "Neutrosophic Bicomplex": TYPE_NEUTROSOPHIC_BICOMPLEX, "Octonion": TYPE_OCTONION, "Sedenion": TYPE_SEDENION, "Clifford": TYPE_CLIFFORD, "Dual": TYPE_DUAL, "Splitcomplex": TYPE_SPLIT_COMPLEX, "Pathion": TYPE_PATHION, "Chingon": TYPE_CHINGON, "Routon": TYPE_ROUTON, "Voudon": TYPE_VOUDON, "Super Real": TYPE_SUPERREAL, "Ternary": TYPE_TERNARY, "Hypercomplex": TYPE_HYPERCOMPLEX, } for name, type_id in all_types.items(): start = ( "-5" if type_id == TYPE_NEGATIVE_REAL else "2+3j" if type_id in [TYPE_COMPLEX, TYPE_BICOMPLEX] else START_VAL ) try: seq = get_with_params(type_id, STEPS, start, ADD_VAL) if seq: logger.info("Generated sequence for %s (len=%d).", name, len(seq)) # Optional: plot for a few selected types to avoid overloading user's environment except Exception as e: logger.exception("Demo generation failed for type %s: %s", name, e) logger.info("Demonstration finished.")