import os
# import sys
import inspect
# import traceback
import numpy as np
import datetime as dt
# import uuid
import warnings, traceback

import astropy.units as u
from astropy import uncertainty as unc

from .utils.versioning import HeadVer
from .utils.pydocformatter import PyDocFormatter
from .valueu import ValueU

class QuantityU:
    __fullname = 'Uncertainty-bearing Quantity'
    __firstwritten = dt.datetime.strptime('2023-09-06', '%Y-%m-%d')
    __lastupdate = dt.datetime.strptime('2026-03-20', '%Y-%m-%d')
    __version = HeadVer(1, __lastupdate, 7)
    __developer = {'name': 'DH.Koh', 'contact': 'donghyeok.koh.code@gmail.com'}
    __collaborators = [{'name': 'JH.Kim', 'contact': None}, {'name': 'KM.Heo', 'contact': None}]
    __contributors = [{'name': None, 'role': None}]
    __callsign = 'Quantity(+/-)'

    __versiondependency = {}

    __array_priority__ = 12000
    _n_samples = None  # Number of samples for uncertainty distribution
    _n_samples_defaultvalue = ValueU._n_samples_defaultvalue  # Default value of __n_samples
    # Sync with ValueU's n_samplesif n_samples is None

    def __init__(self, center=None, std=None, n_samples=None, dtype:np.generic=None):
        # self.__id = uuid.uuid4()  # time.perf_counter_ns()

        if center is None:
            center = np.nan * u.dimensionless_unscaled

        if std is None:
            std = np.nan

        if n_samples is None:
            self.n_samples = ValueU._n_samples_defaultvalue  # Default number of samples for uncertainty distribution
        else:
            try:
                if n_samples == int(n_samples):
                    self.n_samples = int(n_samples)
            except:
                raise TypeError(f'{self.__callsign.ljust(10)}: Input argument \"n_samples\" must be an integer value.')

        if dtype is None:
            self.dtype = np.float32
        elif issubclass(dtype, np.number):
            self.dtype = dtype
        else:
            self.dtype = np.float32

        self._comparison_criterion_by_center = True
        self._comparison_criterion_threshold = None
        # self.enforced_positive = None
        # self.enforced_negative = None

        ### initialize
        self.unit = u.dimensionless_unscaled
        self.distribution = unc.Distribution([np.nan]).astype(self.dtype) * self.unit

        ### recognize value
        generated_distribution = self._generate_distribution(center=center, std=std)

        self._digit_round = 4
        self._digit_stringformat = 7

        return None

    @property
    def value(self):
        """
        [Protected]
        Synchronizes the instance's internal metadata with the current state of the distribution.
        Although primarily designed for internal consistency, it may be manually called by users if necessary.
        """
        return ValueU(n_samples=self.n_samples).set_manual(
            center=self.center.value,
            distribution=unc.Distribution(self.distribution.distribution.value),
            dtype=self.dtype,
        ).set_digit(
            digit_round=self._digit_round,
            digit_stringformat=self._digit_stringformat
        )

    def _sync_info(self):
        """
        [Protected]
        Synchronizes the instance's internal metadata with the current state of the distribution.
        Although primarily designed for internal consistency, it may be manually called by users if necessary.
        """
        self.n_samples = self.distribution.distribution.shape[-1]
        self.dtype = np.result_type(self.center.dtype, self.distribution.dtype)
        # assert self.n_samples == self.distribution.distribution.shape[-1], 'The shape of the distribution does not match the static number of samples.'

        self.unit = self.center.unit

        return self

    def __set_manual(self, center, distribution: unc.Distribution):
        """
        [Private] Manually sets attributes. Assumes inputs are pre-validated.
        """
        self.center = center
        self.distribution = distribution

        return self._sync_info()

    def set_manual(self, center: float = None, distribution: unc.Distribution = None, dtype:np.generic=None):
        """
        [Public] Provides a user-level interface for manually defining the center and distribution of the instance.
        If 'center' is not provided, it is automatically assigned the median value of the given distribution to ensure statistical consistency.
        """
        # if isinstance(center, unc.Distribution):
        #     raise TypeError(f'{self.__callsign.ljust(10)}: The input argument \"center\" should not be an instance of {unc.Distribution}.')
        if not isinstance(distribution, unc.Distribution):
            raise TypeError(f'{self.__callsign.ljust(10)}: The input argument \"distribution\" should be an instance of {unc.Distribution}.')

        if center is None:
            warnings.warn(
                message=f'{self.__callsign.ljust(10)}: Not provided center; automatically set to the median of the distribution.',
                category=UserWarning,
                stacklevel=2
            )
            # traceback.print_stack(limit=2)
            center = distribution.pdf_median()

        if dtype is None:
            dtype = np.result_type(center.dtype, distribution.dtype)

        center_temp = center if isinstance(center, u.Quantity) else center * u.dimensionless_unscaled
        distribution_temp = distribution if isinstance(distribution, u.Quantity) else distribution * u.dimensionless_unscaled

        assert center_temp.unit.is_equivalent(distribution_temp.unit), 'The unit of the center value must be equivalent to the unit of the distribution.'

        self.__set_manual(center=center_temp.astype(dtype), distribution=distribution_temp.astype(dtype))

        return self

    @property
    def enforced_positive(self):
        """
        [Public Property]
        Returns a new instance with a positive-enforced distribution.
        Replaces negative samples with NaN to maintain alignment while enforcing domain.
        """
        if self.center < 0:
            raise ValueError(
                f'{self.__callsign.ljust(10)}: Logical Contradiction, '
                f'Cannot enforce positive on a distribution with a negative center ({self.center}).'
            )

        """
        Replaces samples in the negative domain with NaN to preserve 
        the total sample count and alignment without distorting the valid distribution.
        """
        distribution_positive = np.where(self.distribution.distribution < 0, np.nan, self.distribution.distribution)

        return self.__class__().set_manual(
            center=self.center,
            # distribution=unc.Distribution(distribution_positive.astype(self.dtype))
            distribution = unc.Distribution(distribution_positive),
            dtype=self.dtype,
        ).set_digit(
            self._digit_round,
            self._digit_stringformat
        )

    @property
    def enforced_negative(self):
        """
        [Public Property]
        Returns a new instance with a positive-enforced distribution.
        Replaces negative samples with NaN to maintain alignment while enforcing domain.
        """
        if self.center > 0:
            raise ValueError(
                f'{self.__callsign.ljust(10)}: Logical Contradiction, '
                f'Cannot enforce negative on a distribution with a positive center ({self.center}).'
            )

        """
        Replaces samples in the positive domain with NaN to preserve 
        the total sample count and alignment without distorting the valid distribution.
        """
        enforced_negative = np.where(self.distribution.distribution > 0, np.nan, self.distribution.distribution)

        return self.__class__().set_manual(
            center=self.center,
            # distribution=unc.Distribution(enforced_negative.astype(self.dtype))
            distribution=unc.Distribution(enforced_negative),
            dtype=self.dtype,
        ).set_digit(
            self._digit_round,
            self._digit_stringformat
        )

    def __generate_distribution_symmetric(self, center=None, std=None):
        """
        [Private]
        Generate a symmetric distribution object 'self.distribution' from the input regulated information with unit.
        No return value. Direct user access is strictly prohibited.
        Usage (not allowed direct call this at the user level) :
        >>> self.__generate_distribution_symmetric(center=10 * u.m, std=1 * u.m)
        """
        assert center.unit == std.unit, f'{self.__callsign.ljust(10)}: Input argument \"std\" unit {std.unit} is not equivalent to the center value unit {center.unit}.'
        self.center, self.unit = self.dtype(center.value) * center.unit, center.unit

        distribution_generated = unc.normal(center=self.center, std=std, n_samples=self.n_samples)

        self.distribution = distribution_generated.astype(self.dtype).to(self.unit)

    def __generate_distribution_asymmetric(self, center=None, stds: np.ndarray = None):
        """
        [Private]
        Generate an asymmetric distribution object 'self.distribution' from the input regulated information with unit.
        Directly modify the instance variables to the process results without returning.
        Usage (not allowed direct call this at the user level) :
        >>> self.__generate_distribution_asymmetric(center=10 * u.m, std=np.array([1, 2]) * u.m)
        """
        assert center.unit == stds.unit, f'{self.__callsign.ljust(10)}: Input argument \"stds\" unit {stds.unit} is not equivalent to the center value unit {center.unit}.'
        self.center, self.unit = self.dtype(center.value) * center.unit, center.unit

        distribution_generated_primary = unc.normal(center=0 * self.unit, std=stds[1], n_samples=self.n_samples)
        distribution_generated_secondary = unc.Distribution(
            np.where(
                distribution_generated_primary.distribution < 0,
                distribution_generated_primary.distribution * (-stds[0] / stds[1]),
                distribution_generated_primary.distribution
            )
        )
        distribution_generated = (self.center + distribution_generated_secondary)

        self.distribution = distribution_generated.astype(self.dtype).to(self.unit)

    def _generate_distribution(self, center, std: np.ndarray):
        """
        [Protected]
        Categorize and process the input standard deviation
        Impossible to handle an input variable that is not structured as a shape twice the size of the central value
        Impossible to handle an input variable that cannot be processed as a numpy ndarray object
        Transport processed dispersion range to 'self.__generate_distribution_asymmetric' or 'self.__generate_distribution_symmetric'
        Usage (not recommand direct call this at the user level):
        >>> q = QuantityU(10)
        ... print(repr(q))
        QuantityU(10, (nan, nan))
        >>> q._set_error_relative([-1, 2])
        QuantityU(5, (-1, +2))
        """

        if isinstance(std, np.ndarray):
            if std.shape == (2,):
                ### Case (a-1) std= array([-number, +number])
                if isinstance(center, u.quantity.Quantity):
                    if isinstance(std, u.quantity.Quantity):
                        if center.unit.is_equivalent(std.unit):
                            self.__generate_distribution_asymmetric(center=center, stds=std.to(center.unit))
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" unit {std.unit} is not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_asymmetric(center=center, stds=std * center.unit)
                else:
                    if isinstance(std, u.quantity.Quantity):
                        self.__generate_distribution_asymmetric(center=center * std.unit, stds=std)
                    else:
                        self.__generate_distribution_asymmetric(center=center * u.dimensionless_unscaled, stds=std * u.dimensionless_unscaled)
            elif std.shape == (1,):
                ### Case (a-2) std= array([number])
                if isinstance(center, u.quantity.Quantity):
                    if isinstance(std, u.quantity.Quantity):
                        if center.unit.is_equivalent(std.unit):
                            self.__generate_distribution_symmetric(center=center, std=std[0].to(center.unit))
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" unit {std.unit} is not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_symmetric(center=center, std=std[0] * center.unit)
                else:
                    if isinstance(std, u.quantity.Quantity):
                        self.__generate_distribution_symmetric(center=center * std.unit, std=std[0])
                    else:
                        self.__generate_distribution_symmetric(center=center * u.dimensionless_unscaled, std=std[0] * u.dimensionless_unscaled)
            elif np.prod(std.shape) / np.prod(np.array(center).shape) == 2.:
                ### Case (a-3) std= [[-number1, +number2, ...], [+number1, +number2, ...]]
                """[Describe] - self.center가 단일 값이 아닐 경우를 위한 부분. 현재는 사용처가 없지만 활용 가능성이 있기 때문에 존치."""
                if not std.shape == ((2,) + np.array(center).shape):
                    raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" shape not matched with two times repeated shape of the center value')
                if isinstance(center, u.quantity.Quantity):
                    if isinstance(std, u.quantity.Quantity):
                        if center.unit.is_equivalent(std.unit):
                            self.__generate_distribution_asymmetric(center=center, stds=([std.value[0], std.value[1]] * std.unit).to(center.unit))
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" unit {std.unit} is not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_asymmetric(center=center, stds=[std[0], std[1]] * center.unit)
                else:
                    if isinstance(std, u.quantity.Quantity):
                        self.__generate_distribution_asymmetric(center=center * std.unit, stds=[std.value[0], std.value[1]] * std.unit)
                    else:
                        self.__generate_distribution_asymmetric(center=center * u.dimensionless_unscaled, stds=[std[0], std[1]] * u.dimensionless_unscaled)
            elif np.prod(std.shape) / np.prod(np.array(center).shape) == 1.:
                ### Case (a-4) std= [-number1, +number2, ...]
                """[Describe] - self.center가 단일 값이 아닐 경우를 위한 부분. 현재는 사용처가 없지만 활용 가능성이 있기 때문에 존치."""
                if not std.shape == np.array(center).shape:
                    raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" shape not matched with the center value')
                if isinstance(center, u.quantity.Quantity):
                    if isinstance(std, u.quantity.Quantity):
                        if center.unit.is_equivalent(std.unit):
                            self.__generate_distribution_symmetric(center=center, std=std.to(center.unit))
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" unit {std.unit} is not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_symmetric(center=center, std=std * center.unit)
                else:
                    if isinstance(std, u.quantity.Quantity):
                        self.__generate_distribution_symmetric(center=center * std.unit, std=std)
                    else:
                        self.__generate_distribution_symmetric(center=center * u.dimensionless_unscaled, std=std * u.dimensionless_unscaled)
            else:
                raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"std\" wrong - should be a number pair (ndarray) or the same structure as the center value')
        elif isinstance(std, list) or isinstance(std, tuple):
            if len(std) == 2:
                ### Case (b-1) std= [-number, +number]
                std_isquantity = [isinstance(element, u.quantity.Quantity) for element in std]
                if isinstance(center, u.quantity.Quantity):
                    if std_isquantity[0] and std_isquantity[1]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center, stds=[std[0].to(center.unit).value, std[1].to(center.unit).value] * center.unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[0]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center, stds=[std[0].to(center.unit).value, std[1]] * center.unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[1]:
                        if center.unit.is_equivalent(std[1].unit):
                            self.__generate_distribution_asymmetric(center=center, stds=[std[0], std[1].to(center.unit).value] * center.unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[1]}, not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_asymmetric(center=center, stds=std * center.unit)
                else:
                    if std_isquantity[0] and std_isquantity[1]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center * std[0].unit, stds=[std[0].value, std[1].value] * std[0].unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[0]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center * std[0].unit, stds=[std[0].value, std[1]] * std[0].unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[1]:
                        if center.unit.is_equivalent(std[1].unit):
                            self.__generate_distribution_asymmetric(center=center * std[1].unit, stds=[std[0], std[1].value] * std[1].unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[1]}, not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_asymmetric(center=center * u.dimensionless_unscaled, stds=std * u.dimensionless_unscaled)
            elif len(std) == 1:
                ### Case (b-2) std= [number]
                if isinstance(center, u.quantity.Quantity):
                    if isinstance(std[0], u.quantity.Quantity):
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_symmetric(center=center, std=std[0].to(center.unit))
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" unit {std[0].unit} is not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_symmetric(center=center, std=std[0] * center.unit)
                else:
                    if isinstance(std[0], u.quantity.Quantity):
                        self.__generate_distribution_symmetric(center=center * std[0].unit, std=std[0])
                    else:
                        self.__generate_distribution_symmetric(center=center * u.dimensionless_unscaled, std=std[0] * u.dimensionless_unscaled)
            elif np.prod(np.array(std).shape) / np.prod(np.array(self.center).shape) == 2.:
                ### Case (b-3) std= [[-number1, +number2, ...], [+number1, +number2, ...]]
                """[Describe] - self.center가 단일 값이 아닐 경우를 위한 부분. 현재는 사용처가 없지만 활용 가능성이 있기 때문에 존치."""
                if not np.array(std).shape == ((2,) + np.array(self.center).shape):
                    raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" shape not matched with two times repeated shape of the center value')
                std_isquantity = [isinstance(element, u.quantity.Quantity) for element in std]
                if isinstance(center, u.quantity.Quantity):
                    if std_isquantity[0] and std_isquantity[1]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center, stds=[std[0].to(center.unit).value, std[1].to(center.unit).value] * center.unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[0]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center, stds=[std[0].to(center.unit).value, std[1]] * center.unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[1]:
                        if center.unit.is_equivalent(std[1].unit):
                            self.__generate_distribution_asymmetric(center=center, stds=[std[0], std[1].to(center.unit).value] * center.unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[1]}, not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_asymmetric(center=center, stds=std * center.unit)
                else:
                    if std_isquantity[0] and std_isquantity[1]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center * std[0].unit, stds=[std[0].value, std[1].value] * std[0].unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[0]:
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_asymmetric(center=center * std[0].unit, stds=[std[0].value, std[1]] * std[0].unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[0]}, not equivalent to the center value unit {center.unit}.')
                    elif std_isquantity[1]:
                        if center.unit.is_equivalent(std[1].unit):
                            self.__generate_distribution_asymmetric(center=center * std[1].unit, stds=[std[0], std[1].value] * std[1].unit)
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" has an unit {std.unit[1]}, not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_asymmetric(center=center * u.dimensionless_unscaled, stds=std * u.dimensionless_unscaled)
            elif np.prod(np.array(std).shape) / np.prod(np.array(self.center).shape) == 1.:
                ### Case (b-4) std= [-number1, +number2, ...]
                """[Describe] - self.center가 단일 값이 아닐 경우를 위한 부분. 현재는 사용처가 없지만 활용 가능성이 있기 때문에 존치."""
                if not np.array(std).shape == np.array(self.center).shape:
                    raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" shape not matched with the center value')

                if isinstance(center, u.quantity.Quantity):
                    if isinstance(std[0], u.quantity.Quantity):
                        if center.unit.is_equivalent(std[0].unit):
                            self.__generate_distribution_symmetric(center=center, stds=std[0].to(center.unit))
                        else:
                            raise u.core.UnitsError(f'{self.__callsign.ljust(10)}: Input argument \"stddev\" unit {std[0].unit} is not equivalent to the center value unit {center.unit}.')
                    else:
                        self.__generate_distribution_symmetric(center=center, stds=std[0] * center.unit)
                else:
                    if isinstance(std[0], u.quantity.Quantity):
                        self.__generate_distribution_symmetric(center=center * std[0].unit, stds=std[0])
                    else:
                        self.__generate_distribution_symmetric(center=center * u.dimensionless_unscaled, stds=std[0] * u.dimensionless_unscaled)
            else:
                raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"std\" wrong - should be a number pair (list) or the same structure as the center value')
        elif isinstance(std, int) or isinstance(std, float):
            ### Case (c) std= number
            if isinstance(center, u.quantity.Quantity):
                if isinstance(std, u.quantity.Quantity):
                    self.__generate_distribution_symmetric(center=center, std=std.to(center.unit))
                else:
                    self.__generate_distribution_symmetric(center=center, std=std * center.unit)
            else:
                if isinstance(std, u.quantity.Quantity):
                    self.__generate_distribution_symmetric(center=center * std.unit, std=std)
                else:
                    self.__generate_distribution_symmetric(center=center * u.dimensionless_unscaled, std=std * u.dimensionless_unscaled)
        else:
            raise ValueError(f'{self.__callsign.ljust(10)}: Input argument \"std\" wrong - should be a number pair or the same structure as the center value')

        return self._sync_info()

    # def resample(self, n_samples=None):
    #     """
    #     [Public]
    #     Provides a user-level interface for resampling distribution via random shuffling.
    #     To avoid duplication, it performs sampling without replacement for downscaling,
    #     but permits sampling with replacement for upscaling if necessary.
    #     Usage :
    #     >>> v.resample(n_samples=1000)
    #     """
    #     if n_samples is None:
    #         n_samples = self.n_samples
    #     elif not isinstance(n_samples, (int, np.integer)):
    #         raise TypeError(f'{self.__callsign.ljust(10)}: Input argument \"n_samples\" must be an integer value.')
    #
    #     dummyvalue_synchronized = self._sync_info()
    #
    #     self_resampled = self.__class__().set_manual(
    #         center=self.center,
    #         distribution=unc.Distribution(self.distribution.distribution[np.random.choice(self.n_samples, size=n_samples, replace=n_samples > self.n_samples)]),
    #         dtype=self.dtype,
    #     ).set_digit(
    #         digit_round=self._digit_round,
    #         digit_stringformat=self._digit_stringformat,
    #     )
    #
    #     return self_resampled

    def resample(self, n_samples:int=None, exclude_nan=False, fix_nan=False):
        """
        [Public]
        Provides a user-level interface for resampling distribution via random shuffling.
        To avoid duplication, it performs sampling without replacement for downscaling,
        but permits sampling with replacement for upscaling if necessary.
        * exclude_nan: If True, completely removes NaNs and samples only from valid data.
        * fix_nan: If True (and n_samples == self.n_samples), preserves the exact index positions of NaNs.
        Usage :
        >>> q.resample(n_samples=1000)
        """
        if n_samples is None:
            n_samples = self.n_samples
        elif not isinstance(n_samples, (int, np.integer)):
            raise TypeError(f'{self.__callsign.ljust(10)}: Input argument \"n_samples\" must be an integer value.')

        if exclude_nan and fix_nan:
            raise ValueError(f'{self.__callsign.ljust(10)}: Cannot set both \"exclude_nan\" and \"fix_nan\" to True.')

        if fix_nan and n_samples != self.n_samples:
            raise ValueError(f'{self.__callsign.ljust(10)}: Can fix NaN only if \"n_samples\" is maintained.')

        dummyvalue_synchronized = self._sync_info()

        center_value = self.center.value  # 나중의 고급 리팩터링/캡슐화를 위해 getattr(self.center, 'value', self.center) 로 바꿀 수도 있음
        distribution = self.distribution.distribution
        distribution_value = distribution.value

        deviations = distribution_value - center_value

        # Suppress annoying RuntimeWarning when comparing arrays containing NaNs
        with np.errstate(invalid='ignore'):
            mask_deviations_nan = np.isnan(deviations)
            mask_deviations_positive = deviations > 0.
            mask_deviations_negative = deviations < 0.
            mask_deviations_zero = deviations == 0.

        count_nan = mask_deviations_nan.sum()
        count_valid = self.n_samples - count_nan
        counts_signs = np.array([mask_deviations_positive.sum(), mask_deviations_negative.sum(), mask_deviations_zero.sum()])

        if exclude_nan and count_valid == 0:
            raise ValueError("Cannot exclude NaNs: The distribution contains only NaN values.")

        if exclude_nan:
            count_nan_target = 0
            count_valid_target = n_samples
        else:
            if fix_nan:
                count_nan_target = count_nan
            else:
                count_nan_target = int(round(n_samples * count_nan / self.n_samples))
            count_valid_target = n_samples - count_nan_target

        if count_valid > 0:
            counts_signs_resample = np.round(count_valid_target * counts_signs / count_valid).astype(int)

            # Compensate for rounding errors by allocating the discrepancy to the largest group
            count_discrepancy = count_valid_target - counts_signs_resample.sum()
            if count_discrepancy != 0:
                counts_signs_resample[np.argmax(counts_signs_resample)] += count_discrepancy
        else:
            counts_signs_resample = np.array([0, 0, 0])

        def core_maskedresample(mask, count_original, count_resample):
            if count_resample == 0:
                return np.array([], dtype=self.dtype)

            distribution_value_sliced = distribution_value[mask]

            if count_resample <= count_original:
                return np.random.choice(distribution_value_sliced, size=count_resample, replace=False)

            resample_parapet = [distribution_value_sliced] * (count_resample // count_original)
            resample_merlon = [np.random.choice(distribution_value_sliced, size=count_resample % count_original, replace=False)]

            return np.concatenate(resample_parapet + resample_merlon)

        distribution_value_proliferated = [
            core_maskedresample(mask_deviations_positive, counts_signs[0], counts_signs_resample[0]),
            core_maskedresample(mask_deviations_negative, counts_signs[1], counts_signs_resample[1]),
            core_maskedresample(mask_deviations_zero, counts_signs[2], counts_signs_resample[2])
        ]

        if fix_nan:
            # Preserve the original index positions of NaNs
            distribution_value_resampled = np.empty_like(distribution_value)
            distribution_value_resampled[mask_deviations_nan] = distribution_value[mask_deviations_nan]

            valid_samples = np.concatenate(distribution_value_proliferated)
            np.random.shuffle(valid_samples)
            distribution_value_resampled[~mask_deviations_nan] = valid_samples
        else:
            # General case: Concatenate all sampled groups (including NaNs) and shuffle
            distribution_value_resampled = np.concatenate(distribution_value_proliferated + [np.full(count_nan_target, np.nan, dtype=self.dtype)])
            np.random.shuffle(distribution_value_resampled)

        self_resampled = self.__class__().set_manual(
            center=self.center,
            distribution=unc.Distribution(distribution_value_resampled * self.unit),
            dtype=self.dtype,
        ).set_digit(
            digit_round=self._digit_round,
            digit_stringformat=self._digit_stringformat,
        )

        return self_resampled

    def _promote_nsamples(self, other):
        """
        [Protected]
        Acts as a safety measure to synchronize sample resolutions between instances during operations.
        While the system is designed to maintain a consistent 'n_samples', this method ensures
        compatibility when discrepancies occur by upscaling 'self' to match the higher resolution.
        As this involves resampling via replacement for upscaling, it may introduce minor
        statistical variations in the distribution results. Not intended for direct user-level calls.
        Usage (not recommand direct call this at the user level) :
        >>> q1._promote_nsamples(other) + q2._promote_nsamples(self)
        """
        if not isinstance(other, (ValueU, self.__class__)):
            raise TypeError(f'{self.__callsign.ljust(10)}: Incompatible type for n_samples promotion: {type(other)}')

        n_samples_self = self._sync_info().n_samples
        n_samples_other = other._sync_info().n_samples

        if n_samples_self < n_samples_other:
            return self.copy().resample(n_samples_other)
        else:
            return self.copy()

    def copy(self):
        """
        [Public]
        Returns a new instance with the identical center, distribution, and formatting settings.
        Ensures the original instance remains unchanged during subsequent manipulations.
        Usage:
        >>> new_instance = q.copy()
        """
        self_copied = self.__class__().set_manual(
            center=self.center,
            distribution=self.distribution,
            dtype=self.dtype,
        ).set_digit(
            digit_round=self._digit_round,
            digit_stringformat=self._digit_stringformat,
        )

        return self_copied

    def astype(self, dtype):
        """
        [Public]
        Returns a new instance with the distribution cast to a specified numeric data type (dtype).
        Preserves all metadata while updating the underlying array's precision.
        Usage:
        >>> float32_instance = q.astype(np.float32)
        """
        self_copied = self.__class__().set_manual(
            center=self.center,
            distribution=self.distribution,
            dtype=dtype,
        ).set_digit(
            digit_round=self._digit_round,
            digit_stringformat=self._digit_stringformat,
        )

        return self_copied

    def to(self, unit=None):
        """
        Method for unit decomposition
        calculate instance variables by decomposing their unit into its irreducible parts.
        to support users control the object, by same purpose and manner with 'astropy.units.quantity.Quantity.decompose()'
        usage (exactly same with astropy.units.quantity.Quantity.decompose()):
        $ >>> q = QuantityU(3.26 * u.lyr, 0.5)
        $ ... print(repr(q))
        $ QuantityU(3.26 * u.lyr, (-0.5, +0.5))
        $ >>> print(repr(q.to(u.pc)))
        $ QuantityU(0.99952 * u.pc, (-0.1533, +0.1533))
        """
        try:
            target_unit = u.Unit(getattr(unit, 'unit', unit))  # 입력된 unit에서 실제 Unit 객체를 추출
        except:
            raise u.core.UnitsError(
                f'{self.__callsign.ljust(10)}: Input argument \"{unit}\" is not a valid type {u.__name__}'
            )

        result = self.__class__().set_manual(
            center=self.center.to(unit),
            distribution=self.distribution.to(unit),
            dtype=self.dtype,
        ).set_digit(
            digit_round=self._digit_round,
            digit_stringformat=self._digit_stringformat
        )

        return result

    def decompose(self):
        """
        Method for unit decomposition
        calculate instance variables by decomposing their unit into its irreducible parts.
        to support users control the object, by same purpose and manner with 'astropy.units.quantity.Quantity.decompose()'
        usage (exactly same with astropy.units.quantity.Quantity.decompose()):
        $ >>> q = QuantityU(1e-10 * u.lyr / (25 * u.km / u.second))
        $ ... print(repr(q))
        $ QuantityU(0.0 * u.lyr * u.s / u.km, (nan, nan))
        $ >>> print(repr(q.decompose()))
        $ QuantityU(37.84292 * u.s, (nan, nan))
        """
        result = self.__class__().set_manual(
            center=self.center.decompose(),
            distribution=self.distribution.decompose(),
            dtype=self.dtype,
        ).set_digit(
            digit_round=self._digit_round,
            digit_stringformat=self._digit_stringformat
        )

        return result

    def set_comparison_mode(self, central:bool=False, conservative:bool=False, permissive:bool=False, percentage:int=None):
        """
        [***ToDo*__] (25-01-24) - 단일문으로 작성시 어테이션 에러 발생할때 도무지 알 수 없는 이유로 스레드가 종료되지 않는 스레딩 에러 발생,
        python3.10/threading.py, line 1567, lock.acquire() \n KeyboardInterrupt:
        assert 열에서 하는 일을 바깥으로 빼내어 일단 안정적으로 작동, 임시방편인지 해결팩인지 확인 필요.
        """
        number_of_true_in_arguments: int = np.sum((central, conservative, permissive, not percentage is None))
        error_message = f'Only one of these parameters can be set: central (True), conservative (True), permissive (True), or percentage (\033[3mfloat value\033[0m) for this method ({self.__class__.__name__}.{inspect.getframeinfo(inspect.currentframe()).function})'
        # error_message = f'It is invalid to provide multiple parameters as \'True\' among {["central", "conservative", "upper", "lower"]} for the method {self.__class__.__name__}.{inspect.getframeinfo(inspect.currentframe()).function}.'
        assert number_of_true_in_arguments == 1, error_message

        result = self.copy()
        if central:
            result._comparison_criterion_by_center = True
        else:
            result._comparison_criterion_by_center = False
            if conservative:
                result._comparison_criterion_threshold = 0.9973
            elif permissive:
                result._comparison_criterion_threshold = 0.6827
            elif percentage is not None:
                result._comparison_criterion_threshold = percentage
            else:
                result._comparison_criterion_by_center = True

        return result

    def __getstate__(self):
        stateinfo_sleeping = {
            'center': self.center,
            'distribution': self.distribution.distribution.astype(self.dtype),
            'digits': [self._digit_round, self._digit_stringformat],
            'n_samples': self.n_samples,
            'dtype': self.dtype,
        }

        return stateinfo_sleeping

    def __setstate__(self, stateinfo):
        self_wakeing = self.set_manual(
            center=stateinfo['center'],
            distribution=unc.Distribution(stateinfo['distribution']),
            dtype=stateinfo['dtype'],
        ).set_digit(
            digit_round=stateinfo['digits'][0],
            digit_stringformat=stateinfo['digits'][1],
        )



    def __add__(self, other):  ## self + other
        """
        [Describe] - 가산연산에서 self.unit과 other.unit의 physical type이 다르면 연산 불가능하다.
        self.unit과 other.unit이 상호 호환되지 않는 physical type인 경우를 별도 예외처리하지 않고, 연산을 시도할 경우 기존 에러가 발생하도록 의도함.
        """
        if isinstance(other, self.__class__):
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=self.center.astype(type_upcasted) + other.center.astype(type_upcasted),
                distribution=self.distribution.astype(type_upcasted) + other.distribution.astype(type_upcasted),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        elif isinstance(other, ValueU):
            # 위의 if와 합칠 수 있으나, 향후 유지보수를 위해 존치. 아마 이게 더 빠를 수도 있음
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=self.center.astype(type_upcasted) + other.center.astype(type_upcasted),
                distribution=self.distribution.astype(type_upcasted) + other.distribution.astype(type_upcasted),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        elif isinstance(other, u.quantity.Quantity):
            # else에서 같은 작업을 하기 때문에 필요하지 않으나, 향후 유지보수를 위해 존치
            type_upcasted = np.result_type(self.dtype, other.dtype) if 'dtype' in dir(other) else self.dtype

            if 'astype' in dir(other):
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) + other.astype(type_upcasted),
                    distribution=self.distribution.astype(type_upcasted) + other.astype(type_upcasted),
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )
            else:
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) + other,
                    distribution=self.distribution.astype(type_upcasted) + other,
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )
        else:
            type_upcasted = np.result_type(self.dtype, other.dtype) if 'dtype' in dir(other) else self.dtype

            if 'astype' in dir(other):
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) + other.astype(type_upcasted),
                    distribution=self.distribution.astype(type_upcasted) + other.astype(type_upcasted),
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )
            else:
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) + other,
                    distribution=self.distribution.astype(type_upcasted) + other,
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )

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

    def __neg__(self):  ## -self
        return self.__class__().set_manual(center=-self.center, distribution=-self.distribution, dtype=self.dtype).set_digit(self._digit_round, self._digit_stringformat)

    def __sub__(self, other):  ## self - other
        return self.__add__(other.__neg__())

    def __rsub__(self, other):  ## other - self
        return self.__neg__().__add__(other)

    def __abs__(self):  ## abs(self)
        """
        [Operator: Standard Absolute]
        Applies absolute values to all samples, folding negative values into the positive domain.
        """
        return self.__class__().set_manual(
            center=abs(self.center),
            distribution=abs(self.distribution),
            dtype=self.dtype,
        ).set_digit(self._digit_round, self._digit_stringformat)

    def __pos__(self):  ## + self
        """
        [Operator: Unary Plus]
        Ensures the center is positive by flipping the entire distribution if center < 0.
        Preserves the relative shape of the distribution while aligning it to the positive domain.
        Used via '+instance' syntax.
        """
        if self.center < 0:
            return self.__neg__()
        else:
            return self.copy()

    def __mul__(self, other):  ## self * other
        if isinstance(other, self.__class__):
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=self.center.astype(type_upcasted) * other.center.astype(type_upcasted),
                distribution=self.distribution.astype(type_upcasted) * other.distribution.astype(type_upcasted),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        elif isinstance(other, ValueU):
            # 위의 if와 합칠 수 있으나, 향후 유지보수를 위해 존치. 아마 이게 더 빠를 수도 있음
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=self.center.astype(type_upcasted) * other.center.astype(type_upcasted),
                distribution=self.distribution.astype(type_upcasted) * other.distribution.astype(type_upcasted),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        else:
            type_upcasted = np.result_type(self.dtype, other.dtype) if 'dtype' in dir(other) else self.dtype

            if 'astype' in dir(other):
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) * other.astype(type_upcasted),
                    distribution=self.distribution.astype(type_upcasted) * other.astype(type_upcasted),
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )
            else:
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) * other,
                    distribution=self.distribution.astype(type_upcasted) * other,
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )

    def __rmul__(self, other):  ## other * self
        return self * other

    def __truediv__(self, other):  ## self / other
        if isinstance(other, (self.__class__, ValueU)):
            type_upcasted = np.result_type(self.dtype, other.dtype, np.floating)

            return self.astype(type_upcasted).__mul__(other.astype(type_upcasted).__pow__(-1))
        else:
            type_upcasted = np.result_type(self.dtype, other.dtype, np.floating) if 'dtype' in dir(other) else np.result_type(self.dtype, np.floating)

            if 'astype' in dir(other):
                return self.astype(type_upcasted).__mul__(other.astype(type_upcasted).__pow__(-1))
            else:
                return self.astype(type_upcasted).__mul__(other.__pow__(-1))

    def __rtruediv__(self, other):  ## other / self
        if isinstance(other, (self.__class__, ValueU)):
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.astype(type_upcasted).__pow__(-1).__mul__(other.astype(type_upcasted))
        else:
            type_upcasted = np.result_type(self.dtype, other.dtype, np.floating) if 'dtype' in dir(other) else np.result_type(self.dtype, np.floating)

            if 'astype' in dir(other):
                return self.astype(type_upcasted).__pow__(-1).__mul__(other.astype(type_upcasted))
            else:
                return self.astype(type_upcasted).__pow__(-1).__mul__(other)


    def __pow__(self, other):
        """
        [Describe] - 지수연산에서 other는 단위가 없거나 단위가 dimensionless_unscaled 이어야 한다.
        other가 '지수연산이 불가능한 단위를 가진 객체'인 경우를 별도로 예외처리하지 않고, 연산을 시도할 경우 에러가 발생하도록 의도함.
        띠리서 other은 반드시 numeric하거나, 단위가 dimensionless_unscaled 이어야 한다.
        """
        if isinstance(other, self.__class__):
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=self.center.astype(type_upcasted) ** other.center.astype(type_upcasted),
                distribution=self.distribution.astype(type_upcasted) ** other.distribution.astype(type_upcasted),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        elif isinstance(other, ValueU):
            # 위의 if와 합칠 수 있으나, 향후 유지보수를 위해 존치. 아마 이게 더 빠를 수도 있음
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=self.center.astype(type_upcasted) ** other.center.astype(type_upcasted),
                distribution=(self.distribution.astype(type_upcasted) ** other.distribution.astype(type_upcasted)),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        else:
            type_upcasted = np.result_type(self.dtype, other.dtype) if 'dtype' in dir(other) else self.dtype

            if 'astype' in dir(other):
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) ** other.astype(type_upcasted),
                    distribution=self.distribution.astype(type_upcasted) ** other.astype(type_upcasted),
                    dtype=self.dtype,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )
            else:
                return self.__class__().set_manual(
                    center=self.center.astype(type_upcasted) ** other,
                    distribution=self.distribution.astype(type_upcasted) ** other,
                    dtype=self.dtype,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )

    def __rpow__(self, other):  ## from other ** self
        """
        [Describe] - 역지수연산에서 self는 단위가 dimensionless인 units.quantity.Quantity의 인스턴스여야 한다.
        따라서 Value.__rpow__()에 해당 케이스를 처리하는 별도의 기능을 구현하지 않고, 부적절한 연산을 시도할 경우 에러가 발생하도록 의도.
        """
        if isinstance(other, self.__class__):
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=other.center.astype(type_upcasted) ** self.center.astype(type_upcasted),
                distribution=(other.distribution.astype(type_upcasted) ** self.distribution.astype(type_upcasted)),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        elif isinstance(other, ValueU):
            # 위의 if와 합칠 수 있으나, 향후 유지보수를 위해 존치. 아마 이게 더 빠를 수도 있음
            type_upcasted = np.result_type(self.dtype, other.dtype)

            return self.__class__().set_manual(
                center=other.center.astype(type_upcasted) ** self.center.astype(type_upcasted),
                distribution=(other.distribution.astype(type_upcasted) ** self.distribution.astype(type_upcasted)),
                dtype=type_upcasted,
            ).set_digit(
                digit_round=max(self._digit_round, other._digit_round),
                digit_stringformat=max(self._digit_stringformat, other._digit_stringformat),
            )
        else:
            type_upcasted = np.result_type(self.dtype, other.dtype) if 'dtype' in dir(other) else self.dtype

            if 'astype' in dir(other):
                return self.__class__().set_manual(
                    center=other.astype(type_upcasted) ** self.center.astype(type_upcasted),
                    distribution=other.astype(type_upcasted) ** self.distribution.astype(type_upcasted),
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )
            else:
                return self.__class__().set_manual(
                    center=other ** self.center.astype(type_upcasted),
                    distribution=other ** self.distribution.astype(type_upcasted),
                    dtype=type_upcasted,
                ).set_digit(
                    digit_round=self._digit_round,
                    digit_stringformat=self._digit_stringformat,
                )



    def __eq__(self, other):
        if isinstance(other, self.__class__):
            issame_center = self.center == other.center
            issame_distribution = np.all(self.distribution.distribution[np.where(np.logical_not(np.isnan(self.distribution.distribution)))[0]] == other.distribution.distribution[np.where(np.logical_not(np.isnan(other.distribution.distribution)))[0]])
            return issame_center and issame_distribution
        else:
            return False

    def __lt__(self, other):
        """
        [***ToDo***] (26-01-15) - False 결과의 이중성 검토, False 는 np.nan값과 비교했을때도 발생함. 이에 대한 처리 로직 필요.
        """
        if isinstance(other, self.__class__):
            assert self._comparison_criterion_by_center == other._comparison_criterion_by_center and self._comparison_criterion_threshold == other._comparison_criterion_threshold, 'Comparison criteria of two ValueU instances are different. Please set the same comparison criteria using the method \"set_comparison_mode\" before comparison operation.'
            if self._comparison_criterion_by_center:
                comparison = self.center < other.center
            else:
                comparison = np.average(self.distribution.distribution < other.distribution.distribution) > self._comparison_criterion_threshold
        else:
            if self._comparison_criterion_by_center:
                comparison = self.center < other
            else:
                comparison = np.average(self.distribution.distribution < other) > self._comparison_criterion_threshold
            """
            [***ToDo___] (25-02-11) - 해당 예외를 일으킬만한 상황이 있는가? 삭제해도 문제가 없는지 검토중
            """
            # raise TypeError(f'Not valid type {type(other)} of {other} for operation method \"{__name__}\"')

        return comparison

    def __gt__(self, other):
        """
        [***ToDo***] (26-01-15) - False 결과의 이중성 검토, False 는 np.nan값과 비교했을때도 발생함. 이에 대한 처리 로직 필요.
        """
        if isinstance(other, self.__class__):
            assert self._comparison_criterion_by_center == other._comparison_criterion_by_center and self._comparison_criterion_threshold == other._comparison_criterion_threshold, 'Comparison criteria of two ValueU instances are different. Please set the same comparison criteria using the method \"set_comparison_mode\" before comparison operation.'
            if self._comparison_criterion_by_center:
                comparison = self.center > other.center
            else:
                comparison = np.average(self.distribution.distribution > other.distribution.distribution) > self._comparison_criterion_threshold
        else:
            if self._comparison_criterion_by_center:
                comparison = self.center > other
            else:
                comparison = np.average(self.distribution.distribution > other) > self._comparison_criterion_threshold
            """
            [***ToDo___] (25-02-11) - 해당 예외를 일으킬만한 상황이 있는가? 삭제해도 문제가 없는지 검토중
            """
            # raise TypeError(f'Not valid type {type(other)} of {other} for operation method \"{__name__}\"')

        return comparison

    def __le__(self, other):
        """
        [***ToDo***] (26-01-15) - False 결과의 이중성 검토, False 는 np.nan값과 비교했을때도 발생함. 이에 대한 처리 로직 필요.
        """
        if isinstance(other, self.__class__):
            assert self._comparison_criterion_by_center == other._comparison_criterion_by_center and self._comparison_criterion_threshold == other._comparison_criterion_threshold, 'Comparison criteria of two ValueU instances are different. Please set the same comparison criteria using the method \"set_comparison_mode\" before comparison operation.'
            if self._comparison_criterion_by_center:
                comparison = self.center <= other.center
            else:
                comparison = np.average(self.distribution.distribution <= other.distribution.distribution) > self._comparison_criterion_threshold
        else:
            if self._comparison_criterion_by_center:
                comparison = self.center <= other
            else:
                comparison = np.average(self.distribution.distribution <= other) > self._comparison_criterion_threshold
            """
            [***ToDo___] (25-02-11) - 해당 예외를 일으킬만한 상황이 있는가? 삭제해도 문제가 없는지 검토중
            """
            # raise TypeError(f'Not valid type {type(other)} of {other} for operation method \"{__name__}\"')

        return comparison

    def __ge__(self, other):
        """
        [***ToDo***] (26-01-15) - False 결과의 이중성 검토, False 는 np.nan값과 비교했을때도 발생함. 이에 대한 처리 로직 필요.
        """
        if isinstance(other, self.__class__):
            assert self._comparison_criterion_by_center == other._comparison_criterion_by_center and self._comparison_criterion_threshold == other._comparison_criterion_threshold, 'Comparison criteria of two ValueU instances are different. Please set the same comparison criteria using the method \"set_comparison_mode\" before comparison operation.'
            if self._comparison_criterion_by_center:
                comparison = self.center >= other.center
            else:
                comparison = np.average(self.distribution.distribution >= other.distribution.distribution) > self._comparison_criterion_threshold
        else:
            if self._comparison_criterion_by_center:
                comparison = self.center >= other
            else:
                comparison = np.average(self.distribution.distribution >= other) > self._comparison_criterion_threshold
            """
            [***ToDo___] (25-02-11) - 해당 예외를 일으킬만한 상황이 있는가? 삭제해도 문제가 없는지 검토중
            """
            # raise TypeError(f'Not valid type {type(other)} of {other} for operation method \"{__name__}\"')

        return comparison



    def __int__(self):
        return self.center.astype('int')

    def __round__(self, rounddigit: int=0):
        """
        $ >>> q = QuantityU(3.141592653589793 * u.lyr, 0.5)
        $ ... print(repr(round(q, 3)))
        $ QuantityU(3.142 * u.lyr, (-0.5, +0.5))
        """
        result_rounded = self.copy().set_manual(
            center=np.round(self.center, rounddigit),
            distribution=self.distribution,
            dtype=self.dtype,
        ).set_digit(
            digit_round=rounddigit,
            digit_stringformat=self._digit_stringformat
        )

        return result_rounded

    def __format__(self, format_spec):
        """
        [***ToDo***] (26-01-16) - f-string 및 format() 지원을 위한 커스텀 포매터 구현 플랜:

        1. 배경: 현재 __format__이 정의되지 않아 f-string 포맷 명시자(:>20 등) 사용 시
           객체의 문자열 표현이 아닌 기본 object 포맷이 적용되어 정렬이 무너지는 문제 발생.

        2. 구현 목표:
           - format_spec이 비어있을 경우 기존 __str__ 결과 반환.
           - 정렬(>, <, ^) 및 너비(width) 명시자가 들어올 경우,
             내부 수치 포맷팅(digit_round 등)을 유지하면서 외부 레이아웃 정렬을 수행하도록 설계.

        3. 상세 사양:
           - f"{instance:20}" -> 전체 '중심값(±오차)' 텍스트를 20자 내에서 정렬.
           - f"{instance:.3f}" -> 내부 digit_round 설정을 오버라이드하여 소수점 3자리 강제 적용 검토.

        Note: 현재는 str(instance).rjust(width) 방식으로 임시 대응 중이나,
              가독성과 견고함을 위해 파이썬 표준 포맷팅 프로토콜 도입이 필요함.
        """
        # 임시 방편: 포맷 명시자가 있어도 무시하고 str로 변환 후 포맷 적용
        return format(str(self), format_spec)

    # def __array__(self, dtype=None, copy=None):
    #     """
    #     [Interoperability: NumPy]
    #     Provides a NumPy array representation of the instance.
    #     This enables direct use of NumPy functions (e.g., np.mean, np.nanmean)
    #     by exposing the internal distribution data.
    #     """
    #     if dtype:
    #         return self.distribution.distribution.astype(dtype)
    #     return self.distribution.distribution



    def set_digit(self, digit_round=3, digit_stringformat=5):
        if isinstance(digit_round, int):
            self._digit_round = digit_round
        else:
            raise TypeError(f'{self.__callsign.ljust(10)}: Input argument \'digit_round\' for \"{__name__}\" type wrong - have not to be {int}')

        if isinstance(digit_stringformat, int):
            self._digit_stringformat = digit_stringformat
        else:
            raise TypeError(f'{self.__callsign.ljust(10)}: Input argument \'digit_stringformat\' for \"{__name__}\" type wrong - have not to be {int}')

        return self



    @classmethod
    def help(cls):
        pydoc = PyDocFormatter(120)
        print(f'\n{"#" * pydoc.width}\n')

        print(
            f'\033[1m\033[3m\033[4m\033[7m{cls.__name__}\033[0m\033[4m: \033[1m{cls.__fullname} (Class) '
            f''.ljust(pydoc.width + 4 * 7 - len(str(cls.__version))) + str(cls.__version) + '\033[0m')
        print(f'last updated at {cls.__lastupdate.strftime("%Y-%m-%d")}'.rjust(pydoc.width))

        print(f'\n\033[1m\033[4m{"Introduction:".ljust(25)}\033[0m')
        print(pydoc.f(
            f' {cls.__name__} is a Python class for handling quantities(contains) and their associated uncertainties.'
            f' It stores, computes with, and represents these values not through traditional error propagation, but by modeling uncertainty distribution as a large sequence of sample values.'
            f' This implementation assumes an initial normal distribution based on the provided standard deviations.'
            f' Fundamentally based on the {unc.__name__} package, {cls.__name__} extends it with several key convenience features.'
            f' These enhancements, updated in August 2025, include \033[1mpickling\033[0m, robust preservation of the central value during operations, and more intuitive string representations.'
            f' {cls.__name__} is an upper-compatible extension of {ValueU.__name__} structurally, adding unit control and representation.'
            f' This package processes results under the assumption of independent variables (zero covariance between uncertainties).'
            f' Dependencies include \'NumPy\', \'Astropy\', and standard Python libraries (e.g., \'os\', \'sys\', \'inspect\', \'datetime\').'
            f' Testing and inspection were performed using \033[1mPython 3.10.14\033[0m, \033[1mNumPy 1.26.4\033[0m, and \033[1mAstropy 6.1.3\033[0m.'
            f' While performance was as anticipated in this environment, results may differ in other settings.'
            f' Additional testing is required to ensure consistent behavior across different configurations.'
        ))
        print('\n        \u2013 How to declare/generate an instance:')
        print(
            f'            $ >>> # import sys, os\n'
            f'            $ ... # sys.path.append(r\'{os.path.dirname(os.path.dirname(__file__))}\')  # *For alpha tester\n'
            f'            $ >>> from {os.path.basename(os.path.dirname(__file__))} import {cls.__name__}\n'
            f'            $ >>> my_first_uncertain_quantity = {cls.__name__}(center=15 * u.m, std=3)\n'
        )
        print(pydoc.f(
            f' The \'__init__()\' method accepts \'central\', \'stddev\', and \'limit\' as input parameters.'
            f' The \'stddev\' can accept array-like objects (lists, tuples, numpy.ndarrays) to represent asymmetric errors.'
            f' A single standard deviation value can be provided if the lower and upper errors are symmetric.'
            f' On the other hand, \'limit\' should accept an array-like input value.'
            f' Note that \'stddev\' and \'limit\' cannot be used simultaneously.'
        ))
        print(' The full set of parameters is:\n')
        print(f'    \u2013 \033[1mCentral\033[0m [float]: \033[4mMean\033[0m value (or representative/\033[4mcentral\033[0m value) with associated unit, serving as the base unit for\n                       other properties.')
        print(f'    \u2013 \033[1mStddev\033[0m [float/float-arr]: \033[4mStandard deviation\033[0m(s) representing relative uncertainty(s) from the central value')
        print(f'    \u2013 \033[1mLimit\033[0m [float-arr]: \033[4mAbsolute range\033[0m(array-like) of uncertainty (lower and upper limits)')
        print('')
        print(pydoc.f(
            f'If no keywords are specified, the first parameter is regarded as the central value and the second as the standard deviation.'
            f' \033[4mWe recommend that users avoid using protected methods\033[0m.'
            f' Although we do not restrict users from accessing protected methods like \'_set_central()\' and modifying object contents, \033[4mthese methods are not designed for user access\033[0m.'
        ))

        print(f'\n\033[1m\033[4m{"Application:".ljust(25)}\033[0m')
        print(f'\033[1m\u2022\033[0mMathematical Operation\033[0m')
        print(pydoc.f(
            f' {cls.__name__} uses a sampling-based approach to support non-normal uncertainty distributions.'
            f' During mathematical operations, the sampled sequences of the objects are calculated element-wise.'
            f' Because this calculation is performed index by index, any existing correlation between the objects is inherently reflected in the result.'
            f' If the objects are strictly independent, the outcome is equivalent to standard error propagation.'
        , tab=1))
        print('\n        \u2013 Example 1 of Application : Addition Operation of Symmetric Uncertainty')
        q1, q2 = cls(72 * u.m, 3), cls(800 * u.cm, 400)
        print(f'            $ >>> q1, q2 = {repr(q1.set_digit(0))}, {repr(q2.set_digit(-2))}\n            $ >>> print(\'q1 + q2  = \' + str(q1 + q2) + \' = \' + repr(q1 + q2))\n            $ q1 + q2  =  {str(q1 + q2)}  =  {repr(q1 + q2)}\n')
        print('\n        \u2013 Example 2 of Application : Addition Operation of Asymmetric Uncertainty')
        q1, q2 = cls(72 * u.m, (-3, +12)), cls(800 * u.cm, (-400, +500))
        print(f'            $ >>> q1, q2 = {repr(q1.set_digit(0))}, {repr(q2.set_digit(-2))}\n            $ >>> print(\'q1 + q2  = \' + str(q1 + q2) + \' = \' + repr(q1 + q2))\n            $ q1 + q2  =  {str(q1 + q2)}  =  {repr(q1 + q2)}\n')
        print(pydoc.f(
            f' Other basic arithmetic operations (-, *, /) and exponentiation (**) are supported in the same manner.'
            f' In-place operators (+=, -=, *=, /=, **=) are currently withheld to prevent unintended data mutation.'
            f' Logical operators (and, or) are not implemented, as handling boolean data requires further design.'
            f' Future releases may support additional mathematical functions.'
        , tab=1))
        print(f'\n\033[1m\u2022\033[0mUnit Conversion\033[0m')
        print('    ***writing...***')
        print('\n        \u2013 Example 3 of Application : Unit Conversion')
        q1 = cls(274 * u.mm, (-3, +5))
        print(f'            $ >>> q1 = {repr(q1)}\n            $ >>> print(\'q1 in meter  = \', str(q1.to(u.m)))\n            $ q1 in meter  =  {str(q1.to(u.m))}\n')
        print('\n        \u2013 Example 3 of Application : Unit Decomposition')
        import astropy.constants as const
        q3 = cls(4582 * u.km, 10)
        print(f'            $ >>> import astropy.constants as const\n            $ >>> q3 = {repr(q3)}\n            $ >>> print(\'q3 in frequancy      = \', str((const.c / q3).decompose()))\n            $ q3 in frequancy  =  {str((const.c / q3).decompose())}')
        print('\n\033[1m\u2022\033[0mComparison\033[0m')
        print(pydoc.f(
            f' You can compare {cls.__name__} objects using standard comparison operators (<, >, <=, >=).'
            f' However, because ValueU is designed to represent a probability distribution rather than a single scalar, it lacks a single definitive reference point.'
            f' As a result, the criteria for comparison must be specified before performing these operations.'
            f' For initial setting, the comparison criterion is set to use the central value; it evaluates the objects based solely on their center attribute and ignores uncertainty.'
            f' To customize the criterion, the \'{cls.set_comparison_mode.__name__}()\' method provides an intuitive user-level interface.'
            f' This method accepts three boolean keyword arguments - \'central\', \'conservative\', and \'permissive\'.'
            f' Setting any of these to True enables the corresponding criterion.'
            f' Alternatively, you can pass a numeric value to the percentage keyword argument to manually set a custom significance level.'
            f' The selected comparison mode will govern the subsequent comparison criterion.'
        , tab=1))
        print('    *\033[1mNote\033[0m: \033[4mThis approach is currently under review and may undergo significant changes in future releases.\033[0m')
        print('    The specific behavior for each keyword argument is as follows:\n')
        print(f'        \u2013 \033[1mCentral\033[0m [bool]: Compares only the central values of the {cls.__name__} objects. This is the default setting')
        print(f'        \u2013 \033[1mConservative\033[0m [bool]: Applies a \033[4mconservative\033[0m (or strict) comparison approach. Returns True if the comparison\n            holds for 99.73% (3\u03C3) of the distribution.')
        print(f'        \u2013 \033[1mPermissive\033[0m [bool]: Applies a \033[4mpermissive\033[0m (or relaxed) comparison threshold. Returns True if the comparison hol-\n            ds for 68.27% (1\u03C3) of the distribution.')
        print(f'        \u2013 \033[1mPercentage\033[0m [bool]: Compares using a custom lower bound for the uncertainty ranges of each {cls.__name__} objects')
        print('')
        print(pydoc.f(
            f' Currently, both objects must share the exact same comparison mode.'
            f' Comparing objects with different modes is not implemented.'
            f' Once set, this mode is saved within the object and dictates all future comparisons.'
            f' Therefore, it is recommended to verify the current mode before performing any comparison.'
        , tab=1))
        print('\n        \u2013 Example 4 of Application : Comparison in Various Approaches')
        q3, q4 = cls(90 * u.cm, 50), cls(100 * u.cm, 10)
        print(
            f'            $ >>> q3, q4 = {repr(q3.set_digit(0))}, {repr(q4.set_digit(0))}\n\n'
            f'            $ >>> # Compare by central value\n'
            f'            $ ... if q3.{q3.set_comparison_mode.__name__}(central=True) < q4.{q4.set_comparison_mode.__name__}(central=True):\n            $ ...     print(\'q3 < q4 by central value\')\n'
            f'            $ ... elif q3.{q3.set_comparison_mode.__name__}(central=True) > q4.{q4.set_comparison_mode.__name__}(central=True):\n            $ ...     print(\'q3 > q4 by central value\')\n'
            f'            $ ... else:\n            $ ...     print(\'unable to compare by central value\')')
        print(f'                $ {"q3 < q4 by central value" if q3.set_comparison_mode(central=True) < q4.set_comparison_mode(central=True) else "q3 > q4 by central value" if q3.set_comparison_mode(central=True) > q4.set_comparison_mode(central=True) else "unable to compare by central value"}\n')
        print(
            f'            $ >>> # Compare with conservative approach\n'
            f'            $ ...  if q3.{q3.set_comparison_mode.__name__}(conservative=True) < q4.{q4.set_comparison_mode.__name__}(conservative=True):\n            $ ...     print(\'q3 < q4 in conservative approach\')\n'
            f'            $ ... elif q3.{q3.set_comparison_mode.__name__}(conservative=True) > q4.{q4.set_comparison_mode.__name__}(conservative=True):\n            $ ...     print(\'q3 > q4 in conservative approach\')\n'
            f'            $ ... else:\n            $ ...     print(\'unable to compare in conservative approach\')')
        print('            $ ' + ('q3 < q4 in conservative approach' if q3.set_comparison_mode(conservative=True) < q4.set_comparison_mode(conservative=True) else 'q3 > q4 in conservative approach' if q3.set_comparison_mode(conservative=True) > q4.set_comparison_mode(conservative=True) else 'unable to compare in conservative approach') + '\n')
        print(pydoc.f(
            f' In contrast to the previously described comparison methods, \033[4mthe == operator performs a strict equality check.\033[0m'
            f' It returns True only when both the center and the exact sequence of uncertainty values are completely identical.'
            f' An operation to evaluate the overall similarity between distributions is not yet implemented, as a suitable operator for this behavior has not been decided'
        , tab=1))
        print('\n\033[1m\u2022\033[0mAdditional Functions\033[0m')
        print(pydoc.f(
            f' The \'{cls.set_manual.__name__}(center, distribution: {unc.__name__}.{unc.Distribution.__name__})\' allows manual assignment of the central value and the uncertainty distribution.'
            f' If center is not provided, it automatically defaults to the median of the given distribution to ensure statistical consistency.'
        , tab=1))
        print('\n        \u2013 Example 5 of Application : Manual Set Instance')
        q5 = cls().set_manual(center=0, distribution=unc.Distribution([-3, -1, 2, 4]), )
        print(f'            $ >>> from astropy import uncertainty as unc\n'
              f'            $ ... q5 = {cls.__name__}().{cls.set_manual.__name__}(center={q5.center.value.astype("int")}, distribution=unc.Distribution({str(list(q5.distribution.distribution.value.astype("int")))}))\n'
              f'            $ >>> print(\'q5 includes: \' + repr(q5.distribution.distribution))\n'
              f'            $ q5 includes: {repr(q5.distribution.distribution)}\n'
              f'            $ >>> print(repr(({cls.__name__}().{cls.set_manual.__name__}(center=0, distribution=q5.distribution + 2) - q5).distribution))\n'
              f'            $ {repr((cls().set_manual(center=0, distribution=q5.distribution + 2, ) - q5).distribution)}\n')
        print(pydoc.f(
            f' The {cls.copy.__name__}() method returns an independent duplicate of the {cls.__name__} object.'
            f' The copied instance retains the identical central value and sampled uncertainty sequence.'
            f' It ensures that modifications to the copy do not affect the original object.'
            , tab=1))
        print('\n        \u2013 Example 6 of Application : Copy Object')
        q6 = cls(1897 * u.yr, (-1, 10))
        print(f'            $ >>> q6 = {repr(q6.set_digit(0))}\n'
              f'            $ >>> # The copy holds the same sequence but is a distinct object in memory\n'
              f'            $ ... print((q6 == q6.{q6.copy.__name__}(), q6 is q6.{q6.copy.__name__}()))\n            $ {repr((q6 == q6.copy(), q6 is q6.copy()))}\n')
        print(pydoc.f(
            f' The \'enforced_positive\' / \'enforced_negative\' returns a new instance with the distribution restricted to the positive or negative domain.'
            f' Out-of-bounds samples are replaced with np.NaN to maintain sequence alignment and sample count without distorting the valid distribution.'
            f' A ValueError is raised if the central value contradicts the enforced domain.'
        , tab=1))
        # print(pydoc.f(
        #     f'\033[1m\033[4m\033[7mWarning!\033[0m\033[1m: Replacing out-of-bounds values with NaN automatically upcasts integer arrays to float64, as NumPy\'s NaN is strictly a floating-point representation.'
        #     f' \033[4m\033[7mDo not attempt\033[0m\033[1m to force-cast the resulting array back to integers using \'{cls.astype.__name__}(int)\'.'
        #     f' Because integer types cannot represent NaN, doing so will cause an integer overflow, converting NaN values into arbitrarily large negative integers (e.g., -9223372036854775808).'
        #     f' This will lead to \033[4m\033[7munexpected data distortion and silent bugs\033[0m\033[1m.'
        #     f' The current implementation is not designed to process NumPy masked arrays (numpy.ma) as a workaround.'
        #     f' Fully resolving this integer upcasting limitation will require additional development time in future updates.\033[0m'
        # , tab=1))
        print('\n        \u2013 Example 7 of Application : Sign-Enforced derivative')
        q7 = cls(100 * u.yr, 500)
        print(f'            $ >>> q7 = {repr(q7.set_digit(-2))}\n'
              f'            $ >>> print(repr(q7.enforced_positive)\n            $ {repr(q7.enforced_positive)}\n')
        print(pydoc.f(
            f' The \'{cls.resample.__name__}(n_samples)\' returns a new instance with the distribution resampled to the specified number of samples.'
            f' To prevent unnecessary duplication, it performs sampling without replacement for downscaling. '
            f' For upscaling, it performs sampling with replacement.'
        , tab=1))
        print('\n        \u2013 Example 8 of Application : Resampling')
        q8 = q7.resample(n_samples=50)
        print(f'            $ >>> q8 = q7.{q7.resample.__name__}(n_samples=100)\n'
              f'            $ >>> print(repr(q8) + \' has: \' + str(len(q8.distribution.distribution)) + \' samples\')\n'
              f'            $ {repr(q8) + " has: " + str(len(q8.distribution.distribution)) + " samples"}\n')
        print(pydoc.f(
            f' The \'{cls.astype.__name__}(dtype)\' returns a new instance with the underlying distribution array cast to the specified numeric data type (e.g., {np.__name__}.{np.float32.__name__}).'
            f' This preserves all metadata while updating the array\'s precision.'
            f' \033[1mCaution is required \033[4mif the distribution array contains NaN values\033[0m\033[1m (e.g., after using \'enforced_positive\' or \'enforced_negative\') and is cast to an integer.'
            f' According to the IEEE 754 standard, {np.__name__}.nan is represented by specific bit patterns in the exponent and fraction fields of floating-point numbers.'
            f' Since integer types cannot accommodate this representation, casting NaN to an integer falls back to the minimum representable value of int64 (e.g., -9223372036854775808).'
            f' Although intended as an integer fallback representation for NaN, it arithmetically functions as an actual, extremely large negative number.'
            f' This is highly misleading and will lead to unexpected data distortion and silent bugs.'
            f' Therefore, \033[4m\033[7mit is strongly recommended not to cast an instance to an integer data type\033[0m\033[1m if you are aware of or suspect that the underlying distribution contains {np.__name__}.nan.'
        , tab=1))
        print('\n        \u2013 Example 9 of Application : Type Casting')
        remainders = (q6 - q6.astype(int)).distribution.distribution
        print(
            f'            $ >>> remainders = (q6 - q6.{q6.astype.__name__}(int)).distribution.distribution\n'
            f'            $ >>> print(str(remainders))\n'
            f'            $ ... print((min(remainders), max(remainders)))\n'
            f'            $ {str(remainders)}\n'
            f'            $ {str((min(remainders), max(remainders)))}\n'
        )







        print('\n\033[1m\u2022\033[0mFormatting\033[0m')
        print(pydoc.f(
            f' The \'{cls.set_digit.__name__}\' method allows you to customize how the object is displayed.'
            f' A first parameter, \'digit_round\', controls the number of decimal places for rounding (default: 5 digit), and \'digit_stringformat\' sets the total output width (default: 8 spaces).'
            f' For example, \".{cls.set_digit.__name__}(digit_round=3, digit_stringformat=10)\" would round to 3 decimal places and use a width of 10 characters.'
        , tab=1))
        print('\n        \u2013 Example 6 of Application : Output Formatting')
        print(f'            $ >>> import numpy as np\n            $ ... import astropy.units as u\n            $ >>> q6 = {cls.__name__}(np.pi * u.hour, (-np.pi * 0.011, np.pi * 0.013))')
        q6 = cls(np.pi * u.hour, (-np.pi * 0.011, np.pi * 0.013))

        print(f'\n\033[1m\033[4m{"Warning:".ljust(25)}\033[0m')
        print(pydoc.f(
            ' The operations in this package are designed to propagate errors based on normal distribution theory, treating errors in each variable independently.'
            ' However, due to the complexities of error propagation, some operations may not be mathematically or logically sound.'
            ' We are actively working to identify and address these potential issues through ongoing testing and review.\n\n'
            ' While some NumPy methods, such as \'sum()\', \'diff()\', \'prod()\', and interactions with `numpy.ndarray`, \033[4mappear to function, they have \033[1mnot been fully validated\033[0m.'
            ' \033[1m\033[4mExercise extreme caution\033[0m when using these methods, and do not rely on their output without careful verification.'
            ' Full support for \'numpy.ndarray\' is planned for future development.\n\n'
            ' We are dedicated to improving the accuracy and reliability of this package.'
            ' If you encounter results that differ from other packages, or if you suspect an incorrect or inappropriate operation, please submit a detailed bug report to the primary developer.'
            ' Your feedback is crucial for identifying and resolving any remaining issues.'
            ' We appreciate your collaboration in making this package more robust.'
        ))

        print(f'\n\033[1m\033[4m{"Credit:".ljust(25)}\033[0m')
        print('\033[1m\u2022\033[0mDevelopers\033[0m')
        developers = [f'    {"Main Developer ".ljust(50, "-")}: {cls.__developer["name"]} ({cls.__developer["contact"]})']
        for collaborator in cls.__collaborators:
            if collaborator["contact"] is None:
                developers.append(f'    {"Collaborate Developer ".ljust(50, "-")}: {collaborator["name"]}')
            else:
                developers.append(f'    {"Collaborate Developer ".ljust(50, "-")}: {collaborator["name"]} ({collaborator["contact"]})')
        for contributor in cls.__contributors:
            developers.append(f'    {"Contributor ".ljust(50, "-")}: {contributor["name"]} ({contributor["role"]})')
        print('\n'.join(developers) + '\n')
        print('\033[1m\u2022\033[0mHistory\033[0m')
        histories = [
            {'contents': 'First Development of Varu', 'period': '2349'},
            {'contents': 'First Separated Design of ValueU / QuantityU', 'period': '2406'},
            {'contents': 'Test for Operator Magic Method', 'period': '2412'},
            {'contents': 'Code Commenting', 'period': '2412'},
            {'contents': 'Operator Magic Method Restructuring', 'period': '2507'},
            {'contents': 'Minor hotfix (__rtruediv__ error)', 'period': '2509'},
            {'contents': 'Minor hotfix (system path error in help message)', 'period': '2509'},
            {'contents': 'Help Message Implements', 'period': '2509'},
            {'contents': 'Minor hotfix (__array_priority__)', 'period': '2510'},
            {'contents': 'Minor hotfix (absolute/relative selection in __init__)', 'period': '2510'},
            {'contents': 'Minor hotfix (inherit digit parameter)', 'period': '2510'},
            {'contents': 'Major upgrade (engine transition from theoretical model to approximate sampling)', 'period': '2535'},
            {'contents': 'Minor upgrade (added sign constraints for distributions)', 'period': '2601'},
            {'contents': 'Major upgrade (lightweight value objects via property-based design)', 'period': '2602'},
            {'contents': 'Minor upgrade (implemented auxiliary methods for sampled distribution computation)', 'period': '2603'},
            {'contents': 'Minor upgrade (general validation completed, help() explanation)', 'period': '2609'},
            # {'contents': 'Error hotfix (output formatting and operation)', 'period': '2609'},
            # {'contents': 'Error hotfix (output formatting and operation)', 'period': '2610'},
            {'contents': 'Error hotfix (output formatting and operation)', 'period': '2612'},
            {'contents': 'Minor upgrade (upcast n_samples with retaining statistic characteristics)', 'period': '2612'},
        ]
        historys_period_len = max([len(history["period"]) for history in histories])
        for history_part in histories:
            print(f'    {(history_part["contents"] + " ").ljust(120 - historys_period_len - 6, "-")}: {history_part["period"].rjust(historys_period_len)}')
        # for history_part in histories:
        #     print(f'    {(history_part["contents"] + " ").ljust(50, "-")}: {history_part["period"]}')

        print(f'\n{"#" * pydoc.width}\n{f"Now, you can start {cls.__name__}".rjust(pydoc.width)}')

        return True

    def __str__(self, connection=''):
        notation_central, notations_error = self.value.get_strnotation(digit_round=self._digit_round)

        if notations_error[0][1:] == notations_error[1][1:]:
            if notations_error[0] == 'np.nan' and notations_error[1] == 'np.nan':
                notation_error = f'  {notations_error[-1].ljust(self._digit_stringformat * 2 + 1)}'
            else:
                notation_error = f' ±{notations_error[0][1:].ljust(self._digit_stringformat * 2 + 1)}'
        else:
            notation_error = f' {notations_error[0].ljust(self._digit_stringformat)}, {notations_error[-1].ljust(self._digit_stringformat)}'

        if self.unit is u.dimensionless_unscaled:
            notation_final = (
                f'{notation_central.ljust(self._digit_stringformat)}'
                f' '
                f'({notation_error})'
            )
        else:
            notation_final = (
                f'{notation_central.ljust(self._digit_stringformat)}'
                f' '
                f'({notation_error})'
                f' [{self.unit}]'
            )

        return notation_final

        def __repr__(self):
            notation_central, notations_error = self.value.get_notation()

            if notations_error[0][1:] == notations_error[-1][1:]:
                if np.all(np.isnan(self.error_relative)):
                    notation_error = 'np.nan'
                else:
                    notation_error = f'{notations_error[0][1:]}'
            else:
                notation_error = f'({notations_error[0]}, {notations_error[-1]})'

            if self.unit is u.dimensionless_unscaled:
                notation_unit = ''
            else:
                notation_unit_elements = []
                for operator, part in zip(('*', '/'), self.unit.to_string().split(' / ')):
                    if part[0] == '(' and part[-1] == ')':
                        part = part[1:-1]
                    for unitelement in part.split(' '):
                        if unitelement != '1':

                            unitelement_powerbase = unitelement
                            unitelement_powerexponent = '1'

                            indices_notnum = [index for index, char in enumerate(unitelement) if not char.isnumeric()]
                            if unitelement[-1].isnumeric():
                                unitelement_powerbase = unitelement[:indices_notnum[-1] + 1]
                                unitelement_powerexponent = unitelement[indices_notnum[-1] + 1:]

                            if '(' in unitelement and ')' in unitelement:
                                unitelement_powerexponent_expected = unitelement[
                                                                     unitelement.find('(') + 1:unitelement.find(')')]
                                splitedcomp = unitelement_powerexponent_expected.split('/')
                                if len(splitedcomp) == 2 and splitedcomp[0].isnumeric() and splitedcomp[1].isnumeric():
                                    unitelement_powerbase = unitelement[:unitelement.find('(')]
                                    unitelement_powerexponent = f'({unitelement_powerexponent_expected})'

                            if unitelement_powerexponent == '1':
                                notation_unit_elements.append(f' {operator} u.{unitelement_powerbase}')
                            else:
                                notation_unit_elements.append(
                                    f' {operator} u.{unitelement_powerbase} ** {unitelement_powerexponent}')

                notation_unit = ''.join(notation_unit_elements)

            notation_final = (
                f'{self.__class__.__name__}({notation_central}{notation_unit},'
                f' '
                f'{notation_error})')

            return notation_final

    if __name__ == '__main__':
        QuantityU().help()
