pyuncertainnumber.propagation.b2b ================================= .. py:module:: pyuncertainnumber.propagation.b2b Functions --------- .. autoapisummary:: pyuncertainnumber.propagation.b2b.b2b pyuncertainnumber.propagation.b2b.endpoints pyuncertainnumber.propagation.b2b.subinterval_method pyuncertainnumber.propagation.b2b.vec_cartesian_product pyuncertainnumber.propagation.b2b.i_cartesian_product Module Contents --------------- .. 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:function:: endpoints(vec_itvl: pyuncertainnumber.pba.intervals.number.Interval, func) -> pyuncertainnumber.pba.intervals.number.Interval Implementation of endpoints method, a.k.a vertex method. :param vec_itvl: a vector type Interval object :type vec_itvl: Interval :param func: the function to be evaluated. See notes about function signature. :type func: callable .. note:: The function `func` is expected to accept a 2D numpy array of shape :math:`(2^d, d)` where `d` is the dimension of the vector interval. Therefore, the function should have a vectorised signature, as opposted to taking individual scalar inputs. .. rubric:: Example >>> from pyuncertainnumber import pba >>> v = pba.I([1, 2], [3, 4]) # a vector interval with two dimensions >>> def bar(x): return x[:, 0] ** 3 + x[:, 1] + 5 >>> endpoints(v, bar) Interval(8.0, 36.0) .. py:function:: subinterval_method(vec_itvl: pyuncertainnumber.pba.intervals.number.Interval, func, subinterval_style=None, n_sub=None, parallel=False) -> pyuncertainnumber.pba.intervals.number.Interval Implmentation of subinterval method which splits subintervals and reconstitutes later. :param vec_itvl: a vector type Interval object :type vec_itvl: Interval :param func: the function to be evaluated. See notes about function signature. :type func: callable :param n_sub: number of subintervals :type n_sub: int :param subinterval_style: the subinterval_style used for interval propagation which shall be compatible with the response function signature. - 'direct': direct apply function - 'endpoints': only the endpoints are propagated :type subinterval_style: str .. danger:: There are some subtleties about function signature. For ``endpoints`` subinterval_style, the function `func` should have a vectorised signature as it is expecting a 2D numpy array, whereas for the `direct` subinterval_style, it is expecting to take individual scalar inputs .. rubric:: Example >>> from pyuncertainnumber import pba >>> v = pba.I([1, 2], [3, 4]) >>> def bar(x): return x[0] ** 3 + x[1] + 5 >>> b2b.subinterval_method(vec_itvl=v, func=bar, subinterval_style='direct', n_sub=2) >>> def bar_vec(x): return x[:, 0] ** 3 + x[:, 1] + 5 >>> b2b.subinterval_method(vec_itvl=v, func=bar_vec, subinterval_style='endpoints', n_sub=2) .. py:function:: vec_cartesian_product(*arrays) a vectorised version of the cartesian product :param arrays: a couple of 1D np.ndarray objects .. py:function:: i_cartesian_product(a, b) a vectorisation of the interval cartesian product .. todo:: extend to multiple input arguments