pyuncertainnumber ================= .. py:module:: pyuncertainnumber Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/pyuncertainnumber/calibration/index /autoapi/pyuncertainnumber/characterisation/index /autoapi/pyuncertainnumber/console/index /autoapi/pyuncertainnumber/decorator/index /autoapi/pyuncertainnumber/gutils/index /autoapi/pyuncertainnumber/nlp/index /autoapi/pyuncertainnumber/opt/index /autoapi/pyuncertainnumber/pba/index /autoapi/pyuncertainnumber/propagation/index /autoapi/pyuncertainnumber/sensitivity/index /autoapi/pyuncertainnumber/surrogate/index /autoapi/pyuncertainnumber/validation/index Attributes ---------- .. autoapisummary:: pyuncertainnumber.__version__ pyuncertainnumber.uniform pyuncertainnumber.lognormal pyuncertainnumber.known_constraints Classes ------- .. autoapisummary:: pyuncertainnumber.UN pyuncertainnumber.UncertainNumber pyuncertainnumber.Pbox pyuncertainnumber.Staircase pyuncertainnumber.Interval pyuncertainnumber.EpistemicDomain pyuncertainnumber.dempstershafer_element pyuncertainnumber.DempsterShafer pyuncertainnumber.Dependency pyuncertainnumber.eCDF_bundle pyuncertainnumber.Interval pyuncertainnumber.Staircase pyuncertainnumber.Params pyuncertainnumber.Propagation Functions --------- .. autoapisummary:: pyuncertainnumber.I pyuncertainnumber.D pyuncertainnumber.DSS pyuncertainnumber.norm pyuncertainnumber.gaussian pyuncertainnumber.gamma pyuncertainnumber.normal pyuncertainnumber.alpha pyuncertainnumber.anglit pyuncertainnumber.argus pyuncertainnumber.arcsine pyuncertainnumber.beta pyuncertainnumber.betaprime pyuncertainnumber.bradford pyuncertainnumber.burr pyuncertainnumber.burr12 pyuncertainnumber.cauchy pyuncertainnumber.chi pyuncertainnumber.chi2 pyuncertainnumber.cosine pyuncertainnumber.known_properties pyuncertainnumber.min_max pyuncertainnumber.min_max_mean pyuncertainnumber.min_mean pyuncertainnumber.min_max_mean_std pyuncertainnumber.min_max_mean_var pyuncertainnumber.min_max_mode pyuncertainnumber.min_max_median pyuncertainnumber.mean_std pyuncertainnumber.mean_var pyuncertainnumber.pos_mean_std pyuncertainnumber.from_percentiles pyuncertainnumber.KS_bounds pyuncertainnumber.fit pyuncertainnumber.make_vec_interval pyuncertainnumber.parse_bounds pyuncertainnumber.intervalise pyuncertainnumber.hedge_interpret pyuncertainnumber.infer_cbox pyuncertainnumber.infer_predictive_distribution pyuncertainnumber.KS_bounds pyuncertainnumber.make_vec_interval pyuncertainnumber.reweighting pyuncertainnumber.get_ecdf pyuncertainnumber.convert pyuncertainnumber.envelope pyuncertainnumber.imposition pyuncertainnumber.stochastic_mixture pyuncertainnumber.stacking pyuncertainnumber.mixture_pbox pyuncertainnumber.mixture_ds pyuncertainnumber.env_samples pyuncertainnumber.env_ecdf_sep pyuncertainnumber.env_am pyuncertainnumber.env_pbox_am pyuncertainnumber.b2b pyuncertainnumber.taylor_expansion_method pyuncertainnumber.interval_monte_carlo pyuncertainnumber.slicing pyuncertainnumber.double_monte_carlo pyuncertainnumber.area_metric pyuncertainnumber.inspect_un Package Contents ---------------- .. py:data:: __version__ .. py:class:: UN(name=None, symbol=None, unit=None, uncertainty_type=None, essence=None, masses=None, intervals=None, distribution_parameters=None, pbox_parameters=None, hedge=None, _construct=None, nominal_value=1.0, p_flag=True, _skip_construct_init=False, measurand=None, nature=None, provenence=None, justification=None, structure=None, security=None, ensemble=None, variability=None, dependence=None, uncertainty=None, physical_quantity=None, _samples=None, **kwargs) Uncertain Number class :param - intervals: the interval specification for the UN object; :type - intervals: Interval :param - distribution_parameters: a list of the distribution family and its parameters; e.g. ['norm', [0, 1]]; :param - pbox_initialisation: a list of the distribution family and its parameters; e.g. ['norm', ([0,1], [3,4])]; .. rubric:: Example Uncertain numbers can be constructed in multiple ways. For example, a canonical way allows users to fill in as many fields as possible: >>> from pyuncertainnumber import UncertainNumber >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", intervals=[1, 2]) >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", distribution_parameters=['normal', (10, 2)]) >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", pbox_parameters=['normal', ([8, 12], [0.5, 1.5])]) >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", essence='dempster_shafer', intervals=[[1,5], [3,6]], masses=[0.5, 0.5]) Alternatively, users can use shortcuts to quickly create UN objects and get on with calculations: >>> import pyuncertainnumber as pun >>> pun.I([1, 2]) >>> pun.D('gaussian', (10, 2)) >>> pun.normal([8, 12], [0.5, 1.5]) >>> pun.DSS(intervals=[[1,5], [3,6]], masses=[0.5, 0.5]) .. py:attribute:: Q_ .. py:attribute:: instances :value: [] .. py:attribute:: name :value: None .. py:attribute:: symbol :value: None .. py:attribute:: uncertainty_type :value: None .. py:attribute:: essence :value: None .. py:attribute:: masses :value: None .. py:attribute:: intervals :value: None .. py:attribute:: distribution_parameters :value: None .. py:attribute:: pbox_parameters :value: None .. py:attribute:: hedge :value: None .. py:attribute:: _construct :value: None .. py:attribute:: nominal_value :value: 1.0 .. py:attribute:: p_flag :value: True .. py:attribute:: _skip_construct_init :value: False .. py:attribute:: measurand :value: None .. py:attribute:: nature :value: None .. py:attribute:: provenence :value: None .. py:attribute:: justification :value: None .. py:attribute:: structure :value: None .. py:attribute:: security :value: None .. py:attribute:: ensemble :value: None .. py:attribute:: variability :value: None .. py:attribute:: dependence :value: None .. py:attribute:: uncertainty :value: None .. py:attribute:: _physical_quantity :value: None .. py:attribute:: _samples :value: None .. py:property:: unit get the physical quantity of the uncertain number .. py:method:: __init_check() .. py:method:: __init_construct() the de facto parameterisation/instantiation procedure for the core constructs of the UN class caveat: user needs to by themselves figure out the correct shape of the 'distribution_parameters', such as ['uniform', [1,2]] .. py:method:: parameterised_pbox_specification() .. py:method:: _update_physical_quantity() .. py:method:: match_pbox(keyword, parameters) :staticmethod: match the distribution keyword from the initialisation to create the underlying distribution object :param - keyword: (str) the distribution keyword :param - parameters: (list) the parameters of the distribution .. py:method:: init_check() check if the UN initialisation specification is correct .. note:: a lot of things to double check. keep an growing list: 1. unit 2. hedge: user cannot speficy both 'hedge' and 'intervals'. 'intervals' takes precedence. .. py:method:: __str__() string representation of the UncertainNumber .. note:: the same as __reor__ for now until a better idea is proposed .. py:method:: __repr__() -> str Concise __repr__ .. py:method:: describe(style='verbose') print out a verbose description of the uncertain number .. py:method:: ci() get 95% range confidence interval .. py:method:: plot(**kwargs) quick plot of the uncertain number object .. py:method:: display(**kwargs) quick plot of the uncertain number object .. py:property:: construct .. py:property:: construct_type .. py:property:: physical_quantity get the physical quantity of the uncertain number .. py:method:: from_hedge(hedged_language) :classmethod: create an Uncertain Number from hedged language .. py:method:: fromConstruct(construct) :classmethod: create an Uncertain Number from a construct object .. py:method:: fromDistribution(D, **kwargs) :classmethod: create an Uncertain Number from a Distribution object. :param - D: a Distribution object :type - D: Distribution :param dist_family: the distribution family :type dist_family: str :param dist_params: the distribution parameters :type dist_params: list, tuple or string .. py:method:: from_Interval(u) :classmethod: .. py:method:: from_pbox(p) :classmethod: genenal from pbox .. py:method:: from_ds(ds) :classmethod: .. py:method:: from_sps(sps_dist) :classmethod: create an UN object from a parametric scipy.stats dist object #! it seems that a function will suffice :param - sps_dist: scipy.stats dist object .. note:: - sps_dist --> UN.Distribution object .. py:method:: __array_ufunc__(ufunc, method, *inputs, **kwargs) .. py:method:: _apply(method) .. py:method:: sqrt() .. py:method:: exp() .. py:method:: tanh() .. py:method:: tan() .. py:method:: log() .. py:method:: sin() .. py:method:: cos() .. py:method:: reciprocal() .. py:method:: bin_ops(other, ops) .. py:method:: __add__(other) add two uncertain numbers .. py:method:: __radd__(other) .. py:method:: __sub__(other) .. py:method:: __mul__(other) multiply two uncertain numbers .. py:method:: __rmul__(other) .. py:method:: __truediv__(other) divide two uncertain numbers .. py:method:: __rtruediv__(other) .. py:method:: __pow__(other) power of two uncertain numbers .. py:method:: __rpow__(other) power of two uncertain numbers .. py:method:: add(other, dependency='f') .. py:method:: sub(other, dependency='f') .. py:method:: mul(other, dependency='f') .. py:method:: div(other, dependency='f') .. py:method:: pow(other, dependency='f') .. py:method:: JSON_dump(filename='UN_data.json') the JSON serialisation of the UN object into the filesystem .. py:method:: to_pbox() convert the UN object to a pbox object .. py:class:: UncertainNumber(name=None, symbol=None, unit=None, uncertainty_type=None, essence=None, masses=None, intervals=None, distribution_parameters=None, pbox_parameters=None, hedge=None, _construct=None, nominal_value=1.0, p_flag=True, _skip_construct_init=False, measurand=None, nature=None, provenence=None, justification=None, structure=None, security=None, ensemble=None, variability=None, dependence=None, uncertainty=None, physical_quantity=None, _samples=None, **kwargs) Uncertain Number class :param - intervals: the interval specification for the UN object; :type - intervals: Interval :param - distribution_parameters: a list of the distribution family and its parameters; e.g. ['norm', [0, 1]]; :param - pbox_initialisation: a list of the distribution family and its parameters; e.g. ['norm', ([0,1], [3,4])]; .. rubric:: Example Uncertain numbers can be constructed in multiple ways. For example, a canonical way allows users to fill in as many fields as possible: >>> from pyuncertainnumber import UncertainNumber >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", intervals=[1, 2]) >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", distribution_parameters=['normal', (10, 2)]) >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", pbox_parameters=['normal', ([8, 12], [0.5, 1.5])]) >>> UncertainNumber(name="velocity", symbol="v", unit="m/s", essence='dempster_shafer', intervals=[[1,5], [3,6]], masses=[0.5, 0.5]) Alternatively, users can use shortcuts to quickly create UN objects and get on with calculations: >>> import pyuncertainnumber as pun >>> pun.I([1, 2]) >>> pun.D('gaussian', (10, 2)) >>> pun.normal([8, 12], [0.5, 1.5]) >>> pun.DSS(intervals=[[1,5], [3,6]], masses=[0.5, 0.5]) .. py:attribute:: Q_ .. py:attribute:: instances :value: [] .. py:attribute:: name :value: None .. py:attribute:: symbol :value: None .. py:attribute:: uncertainty_type :value: None .. py:attribute:: essence :value: None .. py:attribute:: masses :value: None .. py:attribute:: intervals :value: None .. py:attribute:: distribution_parameters :value: None .. py:attribute:: pbox_parameters :value: None .. py:attribute:: hedge :value: None .. py:attribute:: _construct :value: None .. py:attribute:: nominal_value :value: 1.0 .. py:attribute:: p_flag :value: True .. py:attribute:: _skip_construct_init :value: False .. py:attribute:: measurand :value: None .. py:attribute:: nature :value: None .. py:attribute:: provenence :value: None .. py:attribute:: justification :value: None .. py:attribute:: structure :value: None .. py:attribute:: security :value: None .. py:attribute:: ensemble :value: None .. py:attribute:: variability :value: None .. py:attribute:: dependence :value: None .. py:attribute:: uncertainty :value: None .. py:attribute:: _physical_quantity :value: None .. py:attribute:: _samples :value: None .. py:property:: unit get the physical quantity of the uncertain number .. py:method:: __init_check() .. py:method:: __init_construct() the de facto parameterisation/instantiation procedure for the core constructs of the UN class caveat: user needs to by themselves figure out the correct shape of the 'distribution_parameters', such as ['uniform', [1,2]] .. py:method:: parameterised_pbox_specification() .. py:method:: _update_physical_quantity() .. py:method:: match_pbox(keyword, parameters) :staticmethod: match the distribution keyword from the initialisation to create the underlying distribution object :param - keyword: (str) the distribution keyword :param - parameters: (list) the parameters of the distribution .. py:method:: init_check() check if the UN initialisation specification is correct .. note:: a lot of things to double check. keep an growing list: 1. unit 2. hedge: user cannot speficy both 'hedge' and 'intervals'. 'intervals' takes precedence. .. py:method:: __str__() string representation of the UncertainNumber .. note:: the same as __reor__ for now until a better idea is proposed .. py:method:: __repr__() -> str Concise __repr__ .. py:method:: describe(style='verbose') print out a verbose description of the uncertain number .. py:method:: ci() get 95% range confidence interval .. py:method:: plot(**kwargs) quick plot of the uncertain number object .. py:method:: display(**kwargs) quick plot of the uncertain number object .. py:property:: construct .. py:property:: construct_type .. py:property:: physical_quantity get the physical quantity of the uncertain number .. py:method:: from_hedge(hedged_language) :classmethod: create an Uncertain Number from hedged language .. py:method:: fromConstruct(construct) :classmethod: create an Uncertain Number from a construct object .. py:method:: fromDistribution(D, **kwargs) :classmethod: create an Uncertain Number from a Distribution object. :param - D: a Distribution object :type - D: Distribution :param dist_family: the distribution family :type dist_family: str :param dist_params: the distribution parameters :type dist_params: list, tuple or string .. py:method:: from_Interval(u) :classmethod: .. py:method:: from_pbox(p) :classmethod: genenal from pbox .. py:method:: from_ds(ds) :classmethod: .. py:method:: from_sps(sps_dist) :classmethod: create an UN object from a parametric scipy.stats dist object #! it seems that a function will suffice :param - sps_dist: scipy.stats dist object .. note:: - sps_dist --> UN.Distribution object .. py:method:: __array_ufunc__(ufunc, method, *inputs, **kwargs) .. py:method:: _apply(method) .. py:method:: sqrt() .. py:method:: exp() .. py:method:: tanh() .. py:method:: tan() .. py:method:: log() .. py:method:: sin() .. py:method:: cos() .. py:method:: reciprocal() .. py:method:: bin_ops(other, ops) .. py:method:: __add__(other) add two uncertain numbers .. py:method:: __radd__(other) .. py:method:: __sub__(other) .. py:method:: __mul__(other) multiply two uncertain numbers .. py:method:: __rmul__(other) .. py:method:: __truediv__(other) divide two uncertain numbers .. py:method:: __rtruediv__(other) .. py:method:: __pow__(other) power of two uncertain numbers .. py:method:: __rpow__(other) power of two uncertain numbers .. py:method:: add(other, dependency='f') .. py:method:: sub(other, dependency='f') .. py:method:: mul(other, dependency='f') .. py:method:: div(other, dependency='f') .. py:method:: pow(other, dependency='f') .. py:method:: JSON_dump(filename='UN_data.json') the JSON serialisation of the UN object into the filesystem .. py:method:: to_pbox() convert the UN object to a pbox object .. py:function:: I(*args: str | list[numbers.Number] | pyuncertainnumber.pba.intervals.number.Interval) -> UncertainNumber a shortcut to construct the interval-type UN object .. py:function:: D(*args, **kwargs) -> UncertainNumber a shortcut to construct the distribution-type UN object .. py:function:: DSS(*args, **kwargs) -> UncertainNumber a shortcut for the Dempster-Shafer-type UN object .. py:function:: norm(*args) .. py:function:: gaussian(*args) .. py:function:: gamma(*args) .. py:function:: normal(*args) .. py:function:: alpha(*args) .. py:function:: anglit(*args) .. py:function:: argus(*args) .. py:function:: arcsine(*args) .. py:function:: beta(*args) .. py:function:: betaprime(*args) .. py:function:: bradford(*args) .. py:function:: burr(*args) .. py:function:: burr12(*args) .. py:function:: cauchy(*args) .. py:function:: chi(*args) .. py:function:: chi2(*args) .. py:function:: cosine(*args) .. py:data:: uniform .. py:data:: lognormal .. py:function:: known_properties(maximum=None, mean=None, median=None, minimum=None, mode=None, percentiles=None, std=None, var=None, family=None, **kwargs) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber Construct a uncertain number given known statistical properties served as constraints. :param maximum: maximum value of the variable :type maximum: number :param mean: mean value of the variable :type mean: number :param median: median value of the variable :type median: number :param minimum: minimum value of the variable :type minimum: number :param mode: mode value of the variable :type mode: number :param percentiles: dictionary of percentiles and their values, e.g. {0: 0, 0.1: 1, 0.5: 2, 0.9: pun.I(3,4), 1:5} :type percentiles: dict :param std: standard deviation of the variable :type std: number :param var: variance of the variable :type var: number :param family: name of the distribution family, e.g. 'normal', 'lognormal', 'uniform', 'triangular', etc. :type family: str :returns: uncertain number .. note:: It's also possible to directly call a function given the known information, such as ``pun.mean_std(mean=1, std=0.5)``. .. rubric:: Example >>> from pyuncertainnumber.pba import known_properties >>> known_properties( ... maximum = 2, ... mean = 1, ... var = 0.25, ... minimum=0, ... ) .. py:data:: known_constraints .. py:function:: min_max(minimum: numbers.Number, maximum: numbers.Number) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Equivalent to an interval object constructed as a nonparametric Pbox. :param minimum: Left end of box :param maximum: Right end of box :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> from pyuncertainnumber.pba import min_max >>> min_max(0, 2) # return a UncertainNumber >>> min_max(0, 2, return_construct=True) # return a Pbox .. py:function:: min_max_mean(minimum: numbers.Number, maximum: numbers.Number, mean: numbers.Number, steps: int = Params.steps) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Generates a distribution-free p-box based upon the minimum, maximum and mean of the variable :param minimum: minimum value of the variable :type minimum: float :param maximum: maximum value of the variable :type maximum: float :param mean: mean value of the variable :type mean: float :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> min_max_mean(0, 2, 1) .. py:function:: min_mean(minimum, mean, steps=Params.steps) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Nonparametric pbox construction based on constraint of minimum and mean :param minimum: minimum value of the variable :type minimum: number :param mean: mean value of the variable :type mean: number :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> from pyuncertainnumber.pba import min_mean >>> min_mean(0, 1) # return a UncertainNumber >>> min_mean(0, 1, return_construct=True) # return a Pbox .. py:function:: min_max_mean_std(minimum: numbers.Number, maximum: numbers.Number, mean: numbers.Number, std: numbers.Number, **kwargs) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Generates a distribution-free p-box based upon the minimum, maximum, mean and standard deviation of the variable :param maximum: maximum value of the variable :type maximum: number :param minimum: minimum value of the variable :type minimum: number :param std: standard deviation of the variable :type std: number :param var: variance of the variable :type var: number :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> min_max_mean_std(0, 2, 1, 0.5) # return a UncertainNumber .. seealso:: :func:`min_max_mean_var` .. py:function:: min_max_mean_var(minimum: numbers.Number, maximum: numbers.Number, mean: numbers.Number, var: numbers.Number, **kwargs) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Generates a distribution-free p-box based upon the minimum, maximum, mean and standard deviation of the variable :param minimum: minimum value of the variable :type minimum: number :param maximum: maximum value of the variable :type maximum: number :param mean: mean value of the variable :type mean: number :param var: variance of the variable :type var: number .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> min_max_mean_var(0, 2, 1, 0.25) # return a UncertainNumber .. admonition:: Implementation Equivalent to ``min_max_mean_std(minimum,maximum,mean,np.sqrt(var))`` .. seealso:: :func:`min_max_mean_std` .. py:function:: min_max_mode(minimum: numbers.Number, maximum: numbers.Number, mode: numbers.Number, steps: int = Params.steps) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Nonparametric pbox construction based on constraint of mean and var :param minimum: minimum value of the variable :param maximum: maximum value of the variable :param mode: mode value of the variable :type mode: number :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> min_max_mode(0, 2, 1) # return a UncertainNumber .. py:function:: min_max_median(minimum: numbers.Number, maximum: numbers.Number, median: numbers.Number, steps: int = Params.steps) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Generates a distribution-free p-box based upon the minimum, maximum and median of the variable :param minimum: minimum value of the variable :param maximum: maximum value of the variable :param median: median value of the variable :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> min_max_median(0, 2, 1) # return a UncertainNumber .. py:function:: mean_std(mean: numbers.Number, std: numbers.Number, steps=Params.steps) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Nonparametric pbox construction based on constraint of mean and std :param mean: mean value of the variable :type mean: number :param std: std value of the variable :type std: number :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> mean_std(1, 0.5) .. py:function:: mean_var(mean: numbers.Number, var: numbers.Number) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox Nonparametric pbox construction based on constraint of mean and var :param mean: mean value of the variable :type mean: number :param vasr: var value of the variable :type vasr: number :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> mean_var(1, 0.25) # return a UncertainNumber .. py:function:: pos_mean_std(mean: numbers.Number, std: numbers.Number, steps=Params.steps) -> pyuncertainnumber.pba.pbox_abc.Pbox Generates a positive distribution-free p-box based upon the mean and standard deviation of the variable :param mean: mean of the variable :param std: standard deviation of the variable :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. py:function:: from_percentiles(percentiles: dict, steps: int = Params.steps) -> pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber | pyuncertainnumber.pba.pbox_abc.Pbox yields a distribution-free p-box based on specified percentiles of the variable :param percentiles: dictionary of percentiles and their values (e.g. {0: 0, 0.1: 1, 0.5: 2, 0.9: I(3,4), 1:5}) :param steps: number of steps to use in the p-box .. note:: The percentiles dictionary is of the form {percentile: value}. Where value can either be a number or an I. If value is a number, the percentile is assumed to be a point percentile. If value is an I, the percentile is assumed to be an interval percentile. If no keys for 0 and 1 are given, ``-np.inf`` and ``np.inf`` are used respectively. This will result in a p-box that is not bounded and raise a warning. If the percentiles are not increasing, the percentiles will be intersected. This may not be desired behaviour. ValueError: If any of the percentiles are not between 0 and 1. :returns: UncertainNumber or Pbox .. tip:: Two types of return values are possible: - by default, a `UncertainNumber` is returned; - For low-level controls, if `return_construct=True` is specified, a `Pbox` is returned. .. rubric:: Example >>> pba.from_percentiles( >>> {0: 0, >>> 0.25: 0.5, >>> 0.5: pba.I(1,2), >>> 0.75: pba.I(1.5,2.5), >>> 1: 3}) >>> .display() .. py:function:: KS_bounds(s: numpy.typing.ArrayLike, alpha: float, display=True, output_type='bounds') -> Union[tuple[pyuncertainnumber.pba.ecdf.eCDF_bundle], pyuncertainnumber.pba.pbox_abc.Pbox, pyuncertainnumber.UncertainNumber] construct free pbox from sample data by Kolmogorov-Smirnoff confidence bounds :param s: sample data, precise and imprecise :type s: ArrayLike :param dn: KS critical value at a significance level and sample size N; :type dn: float :param output_type: A choice between {'bounds', 'pbox', 'un'}, default='bounds' which returns two eCDF bundles as bounds; 'pbox' to return a pbox object; 'un' to return an uncertain number object. :type output_type: str :returns: a tuple of two CDF bounds, i.e. upper and lower (eCDF_bundle objects), or a Pbox object, or an UncertainNumber object the return type is controlled by the `output_type` argument. .. note:: By default the function returns two eCDF bundles as the extreme bounds. With the upper and lower bounds, a free pbox can be constructed. .. rubric:: Example >>> # both precise data (e.g. numpy array) and imprecise data (e.g. a vector of interval) are supported >>> precise_data = np.random.normal(0, 1, 100) # precise data case >>> ub, lb = pba.KS_bounds(precise_data, alpha=0.025, display=True) >>> # alternatively, an uncertain number or a p-box can be returned >>> pba.KS_bounds(precise_data, alpha=0.025, display=False, output_type='pbox') # return a pbox object >>> pba.KS_bounds(precise_data, alpha=0.025, display=False, output_type='un') # return an uncertain number object >>> # imprecise data case >>> impre_data = pba.I(lo = precise_data -0.5, hi = precise_data + 0.5) >>> ub, lb = pba.KS_bounds(impre_data, alpha=0.025, display=True) .. figure:: /_static/ks_bounds_demo.png :alt: ks_bounds :align: center :width: 50% Kolmogorov-Smirnoff confidence bounds illustration with precise and imprecise data. .. py:function:: fit(method: str, family: str, data: numpy.ndarray) -> pyuncertainnumber.UncertainNumber parametric estimator to fit a distribution from data :param method: method of fitting, e.g., {'mle' or 'mom'} 'entropy', 'pert', 'fermi', 'bayesian' :type method: str :param family: distribution family to be fitted :type family: str :param data: data to be fitted :type data: np.ndarray :returns: - UncertainNumber object .. rubric:: Example >>> # precise data >>> pun.fit('mle', 'norm', np.random.normal(0, 1, 100)) >>> # imprecise data >>> precise_sample = sps.expon(scale=1/0.4).rvs(15) >>> imprecise_data = pba.I(lo = precise_sample - 1.4, hi=precise_sample + 1.4) >>> pun.fit('mom', family='exponential', data=imprecise_data) .. seealso:: :func:`pyuncertainnumber.pba.KS_bounds` : a non-parametric charactearisation method using Kolmogorov-Smirnov bounds .. py:class:: Pbox(left: numpy.ndarray | list, right: numpy.ndarray | list, steps=Params.steps, mean=None, var=None, p_values=None) Bases: :py:obj:`pyuncertainnumber.pba.mixins.NominalValueMixin`, :py:obj:`abc.ABC` a base class for Pbox .. danger:: this is an abstract class and should not be instantiated directly. .. seealso:: :class:`pbox_abc.Staircase` and :class:`pbox_abc.Leaf` for concrete implementations. .. py:property:: left .. py:property:: right .. py:attribute:: steps :value: 200 .. py:attribute:: mean :value: None .. py:attribute:: var :value: None .. py:attribute:: _pvalues .. py:method:: _init_moments() :abstractmethod: .. py:method:: _init_range() .. py:method:: post_init_check() .. py:method:: steps_check() .. py:method:: _compute_nominal_value() .. py:method:: degenerate_flag() -> bool check if the pbox is degenerate (i.e. left == right everywhere) .. py:property:: degenerate :type: bool .. py:property:: p_values .. py:property:: range .. py:property:: lo Returns the left-most value in the interval .. py:property:: hi Returns the right-most value in the interval .. py:property:: support .. py:property:: median .. py:property:: enclosed_area the enclosed area between the two extreme cdfs .. py:method:: __iter__() .. py:method:: __eq__(other) Equality operator for Pbox objects .. note:: - two pboxes are equal if their left and right bounds are equal .. py:method:: __contains__(item) .. py:method:: to_interval() discretise pbox into a vec-interval of length of default steps .. note:: If desired a custom length of vec-interval as output, use `discretise()` method. .. py:method:: to_dss(discretisation=Params.steps) convert pbox to DempsterShafer object .. py:method:: to_numpy() convert pbox to a 2D numpy array (n, 2) of left and right .. py:class:: Staircase(left, right, steps=200, mean=None, var=None, p_values=None) Bases: :py:obj:`Pbox` distribution free p-box .. py:method:: _init_moments() Initialize mean/var interval estimates. strategy: 1) Try LP-based bounds. 2) If that fails, try ECDF-based bounds. 3) If that also fails, set to NaN intervals so the program continues. This function NEVER raises. .. py:method:: __repr__() .. py:method:: plot(title=None, ax=None, style='box', fill_color='lightgray', bound_colors=None, bound_styles=None, left_line_kwargs=None, right_line_kwargs=None, nuance='step', alpha=0.3, **kwargs) default plotting function :param style: 'box' or 'simple' :type style: str :param fill_color: color to fill the box (only for 'box' style) :type fill_color: str :param bound_colors: list of two colors for left and right bound lines :type bound_colors: list :param bound_styles: list of two linestyles for left and right bound lines :type bound_styles: list :param left_line_kwargs: additional kwargs for left bound line :type left_line_kwargs: dict :param right_line_kwargs: additional kwargs for right bound line :type right_line_kwargs: dict :param nuance: 'step' or 'curve' for bound line styles :type nuance: str :param alpha: transparency level for the box fill (only for 'box' style) :type alpha: float :param \*\*kwargs: additional keyword arguments for the plot .. note:: Two styles are supported: a 'box' with fill-in color and a 'simple' one without fill-in color. Color and linestyle of the bound lines can be customized via the `bound_styles`, `left_line_kwargs`, and `right_line_kwargs` parameters. The argument `nuance` controls whether the bound lines are plotted as step functions ('step') or smooth curves ('curve'). .. rubric:: Example >>> a = pba.normal([2, 6], [0.5, 1]) >>> fig, ax = plt.subplots() >>> a.plot(ax=ax, style='simple') # simple style without fill-in color >>> # box style with fill-in color and also customized bound colors >>> a.plot(ax=ax, style='box', ... fill_color='lightblue', ... bound_colors = ['lightblue', 'lightblue'], ... bound_styles=("--", ":"), ... alpha=0.5 ... ) >>> # customized left and right bound line styles >>> ax = pbox.plot( ... left_line_kwargs={"linestyle": "--", "linewidth": 2}, ... right_line_kwargs={"linestyle": ":", "linewidth": 2, "alpha": 0.8}, ) .. py:method:: plot_reverse_axis(title=None, ax=None, style='box', fill_color='lightgray', bound_colors=None, nuance='step', alpha=0.3, orientation='xy', invert_xaxis=True, **kwargs) A testing plotting function that can swap quantile and probability axes. :param style: 'box' or 'simple' :type style: str :param orientation: 'xy' keeps x on horizontal and Pr(X<=x) on vertical; 'yx' swaps them. :type orientation: str .. py:method:: plot_outside_legend(title=None, ax=None, style='box', fill_color='lightgray', bound_colors=None, nuance='step', alpha=0.3, **kwargs) a specific variant of `plot()` which is used for scipy proceeding only. :param style: 'box' or 'simple' :type style: str .. py:method:: display(*args, **kwargs) .. py:method:: plot_probability_bound(x: float, ax=None, linecolor='r', markercolor='r', **kwargs) plot the probability bound at a certain quantile x .. note:: - a vertical line .. py:method:: plot_quantile_bound(p: float, ax=None, **kwargs) plot the quantile bound at a certain probability level p .. note:: - a horizontal line .. py:method:: from_CDFbundle(a, b) :classmethod: pbox from two emipirical CDF bundle :param - a: CDF bundle of lower extreme F; :param - b: CDF bundle of upper extreme F; .. py:method:: __neg__() .. py:method:: __add__(other) .. py:method:: __radd__(other) .. py:method:: __sub__(other) .. py:method:: __rsub__(other) .. py:method:: __mul__(other) .. py:method:: __rmul__(other) .. py:method:: __truediv__(other) .. py:method:: __rtruediv__(other) .. py:method:: __pow__(other) .. py:method:: __rpow__(other: numbers.Number) Power operation with the base as `other` and self as the exponent .. py:method:: __array_ufunc__(ufunc, method, *inputs, **kwargs) .. py:method:: cdf(x: numpy.ndarray) get the bounds on the cdf w.r.t x value :param x: x values :type x: array-like .. py:method:: alpha_cut(alpha=0.5) test the lightweight `alpha_cut` method :param alpha: probability levels :type alpha: array-like .. py:method:: sample(n_sam) LHS sampling by default .. py:method:: precise_sample(n_a: int, theta: float = None, n_e: int = None) Generate precise samples from a p-box .. py:method:: discretise(n=None) -> pyuncertainnumber.Interval alpha-cut discretisation of the p-box without outward rounding :param n: number of steps to be used in the discretisation. :type n: int :returns: vector Interval .. py:method:: outer_discretisation(n=None) discretisation of a p-box to get intervals based on the scheme of outer approximation :param n: number of steps to be used in the discretisation :type n: int .. note:: `the_interval_list` will have length one less than that of default `p_values` (i.e. 100 and 99) :returns: the outer intervals in vec-Interval form .. py:method:: condensation(n) -> Self ourter condensation of the pbox to reduce the number of steps and get a sparser staircase pbox :param n: number of steps to be used in the discretisation :type n: int .. note:: Have not thought about a better name so we call it `condensation` for now. Candidate names include 'approximation'. It will ouput a p-box and keep steps as 200 for computational consistency. .. rubric:: Example >>> p.condensation(n=5) :returns: a staircase p-box that looks sparser but has the same number of steps .. py:method:: condense(n) -> pyuncertainnumber.pba.dss.DempsterShafer Another condensation function which has steps of n Compared to the above `condensation` method that ouputs a p-box and keeps steps as 200 for computational consistency. This one condenses in a more literal manner, as in having n steps in the resulting Dempster-Shafer structure. .. py:method:: truncate(a, b) Truncate the Pbox to the range [a, b]. example: >>> from pyuncertainnumber import pba >>> p = pba.normal([4, 9], 1) >>> tr = p.truncate(3, 8) >>> fig, ax = plt.subplots() >>> p.plot(ax=ax) >>> tr.plot(ax=ax, fill_color='r') >>> plt.show() .. py:method:: min(other, method='f') Returns a new Pbox object that represents the element-wise minimum of two Pboxes. :param - other: Another Pbox object or a numeric value. :param - method: Calculation method to determine the minimum. Can be one of 'f', 'p', 'o', 'i'. :returns: Pbox .. py:method:: max(other, method='f') .. py:method:: get_PI(alpha: numbers.Number = 0.95, style='narrowest') -> pyuncertainnumber.Interval Compute the predictive interval at the coverage level of `alpha` :param alpha: coverage level for the predictive interval, default is 0.95 :type alpha: Number :param style: 'narrowest' or 'widest', default is 'narrowest' :type style: str .. note:: by default, narrowest predictive interval is returned; when the narrowest does not exist, a warning will the generated and then the widest is returned instead. .. rubric:: Example >>> from pyuncertainnumber import pba >>> p = pba.normal([10, 15, 1]) >>> p.get_PI(alpha=0.95, style='narrowest') .. py:method:: straddles(N, endpoints=True) -> bool Check whether the p-box straddles a number N :param N: the Number to check :type N: float :param endpoints: Whether to include the endpoints within the check :type endpoints: Boolean :returns: True If :math:`\mathrm{left} \leq N \leq \mathrm{right}` (Assuming `endpoints=True`) False Otherwise .. note:: This could affect the results of Frechet bounds .. py:method:: straddles_zero() -> bool Checks specifically whether :math:`0` is within the p-box .. py:method:: is_zero() .. py:method:: is_nagative() .. py:method:: env(other) computes the envelope of two Pboxes. :param other: :type other: Pbox :returns: - Pbox .. py:method:: imp(other) Returns the imposition of self with other pbox .. note:: - binary imposition between two pboxes only .. py:method:: _unary_template(f) .. py:method:: exp() exponential function: e^x .. py:method:: sqrt() square root function: √x .. py:method:: reciprocal() Calculate the reciprocal of the pbox .. note:: the pbox should not straddle zero, otherwise a warning is raised .. py:method:: log() natural logarithm of the pbox .. note:: - the pbox must be positive .. py:method:: sin() .. py:method:: cos() .. py:method:: tanh() .. py:method:: add(other, dependency='f') .. py:method:: sub(other, dependency='f') .. py:method:: mul(other, dependency='f') Multiplication of uncertain numbers with the defined dependency dependency .. py:method:: div(other, dependency='f') .. py:method:: pow(other, dependency='f') Exponentiation of uncertain numbers with the defined dependency dependency This suggests that the exponent (i.e. `other`) can also be an uncertain number. .. py:method:: balchprod(other) Frechet convolution of two pboxes when any of them straddles zero .. py:class:: Interval(lo: Union[float, numpy.ndarray], hi: Optional[Union[float, numpy.ndarray]] = None, do_heavy_checks: bool = True) Bases: :py:obj:`pyuncertainnumber.pba.mixins.NominalValueMixin` Interval is the main class .. py:attribute:: _lo .. py:attribute:: _hi :value: None .. py:method:: run_heavy_checks() Run heavy checks on the interval object .. py:method:: __repr__() .. py:method:: __str__() .. py:method:: __len__() .. py:method:: __iter__() .. py:method:: __contains__(item) Check if an item is enclosed within the interval. .. rubric:: Example >>> i = Interval(1,3) >>> 2 in i True >>> 4 in i False .. py:method:: __next__() .. py:method:: __getitem__(i: Union[int, slice]) .. py:method:: to_numpy() -> numpy.ndarray transform interval objects to numpy arrays .. py:method:: to_pbox() .. py:method:: lhs_sample(n) -> numpy.ndarray LHS sampling within the interval :param n: number of samples .. py:method:: endpoints_lhs_sample(n) -> numpy.ndarray LHS sampling within the interval plus the endpoints :param n: number of samples .. py:method:: plot(ax=None, **kwargs) .. py:method:: display() .. py:method:: is_degenerate() -> bool Check if the interval is degenerate (i.e., has zero width). .. py:method:: _compute_nominal_value() .. py:method:: ravel() Return a flattened (1D) interval object for multi-dimensional intervals .. rubric:: Example >>> A = np.random.rand(200, 200, 2) >>> i = pba.intervalise(A) >>> print(i.shape) >>> i2 = i.ravel() >>> print(i2.shape) .. py:property:: lo :type: Union[numpy.ndarray, float] .. py:property:: hi :type: Union[numpy.ndarray, float] .. py:property:: left .. py:property:: right .. py:property:: width .. py:property:: rad half width .. py:property:: mid .. py:property:: unsized .. py:property:: val seemingly equivalent to `self.to_numpy()` .. py:property:: scalar Check if the interval is wide sense scalar .. note:: wide sense: I(1,2) and I([1],[2]) are both scalars .. py:property:: is_scalar Check if the interval is a strict-sense scalar .. note:: strict sense: I(1,2) is a scalar, but I([1],[2]) is not .. py:property:: shape .. py:property:: ndim .. py:method:: __neg__() .. py:method:: __pos__() .. py:method:: __add__(other) .. py:method:: __radd__(left) .. py:method:: __sub__(other) .. py:method:: __rsub__(left) .. py:method:: __mul__(other) .. py:method:: __rmul__(left) .. py:method:: __truediv__(other) .. py:method:: __rtruediv__(left) .. py:method:: __pow__(other) .. py:method:: __lt__(other) .. py:method:: __rlt__(left) .. py:method:: __gt__(other) .. py:method:: __rgt__(left) .. py:method:: __le__(other) .. py:method:: __rle__(left) .. py:method:: __ge__(other) .. py:method:: __rge__(left) .. py:method:: __eq__(other) .. py:method:: __ne__(other) .. py:method:: __array_ufunc__(ufunc, method, *inputs, **kwargs) .. py:method:: abs() .. py:method:: sqrt() .. py:method:: exp() .. py:method:: log() .. py:method:: sin() .. py:method:: cos() .. py:method:: tan() .. py:method:: from_meanform(x, half_width) :classmethod: .. py:method:: save_json(filename: str, comment: str = None, save_dir: str | pathlib.Path = '.') -> None Save the interval object to a JSON5 file. :param filename: The name of the file (without extension) to save the interval object to. :type filename: str :param comment: A comment to include at the top of the file. :type comment: str, optional :param save_dir: Directory where the file should be saved. Defaults to current directory. :type save_dir: str | Path, optional .. note:: The file is saved with a `.json5` extension. .. rubric:: Example >>> a.save_json("interval_data", comment="This is interval data", save_dir="results/") .. py:function:: make_vec_interval(vec) parse an array-like structure into a vector interval For most part, it works same to `intervalise`, except that this function can also handle a list of UN objects. .. rubric:: Example >>> a, b = pba.I(1, 2), pba.I(3, 4) >>> make_vec_interval([a, b]) Interval([1, 3], [2, 4]) .. py:function:: parse_bounds(b) top-level function that universally parses scalar and vector bounds .. py:function:: intervalise(x_: Any, interval_index=-1) -> Union[pyuncertainnumber.pba.intervals.number.Interval, Any] This function casts an array-like structure into an Interval structure. All array-like structures will be first coerced into an ndarray of floats. If the coercion is unsuccessful the following error is thrown: `ValueError: setting an array element with a sequence.` For example this is the expected behaviour: (*) an ndarray of shape (4,2) will be cast as an Interval of shape (4,). (*) an ndarray of shape (7,3,2) will be cast as an Interval of shape (7,3). (*) an ndarray of shape (3,2,7) will be cast as a degenerate Interval of shape (3,2,7). (*) an ndarray of shape (2,3,7) will be cast as an Interval of shape (3,7). (*) an ndarray of shape (2,3,7,2) will be cast as an Interval of shape (2,3,7) if interval_index is set to -1. If an ndarray has shape with multiple dimensions having size 2, then the last dimension is intervalised. So, an ndarray of shape (7,2,2) will be cast as an Interval of shape (7,2) with the last dimension intervalised. When the ndarray has shape (2,2) again is the last dimension that gets intervalised. In case of ambiguity, e.g. (2,5,2), now the first dimension can be forced to be intervalised, selecting index=0, default is -1. It returns an interval only if the input is an array-like structure, otherwise it returns the following numpy error: `ValueError: setting an array element with a sequence.` TODO: Parse a list of mixed numbers: interval and ndarrays. .. py:class:: EpistemicDomain(*vars: pyuncertainnumber.pba.intervals.Interval) Representation of the epistemic space which are indeed bounds of each dimension This class provides a set of handy functions to work with epistemic uncertainty in the form of bounds. It will be useful for tasks such as propagation or optimization where epistemic uncertainty is involved. :param vars: a set of Interval variables .. tip:: Recommended to use for optimisation tasks where the design bounds can be quickly specified with the ``toOptBounds()`` method. .. seealso:: :class:`pyuncertainnumber.src.pyuncertainnumber.opt.bo` : Bayesian optimisation class. :class:`pyuncertainnumber.src.pyuncertainnumber.opt.ga` : Genetic algorithm class. .. rubric:: Example >>> from pyuncertainnumber import pba >>> e = EpistemicDomain(pba.I(-1, 3), pba.I(5, 9)) >>> # convert the epistemic space to bounds for the optimizer >>> e.toOptBounds(method='GA') # `varbound` for genetic algorithm >>> e.toOptBounds(method='BO') # `xc_bounds` for Bayesian optimisation >>> # perform lhs sampling on the epistemic space >>> sample = e.lhs_sampling(1000) .. py:method:: lhs_sampling(n_samples: int) perform lhs sampling on the epistemic space .. py:method:: lhs_plus_endpoints(n_samples: int) perform lhs sampling on the epistemic space and add endpoints .. py:method:: bound_rep() return the bounds (vec or matrix) of the epistemic space .. py:method:: toOptBounds(method: str) convert the epistemic space to bounds for the optimizer :param method: the optimization method to use, e.g. 'BayesOpt', 'GA' :type method: str :returns: the bounds of the design varibale used for the optimisation method .. py:method:: to_GA_varBounds() -> numpy.ndarray convert the epistemic space to bounds for the genetic algorithm optimizer .. py:method:: to_BayesOptBounds(func_signature='vectorisation') -> dict convert the epistemic space to bounds for the Bayesian optimisation optimizer .. py:function:: hedge_interpret(hedge: str, return_type='interval') -> pyuncertainnumber.pba.intervals.Interval | pyuncertainnumber.pba.pbox_abc.Pbox interpret linguistic hedge words into UncertainNumber objects :param hedge: the hedge numerical expression to be interpreted :type hedge: str :param return_type: the type of object to be returned, either 'interval' or 'pbox' :type return_type: str .. note:: - the return can either be an interval or a pbox object .. rubric:: Example >>> hedge_interpret("about 200", return_type="pbox") >>> hedge_interpret("200.00") .. py:function:: infer_cbox(family: str, data, **args) -> pyuncertainnumber.pba.cbox_constructor.Cbox top-level call signature to infer a c-box given data and family, plus rarely additional kwargs .. rubric:: Notes - data (list): a list of data samples, e.g. [2] - additina kwargs such as N for binomial family .. rubric:: Example >>> infer_cbox('binomial', data=[2], N=10) .. py:function:: infer_predictive_distribution(family: str, data, **args) top-level call for the next value predictive distribution .. py:class:: dempstershafer_element Bases: :py:obj:`tuple` .. py:attribute:: interval .. py:attribute:: mass .. py:class:: DempsterShafer(intervals: pyuncertainnumber.pba.intervals.Interval | list[list] | list[pyuncertainnumber.pba.intervals.Interval] | numpy.ndarray, masses: numpy.typing.ArrayLike) Bases: :py:obj:`pyuncertainnumber.pba.mixins.NominalValueMixin`, :py:obj:`pyuncertainnumber.pba.mixins._PboxOpsMixin` Class for Dempester-Shafer structures. :param intervals: expect wildcard vector intervals, vec-Interval; list of scalar intervals; list of list pairs; or 2D array; :param masses: probability masses :type masses: ArrayLike .. rubric:: Example >>> from pyuncertainnumber import pba >>> dss = pba.DempsterShafer(intervals=[[1,5], [3,6]], masses=[0.5, 0.5]) >>> dss.structures [dempstershafer_element(interval=[1.0,5.0], mass=0.5), dempstershafer_element(interval=[3.0,6.0], mass=0.5)] .. note:: Dempster-Shafer structures are also called belief structures or evidence structures, and it can be converted to p-boxes. .. figure:: /_static/dss_pbox_illustration.png :alt: p-box and DSS illustration :align: center :width: 80% P-box and Dempster Shafer structure illustration. .. py:attribute:: _intervals .. py:attribute:: _masses .. py:method:: _create_DSstructure() .. py:method:: __repr__() .. py:method:: _compute_nominal_value() .. py:property:: structures .. py:property:: intervals Returns the Interval-typed focal elements of the Dempster-Shafer structure. .. py:property:: focal_elements Returns the focal elements of the Dempster-Shafer structure. .. py:property:: masses .. py:method:: plot(style='raw', ax=None, zorder=None, **kwargs) for box type transform dss into a pbox and plot :param style: "raw" (default), "box", "pbox", "interval" :type style: str :param edge_color: edge color for raw style. If None, use default red color. :type edge_color: str .. py:method:: display(style='box', ax=None, **kwargs) .. py:method:: to_pbox() .. py:method:: _to_pbox() for mixin use only .. py:method:: from_dsElements(*ds_elements: dempstershafer_element) :classmethod: Create a Dempster-Shafer structure from a list of Dempster-Shafer elements. .. py:class:: Dependency(family: str, params: numbers.Number | None = None, **kwargs) Dependency class to specify copula models. :param family: Name of the copula family, one of "gaussian", "t", "frank", "gumbel", "clayton", "independence". :type family: str :param params: Backward-compatible single-parameter shortcut: - gaussian/t: interpreted as corr - frank/gumbel/clayton: interpreted as theta - independence: ignored :type params: Number | None :param \*\*kwargs: Any keyword parameters supported by the selected copula, e.g. corr=..., df=..., theta=..., k_dim=..., allow_singular=... .. rubric:: Examples >>> Dependency("gaussian", params=0.8, k_dim=3) # legacy style >>> Dependency("gaussian", corr=0.8, k_dim=3) # explicit >>> Dependency("t", corr=0.6, df=5, k_dim=4) >>> Dependency("frank", theta=2.5, k_dim=2) >>> Dependency("independence", k_dim=5) .. py:attribute:: copulas_dict .. py:attribute:: _single_param_alias .. py:attribute:: family :value: '' .. py:attribute:: params :value: None .. py:attribute:: _copula .. py:property:: copula Access the underlying statsmodels copula instance. .. py:method:: _post_init_check() .. py:method:: __repr__() .. py:method:: pdf(u) .. py:method:: cdf(u) .. py:method:: u_sample(n: int, random_state=None) draws n samples in the U space (unit hypercube) .. py:method:: display(style='3d_cdf', ax=None) show the PDF or CDF in the u space .. py:method:: fit(data) .. py:function:: KS_bounds(s: numpy.typing.ArrayLike, alpha: float, display=True, output_type='bounds') -> Union[tuple[pyuncertainnumber.pba.ecdf.eCDF_bundle], pyuncertainnumber.pba.pbox_abc.Pbox, pyuncertainnumber.UncertainNumber] construct free pbox from sample data by Kolmogorov-Smirnoff confidence bounds :param s: sample data, precise and imprecise :type s: ArrayLike :param dn: KS critical value at a significance level and sample size N; :type dn: float :param output_type: A choice between {'bounds', 'pbox', 'un'}, default='bounds' which returns two eCDF bundles as bounds; 'pbox' to return a pbox object; 'un' to return an uncertain number object. :type output_type: str :returns: a tuple of two CDF bounds, i.e. upper and lower (eCDF_bundle objects), or a Pbox object, or an UncertainNumber object the return type is controlled by the `output_type` argument. .. note:: By default the function returns two eCDF bundles as the extreme bounds. With the upper and lower bounds, a free pbox can be constructed. .. rubric:: Example >>> # both precise data (e.g. numpy array) and imprecise data (e.g. a vector of interval) are supported >>> precise_data = np.random.normal(0, 1, 100) # precise data case >>> ub, lb = pba.KS_bounds(precise_data, alpha=0.025, display=True) >>> # alternatively, an uncertain number or a p-box can be returned >>> pba.KS_bounds(precise_data, alpha=0.025, display=False, output_type='pbox') # return a pbox object >>> pba.KS_bounds(precise_data, alpha=0.025, display=False, output_type='un') # return an uncertain number object >>> # imprecise data case >>> impre_data = pba.I(lo = precise_data -0.5, hi = precise_data + 0.5) >>> ub, lb = pba.KS_bounds(impre_data, alpha=0.025, display=True) .. figure:: /_static/ks_bounds_demo.png :alt: ks_bounds :align: center :width: 50% Kolmogorov-Smirnoff confidence bounds illustration with precise and imprecise data. .. py:function:: make_vec_interval(vec) parse an array-like structure into a vector interval For most part, it works same to `intervalise`, except that this function can also handle a list of UN objects. .. rubric:: Example >>> a, b = pba.I(1, 2), pba.I(3, 4) >>> make_vec_interval([a, b]) Interval([1, 3], [2, 4]) .. py:function:: reweighting(*masses) reweight the masses to sum to 1 .. py:class:: eCDF_bundle a handy tuple of eCDF function q and p .. py:attribute:: quantiles :type: numpy.ndarray .. py:attribute:: probabilities :type: numpy.ndarray .. py:method:: __repr__() .. py:method:: from_sps_ecdf(e) :classmethod: utility to tranform sps.ecdf to eCDF_bundle .. py:method:: plot_bounds(other) plot the lower and upper bounds .. py:function:: get_ecdf(s, w=None, display=False) -> tuple compute the weighted ecdf from (precise) sample data :param s: 1 dimensional precise sample data :type s: array-like :param w: weights :type w: array-like .. note:: - Sudret eq.1 :returns: ecdf in the form of a tuple of q and p .. py:class:: Interval(lo: Union[float, numpy.ndarray], hi: Optional[Union[float, numpy.ndarray]] = None, do_heavy_checks: bool = True) Bases: :py:obj:`pyuncertainnumber.pba.mixins.NominalValueMixin` Interval is the main class .. py:attribute:: _lo .. py:attribute:: _hi :value: None .. py:method:: run_heavy_checks() Run heavy checks on the interval object .. py:method:: __repr__() .. py:method:: __str__() .. py:method:: __len__() .. py:method:: __iter__() .. py:method:: __contains__(item) Check if an item is enclosed within the interval. .. rubric:: Example >>> i = Interval(1,3) >>> 2 in i True >>> 4 in i False .. py:method:: __next__() .. py:method:: __getitem__(i: Union[int, slice]) .. py:method:: to_numpy() -> numpy.ndarray transform interval objects to numpy arrays .. py:method:: to_pbox() .. py:method:: lhs_sample(n) -> numpy.ndarray LHS sampling within the interval :param n: number of samples .. py:method:: endpoints_lhs_sample(n) -> numpy.ndarray LHS sampling within the interval plus the endpoints :param n: number of samples .. py:method:: plot(ax=None, **kwargs) .. py:method:: display() .. py:method:: is_degenerate() -> bool Check if the interval is degenerate (i.e., has zero width). .. py:method:: _compute_nominal_value() .. py:method:: ravel() Return a flattened (1D) interval object for multi-dimensional intervals .. rubric:: Example >>> A = np.random.rand(200, 200, 2) >>> i = pba.intervalise(A) >>> print(i.shape) >>> i2 = i.ravel() >>> print(i2.shape) .. py:property:: lo :type: Union[numpy.ndarray, float] .. py:property:: hi :type: Union[numpy.ndarray, float] .. py:property:: left .. py:property:: right .. py:property:: width .. py:property:: rad half width .. py:property:: mid .. py:property:: unsized .. py:property:: val seemingly equivalent to `self.to_numpy()` .. py:property:: scalar Check if the interval is wide sense scalar .. note:: wide sense: I(1,2) and I([1],[2]) are both scalars .. py:property:: is_scalar Check if the interval is a strict-sense scalar .. note:: strict sense: I(1,2) is a scalar, but I([1],[2]) is not .. py:property:: shape .. py:property:: ndim .. py:method:: __neg__() .. py:method:: __pos__() .. py:method:: __add__(other) .. py:method:: __radd__(left) .. py:method:: __sub__(other) .. py:method:: __rsub__(left) .. py:method:: __mul__(other) .. py:method:: __rmul__(left) .. py:method:: __truediv__(other) .. py:method:: __rtruediv__(left) .. py:method:: __pow__(other) .. py:method:: __lt__(other) .. py:method:: __rlt__(left) .. py:method:: __gt__(other) .. py:method:: __rgt__(left) .. py:method:: __le__(other) .. py:method:: __rle__(left) .. py:method:: __ge__(other) .. py:method:: __rge__(left) .. py:method:: __eq__(other) .. py:method:: __ne__(other) .. py:method:: __array_ufunc__(ufunc, method, *inputs, **kwargs) .. py:method:: abs() .. py:method:: sqrt() .. py:method:: exp() .. py:method:: log() .. py:method:: sin() .. py:method:: cos() .. py:method:: tan() .. py:method:: from_meanform(x, half_width) :classmethod: .. py:method:: save_json(filename: str, comment: str = None, save_dir: str | pathlib.Path = '.') -> None Save the interval object to a JSON5 file. :param filename: The name of the file (without extension) to save the interval object to. :type filename: str :param comment: A comment to include at the top of the file. :type comment: str, optional :param save_dir: Directory where the file should be saved. Defaults to current directory. :type save_dir: str | Path, optional .. note:: The file is saved with a `.json5` extension. .. rubric:: Example >>> a.save_json("interval_data", comment="This is interval data", save_dir="results/") .. py:class:: Staircase(left, right, steps=200, mean=None, var=None, p_values=None) Bases: :py:obj:`Pbox` distribution free p-box .. py:method:: _init_moments() Initialize mean/var interval estimates. strategy: 1) Try LP-based bounds. 2) If that fails, try ECDF-based bounds. 3) If that also fails, set to NaN intervals so the program continues. This function NEVER raises. .. py:method:: __repr__() .. py:method:: plot(title=None, ax=None, style='box', fill_color='lightgray', bound_colors=None, bound_styles=None, left_line_kwargs=None, right_line_kwargs=None, nuance='step', alpha=0.3, **kwargs) default plotting function :param style: 'box' or 'simple' :type style: str :param fill_color: color to fill the box (only for 'box' style) :type fill_color: str :param bound_colors: list of two colors for left and right bound lines :type bound_colors: list :param bound_styles: list of two linestyles for left and right bound lines :type bound_styles: list :param left_line_kwargs: additional kwargs for left bound line :type left_line_kwargs: dict :param right_line_kwargs: additional kwargs for right bound line :type right_line_kwargs: dict :param nuance: 'step' or 'curve' for bound line styles :type nuance: str :param alpha: transparency level for the box fill (only for 'box' style) :type alpha: float :param \*\*kwargs: additional keyword arguments for the plot .. note:: Two styles are supported: a 'box' with fill-in color and a 'simple' one without fill-in color. Color and linestyle of the bound lines can be customized via the `bound_styles`, `left_line_kwargs`, and `right_line_kwargs` parameters. The argument `nuance` controls whether the bound lines are plotted as step functions ('step') or smooth curves ('curve'). .. rubric:: Example >>> a = pba.normal([2, 6], [0.5, 1]) >>> fig, ax = plt.subplots() >>> a.plot(ax=ax, style='simple') # simple style without fill-in color >>> # box style with fill-in color and also customized bound colors >>> a.plot(ax=ax, style='box', ... fill_color='lightblue', ... bound_colors = ['lightblue', 'lightblue'], ... bound_styles=("--", ":"), ... alpha=0.5 ... ) >>> # customized left and right bound line styles >>> ax = pbox.plot( ... left_line_kwargs={"linestyle": "--", "linewidth": 2}, ... right_line_kwargs={"linestyle": ":", "linewidth": 2, "alpha": 0.8}, ) .. py:method:: plot_reverse_axis(title=None, ax=None, style='box', fill_color='lightgray', bound_colors=None, nuance='step', alpha=0.3, orientation='xy', invert_xaxis=True, **kwargs) A testing plotting function that can swap quantile and probability axes. :param style: 'box' or 'simple' :type style: str :param orientation: 'xy' keeps x on horizontal and Pr(X<=x) on vertical; 'yx' swaps them. :type orientation: str .. py:method:: plot_outside_legend(title=None, ax=None, style='box', fill_color='lightgray', bound_colors=None, nuance='step', alpha=0.3, **kwargs) a specific variant of `plot()` which is used for scipy proceeding only. :param style: 'box' or 'simple' :type style: str .. py:method:: display(*args, **kwargs) .. py:method:: plot_probability_bound(x: float, ax=None, linecolor='r', markercolor='r', **kwargs) plot the probability bound at a certain quantile x .. note:: - a vertical line .. py:method:: plot_quantile_bound(p: float, ax=None, **kwargs) plot the quantile bound at a certain probability level p .. note:: - a horizontal line .. py:method:: from_CDFbundle(a, b) :classmethod: pbox from two emipirical CDF bundle :param - a: CDF bundle of lower extreme F; :param - b: CDF bundle of upper extreme F; .. py:method:: __neg__() .. py:method:: __add__(other) .. py:method:: __radd__(other) .. py:method:: __sub__(other) .. py:method:: __rsub__(other) .. py:method:: __mul__(other) .. py:method:: __rmul__(other) .. py:method:: __truediv__(other) .. py:method:: __rtruediv__(other) .. py:method:: __pow__(other) .. py:method:: __rpow__(other: numbers.Number) Power operation with the base as `other` and self as the exponent .. py:method:: __array_ufunc__(ufunc, method, *inputs, **kwargs) .. py:method:: cdf(x: numpy.ndarray) get the bounds on the cdf w.r.t x value :param x: x values :type x: array-like .. py:method:: alpha_cut(alpha=0.5) test the lightweight `alpha_cut` method :param alpha: probability levels :type alpha: array-like .. py:method:: sample(n_sam) LHS sampling by default .. py:method:: precise_sample(n_a: int, theta: float = None, n_e: int = None) Generate precise samples from a p-box .. py:method:: discretise(n=None) -> pyuncertainnumber.Interval alpha-cut discretisation of the p-box without outward rounding :param n: number of steps to be used in the discretisation. :type n: int :returns: vector Interval .. py:method:: outer_discretisation(n=None) discretisation of a p-box to get intervals based on the scheme of outer approximation :param n: number of steps to be used in the discretisation :type n: int .. note:: `the_interval_list` will have length one less than that of default `p_values` (i.e. 100 and 99) :returns: the outer intervals in vec-Interval form .. py:method:: condensation(n) -> Self ourter condensation of the pbox to reduce the number of steps and get a sparser staircase pbox :param n: number of steps to be used in the discretisation :type n: int .. note:: Have not thought about a better name so we call it `condensation` for now. Candidate names include 'approximation'. It will ouput a p-box and keep steps as 200 for computational consistency. .. rubric:: Example >>> p.condensation(n=5) :returns: a staircase p-box that looks sparser but has the same number of steps .. py:method:: condense(n) -> pyuncertainnumber.pba.dss.DempsterShafer Another condensation function which has steps of n Compared to the above `condensation` method that ouputs a p-box and keeps steps as 200 for computational consistency. This one condenses in a more literal manner, as in having n steps in the resulting Dempster-Shafer structure. .. py:method:: truncate(a, b) Truncate the Pbox to the range [a, b]. example: >>> from pyuncertainnumber import pba >>> p = pba.normal([4, 9], 1) >>> tr = p.truncate(3, 8) >>> fig, ax = plt.subplots() >>> p.plot(ax=ax) >>> tr.plot(ax=ax, fill_color='r') >>> plt.show() .. py:method:: min(other, method='f') Returns a new Pbox object that represents the element-wise minimum of two Pboxes. :param - other: Another Pbox object or a numeric value. :param - method: Calculation method to determine the minimum. Can be one of 'f', 'p', 'o', 'i'. :returns: Pbox .. py:method:: max(other, method='f') .. py:method:: get_PI(alpha: numbers.Number = 0.95, style='narrowest') -> pyuncertainnumber.Interval Compute the predictive interval at the coverage level of `alpha` :param alpha: coverage level for the predictive interval, default is 0.95 :type alpha: Number :param style: 'narrowest' or 'widest', default is 'narrowest' :type style: str .. note:: by default, narrowest predictive interval is returned; when the narrowest does not exist, a warning will the generated and then the widest is returned instead. .. rubric:: Example >>> from pyuncertainnumber import pba >>> p = pba.normal([10, 15, 1]) >>> p.get_PI(alpha=0.95, style='narrowest') .. py:method:: straddles(N, endpoints=True) -> bool Check whether the p-box straddles a number N :param N: the Number to check :type N: float :param endpoints: Whether to include the endpoints within the check :type endpoints: Boolean :returns: True If :math:`\mathrm{left} \leq N \leq \mathrm{right}` (Assuming `endpoints=True`) False Otherwise .. note:: This could affect the results of Frechet bounds .. py:method:: straddles_zero() -> bool Checks specifically whether :math:`0` is within the p-box .. py:method:: is_zero() .. py:method:: is_nagative() .. py:method:: env(other) computes the envelope of two Pboxes. :param other: :type other: Pbox :returns: - Pbox .. py:method:: imp(other) Returns the imposition of self with other pbox .. note:: - binary imposition between two pboxes only .. py:method:: _unary_template(f) .. py:method:: exp() exponential function: e^x .. py:method:: sqrt() square root function: √x .. py:method:: reciprocal() Calculate the reciprocal of the pbox .. note:: the pbox should not straddle zero, otherwise a warning is raised .. py:method:: log() natural logarithm of the pbox .. note:: - the pbox must be positive .. py:method:: sin() .. py:method:: cos() .. py:method:: tanh() .. py:method:: add(other, dependency='f') .. py:method:: sub(other, dependency='f') .. py:method:: mul(other, dependency='f') Multiplication of uncertain numbers with the defined dependency dependency .. py:method:: div(other, dependency='f') .. py:method:: pow(other, dependency='f') Exponentiation of uncertain numbers with the defined dependency dependency This suggests that the exponent (i.e. `other`) can also be an uncertain number. .. py:method:: balchprod(other) Frechet convolution of two pboxes when any of them straddles zero .. py:function:: convert(un) Convert any input un into a Pbox object .. note:: - theorically 'un' can be {Interval, DempsterShafer, Distribution, float, int} .. py:class:: Params .. py:attribute:: steps :value: 200 .. py:attribute:: many :value: 2000 .. py:attribute:: p_lboundary :value: 0.001 .. py:attribute:: p_hboundary :value: 0.999 .. py:attribute:: p_values .. py:attribute:: scott_hedged_interpretation .. py:attribute:: user_hedged_interpretation .. py:function:: envelope(*l_uns: pyuncertainnumber.pba.pbox_abc.Pbox | pyuncertainnumber.pba.dss.DempsterShafer | numbers.Number | pyuncertainnumber.pba.intervals.Interval | pyuncertainnumber.pba.distributions.Distribution | pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber, output_type='pbox') -> pyuncertainnumber.pba.pbox_abc.Staircase | pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber calculates the envelope of constructs only :param l_uns: the components, constructs and uncertain numbers, on which the envelope operation applied on. :type l_uns: list :param output_type: {'pbox' or 'uncertain_number' or 'un'} - default is pbox :type output_type: str :returns: the envelope of the given arguments, either a p-box or an interval. .. rubric:: Example >>> from pyuncertainnumber import envelope >>> a = pba.normal(3, 1) >>> b = pba.uniform(5, 8) >>> c = pba.normal(13, 2) >>> t = envelope(a, b, c, output_type='pbox') # or output_type='uncertain_number' .. py:function:: imposition(*l_uns: pyuncertainnumber.pba.pbox_abc.Pbox | pyuncertainnumber.pba.dss.DempsterShafer | numbers.Number | pyuncertainnumber.pba.intervals.Interval | pyuncertainnumber.pba.distributions.Distribution | pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber, output_type='pbox') -> pyuncertainnumber.pba.pbox_abc.Staircase | pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber Returns the imposition/intersection of the list of p-boxes :param l_uns: a list of constructs or UN objects to be mixed :type l_uns: list :param output_type: {'pbox' or 'uncertain_number' or 'un'} - default is pbox :type output_type: str :returns: - Pbox or UncertainNumber .. rubric:: Example >>> import pyuncertainnumber as pun >>> from pyuncertainnumber import pba >>> a = pba.normal([3, 7], 1) >>> b = pba.uniform([3,5], [6,9]) >>> i = pun.imposition(a, b) .. py:function:: stochastic_mixture(*l_uns: pyuncertainnumber.pba.pbox_abc.Pbox | pyuncertainnumber.pba.dss.DempsterShafer | numbers.Number | pyuncertainnumber.pba.intervals.Interval | pyuncertainnumber.pba.distributions.Distribution | pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber, weights=None) it could work for either Pbox, distribution, DS structure or Intervals :param - l_uns: list of constructs or uncertain numbers :type - l_uns: list :param - weights: list of weights :type - weights: list .. rubric:: Example >>> import pyuncertainnumber as pun >>> p = pun.stochastic_mixture([[1,3], [2,4]]) .. py:function:: stacking(vec_interval: pyuncertainnumber.pba.intervals.Interval | list[pyuncertainnumber.pba.intervals.Interval], *, weights=None, display=False, ax=None, return_type='pbox', **kwargs) -> pyuncertainnumber.pba.pbox_abc.Pbox stochastic mixture operation of Intervals with probability masses :param - vec_interval: list of Intervals or a vectorised Interval :type - vec_interval: list :param - weights: list of weights :type - weights: list :param - display: boolean for plotting :type - display: Boolean :param - return_type: {'pbox' or 'ds' or 'bounds'} :type - return_type: str :returns: by default a p-box but can return the left and right bound F in `eCDF_bundlebounds`. .. note:: - For intervals specifically. - it takes a list of intervals or a single vectorised interval, which is a different signature compared to the other aggregation functions. - together the interval and masses, it can be deemed that all the inputs required is jointly a DS structure .. rubric:: Example >>> stacking([[1,3], [2,4]], weights=[0.5, 0.5], display=True) .. py:function:: mixture_pbox(*l_pboxes, weights=None, display=False) -> pyuncertainnumber.pba.pbox_abc.Pbox .. py:function:: mixture_ds(*l_ds, display=False) -> pyuncertainnumber.pba.dss.DempsterShafer mixture operation for DS structure .. py:function:: env_samples(data: numpy.typing.ArrayLike, output_type='pbox', ecdf_choice='canonical') nonparametric envelope function directly from data samples :param data: Each row represents a distribution, on which the envelope operation applied. :type data: ArrayLike :param output_type: {'pbox' or 'cdf'} default is pbox cdf is the CDF bundle :type output_type: str :param ecdf_choice: {'canonical' or 'staircase'} :type ecdf_choice: str .. note:: envelope on a set of empirical CDFs .. py:function:: env_ecdf_sep(*ecdfs, output_type='pbox', ecdf_choice='canonical') nonparametric envelope function for separate empirical CDFs .. py:function:: env_am(n_pars: numpy.typing.ArrayLike) -> numpy.ndarray bespoke function used for am metric case :param n_pars: (n_sam, 2) of tuple (mu, sigma) which may be a tensor :type n_pars: ArrayLike .. py:function:: env_pbox_am(n_mean: numpy.typing.ArrayLike, n_std: numpy.typing.ArrayLike) -> numpy.ndarray bespoke function used for am metric case :param n_mean: (n_sam,) of mean values which may be a tensor :type n_mean: ArrayLike :param n_std: (n_sam,) of standard deviation values which may be a tensor :type n_std: ArrayLike .. py:function:: b2b(vars: pyuncertainnumber.pba.intervals.number.Interval | list[pyuncertainnumber.pba.intervals.number.Interval], func: callable, interval_strategy: str = None, subinterval_style: str = None, n_sub: int = None, n_sam: int = 200, **kwargs) -> pyuncertainnumber.pba.intervals.number.Interval General implementation of interval propagation through a function: .. math:: Y = g(I_{x1}, I_{x2}, ..., I_{xn}) where :math:`I_{x1}, I_{x2}, ..., I_{xn}` are intervals. In a general case, the function :math:`g` is not necessarily monotonic and :math:`g` may be a black-box model. Optimisation to the rescue and two of them particularly: Genetic Algorithm and Bayesian Optimisation. :param vars: a vector Interval or a list or tuple of scalar Intervals, or an EpistemicDomain object, or a scalar Interval; :type vars: Interval | list[Interval] :param func: performance or response function or a black-box model as in subprocess. Expect 2D inputs therefore `func` shall have the matrix signature. See Notes for additional details. :type func: callable :param interval_strategy: the interval_strategy used for interval propagation. The choice shall be compatible with the response function signature. Seethe notes below for additional details. - 'endpoints': only the endpoints - 'ga': genetic algorithm - 'bo': bayesian optimisation - 'direct': directly apply function to the input intervals (the default) - 'subinterval': apply function to subintervals - 'cauchy_deviate': use the Cauchy Deviate Method for interval propagation :type interval_strategy: str :param subinterval_style: the subinterval_style only used for subinterval propagation, including {''direct'', ''endpoints''}. :type subinterval_style: str :param n_sub: number of subintervals, only used for subinterval propagation. :type n_sub: int :param n_sam: number of samples, only used for Cauchy deviate method :type n_sam: int :param \*\*kwargs: additional keyword arguments to be passed to the function, which provides extra control for the algorithm used. For example, for GA, one can pass in 'algorithm_param' for BO, one can pass in 'acquisition_function', 'num_iterations' etc. Typically, one would try the optimisation harder (e.g. more iterations) for a more accurate result. .. tip:: This serves as a top-level for generic interval propagation . .. caution:: ``interval_strategy`` suggests the method of interval propagation (e.g. 'direct' or 'endpoints', or 'subinterval', or 'ga', or 'bo'), whhile ``subinterval_style`` is only used for 'subinterval' propagation. This is to say that what strategy (whether 'direct' or 'endpoints') will be further chosen for the sub-intervals. For scalar function propagation, ``vars`` shuld just be a scalar Interval object rather than a list. .. danger:: There are some subtleties about the calling signature of the propagating function. For ``endpoints`` strategy/subinterval_style, the function `func` should have a vectorised signature as it is expecting a 2D numpy array, whereas for the ``direct`` strategy/subinterval_style, it is expecting to take individual scalar inputs. It is recommended to write a function which implements both signature, as seen in the example below. :returns: the low and upper bound of the response :rtype: Interval .. rubric:: Example >>> from pyuncertainnumber import b2b >>> import numpy as np >>> import pyuncertainnumber as pba >>> # Define a universal function that handles a performance function with both `vectorised` and `iterable` signatures >>> def bar_universal(x): ... if isinstance(x, np.ndarray): # foo_vectorised signature ... if x.ndim == 1: ... x = x[None, :] ... return x[:, 0] ** 3 + x[:, 1] + 5 ... else: ... return x[0] ** 3 + x[1] + 5 # foo_iterable signature >>> # Define input intervals >>> a = pba.I(3., 5.) >>> b = pba.I(6., 26.) >>> # using the {'endpoints', "direct", ga", "bo"} strategy >>> b2b(vars=[a, b], ... func=bar_universal, ... interval_strategy='endpoints') # replace with {"direct", ga", "bo"} >>> # using the 'subinterval' strategy >>> b2b(vars=[a, b], ... func=bar_universal, ... interval_strategy='subinterval', ... subinterval_style='endpoints', ... n_sub=2) >>> # using the 'cauchy_deviate' strategy >>> b2b(vars=[a, b], ... func=bar_universal, ... interval_strategy='cauchy_deviate', ... n_sam=1000) >>> # in comparison, one can compare with the result of interval arithmetic >>> def bar_individual(x1, x2): ... return x1 ** 3 + x2 + 5 # individual signature >>> bar_individual(a, b) [38.0, 156.0] .. py:class:: Propagation(vars: list[pyuncertainnumber.characterisation.uncertainNumber.UncertainNumber], func: callable, method: str, dependency: str | pyuncertainnumber.pba.dependency.Dependency = None, interval_strategy: str = None) High-level integrated class for the propagation of uncertain numbers :param vars: a list of uncertain numbers objects :type vars: UncertainNumber :param func: the response or performance function applied to the uncertain numbers :type func: Callable :param method: a string indicating the method to be used for propagation (e.g. "monte_carlo", "endpoint", etc.) which may depend on the constructs of the uncertain numbers. See notes about function signature. :type method: str :param dependency: a Dependency object(i.e. a copula function) to model the dependency structure among input variables. Strings such as "independence" accepted for independence. :type dependency: string or Dependency :param interval_strategy: a strategy for interval propagation, including {'direct', 'subinterval', 'endpoints'} which will affect the function signature of the response function. See notes about function signature. :type interval_strategy: str .. caution:: This class supports with high-level computation with `UncertainNumber` objects. .. note:: Discussion of the methods and strategies. When choosing ``interval_strategy``, "direct" requires function signature to take a list of inputs, whereas "subinterval" and "endpoints" require the function to take a vectorised signature. .. warning:: The computation cost increases exponentially with the number of input variables and the number of slices. Be cautious with the choice of number of slices ``n_slices`` given the number of input variables ``vars`` of the response function. .. rubric:: Example >>> import pyuncertainnumber as pun >>> # construction of uncertain number objects >>> a = pun.I(2, 3) >>> b = pun.normal(4, 1) >>> c = pun.uniform([4,5], [9,10]) >>> # vectorised function signature with matrix input (2D np.ndarray) >>> def foo_vec(x): return x[:, 0] ** 3 + x[:, 1] + x[:, 2] >>> # high-level propagation API >>> p = Propagation(vars=[a,b,c], >>> func=foo, >>> method='slicing', >>> interval_strategy='subinterval' >>> ) >>> # heavy-lifting of propagation >>> t = p.run(n_sam=20, n_sub=2, style='endpoints') .. py:attribute:: _vars .. py:attribute:: _func .. py:attribute:: method .. py:attribute:: dependency :value: None .. py:attribute:: interval_strategy :value: None .. py:method:: _post_init_check() Some checks after initialisation .. py:method:: assign_method() Assign the propagation method based on the essence of constructs .. py:property:: constructs return the underlying constructs .. py:method:: run(**kwargs) Doing the propagation and return UN :returns: the result of the propagation as an uncertain number object :rtype: UncertainNumber .. py:function:: taylor_expansion_method(func, mean, *, var=None, cov=None) -> tuple Performs uncertainty propagation using the Taylor expansion method. :param func: function to propagate uncertainty through. Expecting a iterable-signature function. :param mean: mean of the input random variable (scalar or vector) :type mean: Jax array :param var: variance of the input random variable (scalar only) :type var: Jax array :param cov: covariance matrix of the input random vector (vector only) :type cov: Jax array :returns: mean of the output random variable through the function var_f: variance of the output random variable through the function :rtype: mu_f .. note:: Currently it only supports scalar-output functions. Also, for multivariate function, the calling signature is assumed to be func(x) where x is a 1D array, i.e. func: R^n -> R, the vec style. For best compatibility to work with derivatives, the `func` is better written in jax.numpy. .. rubric:: Example >>> import jax.numpy as jnp >>> from pyuncertainnumber import taylor_expansion_method >>> MEAN= jnp.array([3., 2.5]) >>> COV = jnp.array([[4, 0.3], [0.3, 0.25]]) >>> def bar(x): return x[0]**2 + x[1] + 3 >>> mu_, var_ = taylor_expansion_method(func=bar, mean=MEAN, cov=COV) .. py:function:: interval_monte_carlo(vars: list[pyuncertainnumber.pba.intervals.Interval | pyuncertainnumber.pba.distributions.Distribution | pyuncertainnumber.pba.pbox_abc.Pbox], func: callable, interval_strategy, n_sam: int, dependency: pyuncertainnumber.pba.dependency.Dependency = None, random_state=None, side_effects=False, **kwargs) -> pyuncertainnumber.pba.pbox_abc.Pbox Interval Monte Carlo for propagation of pbox :param vars: a list of constructs :type vars: list :param func: response function. By default, iterable signature is expected. :type func: callable :param interval_strategy: strategy for interval discretisation, options include {'direct', 'endpoints', 'subinterval'} :type interval_strategy: str :param n_sam: number of samples for each input :type n_sam: int :param dependency: dependency structure (e.g. vine copula or archimedean copula :param random_state: random seed for reproducibility :param side_effects: whether return auxiliary outputs (side effects) during propagation If true, the alpha-cut samples in the uniform space will be returned as well. otherwise, the default is False and only the p-box is returned. :type side_effects: bool .. note:: When choosing ``interval_strategy``, "direct" requires function signature to take a list of inputs, whereas "subinterval" and "endpoints" require the function to have a vectorised signature. :returns: Pbox .. rubric:: Example >>> from pyuncertainnumber import pba >>> def foo(x): return x[0] ** 3 + x[1] + x[2] >>> a = pba.normal([2, 3], [1]) >>> b = pba.normal([10, 14], [1]) >>> c = pba.normal([4, 5], [1]) >>> corre_matrix = np.array([[1, 0.5, 0.3], [0.5, 1, 0.4], [0.3, 0.4, 1]]) >>> de = pba.Dependency(family='gaussian', corr=corre_matrix) >>> mix = interval_monte_carlo(vars=[a,b,c], >>> ... func=foo, >>> ... n_sam=20, >>> ... dependency=de, >>> ... interval_strategy='direct') .. py:function:: slicing(vars: list[pyuncertainnumber.pba.distributions.Distribution | pyuncertainnumber.pba.intervals.Interval | pyuncertainnumber.pba.pbox_abc.Pbox], func, interval_strategy, n_slices, outer_discretisation=True, dependency=None, **kwargs) -> pyuncertainnumber.pba.pbox_abc.Pbox classic slicing algoritm for rigorous propagation of pbox :param vars: list of constructs :type vars: list :param func: response function :type func: callable :param interval_strategy: strategy for interval discretisation, options include {'direct', 'endpoints', 'subinterval'} :type interval_strategy: str :param n_slices: number of slices for each input :param outer_discretisation: whether to use outer discretisation for pbox. By default is True for rigorous propagation; however, alpha-cut style interval are also supported. :type outer_discretisation: bool :param dependency: dependency structure (e.g. vine copula or archimedean copula). .. tip:: Merely independence assumption is supported by now. Other dependency structures are at beta developement now. .. note:: When choosing ``interval_strategy``, "direct" requires function signature to take a list of inputs, whereas "subinterval" and "endpoints" require the function to have a vectorised signature. :returns: Pbox .. rubric:: Example >>> from pyuncertainnumber import pba >>> def foo(x): return x[0] ** 3 + x[1] + x[2] >>> a = pba.normal([2, 3], [1]) >>> b = pba.normal([10, 14], [1]) >>> c = pba.normal([4, 5], [1]) >>> mix = slicing(vars=[a,b,c], >>> ... func=foo, >>> ... n_slices=20, >>> ... interval_strategy='direct') .. py:function:: double_monte_carlo(joint_distribution: pyuncertainnumber.pba.distributions.Distribution | pyuncertainnumber.pba.distributions.JointDistribution, epistemic_vars: list[pyuncertainnumber.pba.intervals.Interval], n_a: int, n_e: int, func: callable, side_effects=False, parallel=False) -> tuple[pyuncertainnumber.pba.pbox_abc.Pbox, list, numpy.ndarray] Double-loop Monte Carlo or nested Monte Carlo for mixed uncertainty propagation :param joint_distribution: an aleatoric sampler based on joint distribution of aleatory variables (or marginal one in 1d case). A sampler is basically anything (univariate or multivariate) that has the `sample` interface whereby it can sample a given number of samples. :type joint_distribution: Distribution or JointDistribution :param epistemic_vars: a list epistemic variables in the form of Interval :type epistemic_vars: list :param n_a: number of aleatory samples :type n_a: int :param n_e: number of epistemic samples :type n_e: int :param parallel: parallel processing. Only use it for heavy computation (black-box) due to overhead :type parallel: Boolean .. hint:: consider a function mapping f(X) -> y - :math:`X` in :math:`R^5` with `n_a=1000`will suggest f(1000, 5) - resulting sample array: with `n_e=2`, the response :math:`y` : (n_ep+2, n_a) e.g. (4, 1000) side_effects (bool): whether return auxiliary outputs (side effects) during propagation If true, the alpha-cut samples in the uniform space will be returned as well. otherwise, the default is False and only the p-box is returned. :returns: - a p-box enveloping all the CDFs from the epistemic samples - a list of ECDFs for each epistemic sample - numpy array of shape ``(n_e+2, n_a)`` as a collection of CDFs for the response - the epistemic samples used Otherwise, just the p-box. :rtype: If `side_effects` is True, a tuple containing the following items .. note:: The result array can be interpreted as a collection of CDFs for the response function evaluated at the aleatory samples for each epistemic sample. One can further envelope these CDFs into a ``Pbox`` or ``UncertainNumber`` object. .. rubric:: Example >>> from pyuncertainnumber import pba >>> # vectorised function signature with matrix input (2D np.ndarray) >>> def foo_vec(x): ... return x[:, 0] ** 3 + x[:, 1] + x[:, 2] + x[:, 3] >>> dist_a = pba.Distribution('gaussian', (5, 1)) >>> dist_b = pba.Distribution('uniform', (2, 3)) >>> c = pba.Dependency('gaussian', params=0.8) >>> joint_dist = pba.JointDistribution(copula=c, marginals=[dist_a, dist_b]) >>> xe1 = pba.I(1, 2) >>> xe2 = pba.I(3, 4) >>> t = double_monte_carlo( ... joint_distribution=joint_dist, ... epistemic_vars=[xe1, xe2], ... n_a=20, ... n_e=3, ... func=foo_vec ... ) .. py:function:: area_metric(a: numbers.Number | pyuncertainnumber.Pbox | numpy.typing.ArrayLike, b: numbers.Number | pyuncertainnumber.Pbox | numpy.typing.ArrayLike) -> float Compute the area metric between two objects. .. note:: top-level function to compute area metric between any two objects .. py:function:: inspect_un(x: any) Inspect the any type of uncertain number x.