# This file was automatically generated by SWIG (http://www.swig.org).
# Version 4.0.2
#
# Do not make changes to this file unless you know what you are doing--modify
# the SWIG interface file instead.

"""otmorris module"""

from sys import version_info as _swig_python_version_info
if _swig_python_version_info < (2, 7, 0):
    raise RuntimeError("Python 2.7 or later required")

# Import the low-level C/C++ module
if __package__ or "." in __name__:
    from . import _otmorris
else:
    import _otmorris

try:
    import builtins as __builtin__
except ImportError:
    import __builtin__

def _swig_repr(self):
    try:
        strthis = "proxy of " + self.this.__repr__()
    except __builtin__.Exception:
        strthis = ""
    return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)


def _swig_setattr_nondynamic_instance_variable(set):
    def set_instance_attr(self, name, value):
        if name == "thisown":
            self.this.own(value)
        elif name == "this":
            set(self, name, value)
        elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
            set(self, name, value)
        else:
            raise AttributeError("You cannot add instance attributes to %s" % self)
    return set_instance_attr


def _swig_setattr_nondynamic_class_variable(set):
    def set_class_attr(cls, name, value):
        if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
            set(cls, name, value)
        else:
            raise AttributeError("You cannot add class attributes to %s" % cls)
    return set_class_attr


def _swig_add_metaclass(metaclass):
    """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
    def wrapper(cls):
        return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
    return wrapper


class _SwigNonDynamicMeta(type):
    """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
    __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)


import openturns.base
import openturns.common
import openturns.typ
import openturns.statistics
import openturns.graph
import openturns.func
import openturns.geom
import openturns.diff
import openturns.optim
import openturns.experiment
import openturns.solver
import openturns.algo
import openturns.uncertainty
import openturns.model_copula
import openturns.randomvector
import openturns.dist_bundle1
import openturns.dist_bundle2
import openturns.weightedexperiment
import openturns.classification
import openturns.orthogonalbasis
import openturns.metamodel
import openturns.transformation
import openturns.analytical
import openturns.simulation
import openturns.stattests
import openturns.model_process
import openturns.dist_bundle3
class MorrisExperimentImplementationdInterfaceObject(openturns.common.InterfaceObject):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        _otmorris.MorrisExperimentImplementationdInterfaceObject_swiginit(self, _otmorris.new_MorrisExperimentImplementationdInterfaceObject(*args))

    def getImplementation(self):
        r"""
        Accessor to the underlying implementation.

        Returns
        -------
        impl : Implementation
            The implementation class.
        """
        return _otmorris.MorrisExperimentImplementationdInterfaceObject_getImplementation(self)

    def setName(self, name):
        r"""
        Accessor to the object's name.

        Parameters
        ----------
        name : str
            The name of the object.
        """
        return _otmorris.MorrisExperimentImplementationdInterfaceObject_setName(self, name)

    def getName(self):
        r"""
        Accessor to the object's name.

        Returns
        -------
        name : str
            The name of the object.
        """
        return _otmorris.MorrisExperimentImplementationdInterfaceObject_getName(self)

    def __eq__(self, other):
        return _otmorris.MorrisExperimentImplementationdInterfaceObject___eq__(self, other)

    def __ne__(self, other):
        return _otmorris.MorrisExperimentImplementationdInterfaceObject___ne__(self, other)
    __swig_destroy__ = _otmorris.delete_MorrisExperimentImplementationdInterfaceObject

# Register MorrisExperimentImplementationdInterfaceObject in _otmorris:
_otmorris.MorrisExperimentImplementationdInterfaceObject_swigregister(MorrisExperimentImplementationdInterfaceObject)

class MorrisExperiment(openturns.weightedexperiment.WeightedExperimentImplementation):
    r"""
    Base class for the Morris method experiments.

    See also
    --------
    MorrisExperimentGrid, MorrisExperimentLHS
    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def getClassName(self):
        r"""
        Accessor to the object's name.

        Returns
        -------
        class_name : str
            The object class name (`object.__class__.__name__`).
        """
        return _otmorris.MorrisExperiment_getClassName(self)

    def getBounds(self):
        r"""
        Get the bounds of the domain.

        Returns
        -------
        bounds : :py:class:`openturns.Interval`
            Bounds of the domain, default is :math:`[0,1]^d`

        """
        return _otmorris.MorrisExperiment_getBounds(self)

    def generate(self):
        r"""
        Generate points according to the type of the experiment.

        Returns
        -------
        sample : :py:class:`openturns.Sample`
            Points that constitute the design of experiment, of size :math:`N \times (p+1)`

        """
        return _otmorris.MorrisExperiment_generate(self)

    def __repr__(self):
        return _otmorris.MorrisExperiment___repr__(self)

    def __init__(self, *args):
        _otmorris.MorrisExperiment_swiginit(self, _otmorris.new_MorrisExperiment(*args))
    __swig_destroy__ = _otmorris.delete_MorrisExperiment

# Register MorrisExperiment in _otmorris:
_otmorris.MorrisExperiment_swigregister(MorrisExperiment)

class MorrisExperimentGrid(MorrisExperiment):
    r"""
    MorrisExperimentGrid builds experiments for the Morris method starting from full p-levels grid experiments.

    Available constructors:

        MorrisExperimentGrid(levels, N)

        MorrisExperimentGrid(levels, interval, N)

    Parameters
    ----------
    levels : :py:class:`openturns.Indices`
        Number of levels for a regular grid
    N : int
        Number of trajectories
    interval : :py:class:`openturns.Interval`
        Bounds of the domain

    Notes
    -----
    With first constructor, we consider that initial experiment is a regular grid defined in :math:`[0,1]^d`.
    With second constructor, we consider that initial distribution model is uniform with bounds given by the interval argument. Also, the initial experiment is of type regular.

    Examples
    --------
    >>> import openturns as ot
    >>> import otmorris
    >>> # Number of trajectories
    >>> r = 10
    >>> # Define a k-grid level (so delta = 1/(k-1))
    >>> k = 5
    >>> dim = 3
    >>> experiment = otmorris.MorrisExperimentGrid([k] * dim, r)
    >>> X = experiment.generate()

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def getClassName(self):
        r"""
        Accessor to the object's name.

        Returns
        -------
        class_name : str
            The object class name (`object.__class__.__name__`).
        """
        return _otmorris.MorrisExperimentGrid_getClassName(self)

    def generate(self):
        r"""
        Generate points according to the type of the experiment.

        Returns
        -------
        sample : :py:class:`openturns.Sample`
            Points that constitute the design of experiment, of size :math:`N \times (p+1)`

        """
        return _otmorris.MorrisExperimentGrid_generate(self)

    def __repr__(self):
        return _otmorris.MorrisExperimentGrid___repr__(self)

    def getJumpStep(self):
        r"""
        Get the jump step,  specifying the number of levels for each factor that are increased/decreased for computing the
        elementary effects. If not given, it is set to 1 for each factor.

        Returns
        -------
        humpStep : :py:class:`openturns.Indices`
            Number of levels for each factot that are increased/decreased for computating the EE.

        """
        return _otmorris.MorrisExperimentGrid_getJumpStep(self)

    def setJumpStep(self, jumpStep):
        r"""
        Set the jump step,  specifying the number of levels for each factor that are increased/decreased for computing the
        elementary effects. If not given, it is set to 1 for each factor.


        Parameters
        ----------
        humpStep : :py:class:`openturns.Indices`
            Number of levels for each factot that are increased/decreased for computating the EE.

        Notes
        -----
        The final jump step contains only integers, so the parameter argument is converted into a list of integer thanks to the
        floor operator.

        """
        return _otmorris.MorrisExperimentGrid_setJumpStep(self, jumpStep)

    def __init__(self, *args):
        _otmorris.MorrisExperimentGrid_swiginit(self, _otmorris.new_MorrisExperimentGrid(*args))
    __swig_destroy__ = _otmorris.delete_MorrisExperimentGrid

# Register MorrisExperimentGrid in _otmorris:
_otmorris.MorrisExperimentGrid_swigregister(MorrisExperimentGrid)

class MorrisExperimentLHSdInterfaceObject(openturns.common.InterfaceObject):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        _otmorris.MorrisExperimentLHSdInterfaceObject_swiginit(self, _otmorris.new_MorrisExperimentLHSdInterfaceObject(*args))

    def getImplementation(self):
        r"""
        Accessor to the underlying implementation.

        Returns
        -------
        impl : Implementation
            The implementation class.
        """
        return _otmorris.MorrisExperimentLHSdInterfaceObject_getImplementation(self)

    def setName(self, name):
        r"""
        Accessor to the object's name.

        Parameters
        ----------
        name : str
            The name of the object.
        """
        return _otmorris.MorrisExperimentLHSdInterfaceObject_setName(self, name)

    def getName(self):
        r"""
        Accessor to the object's name.

        Returns
        -------
        name : str
            The name of the object.
        """
        return _otmorris.MorrisExperimentLHSdInterfaceObject_getName(self)

    def __eq__(self, other):
        return _otmorris.MorrisExperimentLHSdInterfaceObject___eq__(self, other)

    def __ne__(self, other):
        return _otmorris.MorrisExperimentLHSdInterfaceObject___ne__(self, other)
    __swig_destroy__ = _otmorris.delete_MorrisExperimentLHSdInterfaceObject

# Register MorrisExperimentLHSdInterfaceObject in _otmorris:
_otmorris.MorrisExperimentLHSdInterfaceObject_swigregister(MorrisExperimentLHSdInterfaceObject)

class MorrisExperimentLHS(MorrisExperiment):
    r"""
    MorrisExperimentLHS builds experiments for the Morris method using a centered LHS design as input starting.

    Available constructors:

        MorrisExperimentLHS(lhsDesign, N)

        MorrisExperimentLHS(lhsDesign, interval, N)

    Parameters
    ----------
    lhsDesign : :py:class:`openturns.Sample`
        Initial design
    interval : :py:class:`openturns.Interval`
        Bounds of the domain
    N : int
        Number of trajectories

    Notes
    -----
    With the first constructor, we fix the initial design which could be an LHS, an optimal LHS defined using uniform marginals.
    With the second constructor LHS design and bounds are required.
    The lhs sample must be centered, ie from :py:class:`openturns.LHSExperiment` with randomShift=False.

    The method consists in generating trajectories (paths) by randomly selecting their initial points from the lhs design.
    If number of trajectories is lesser than the lhsDesign's size, we enforce the selection of the starting point using
    :py:class:`openturns.KPermutationsDistribution` which ensure full different trajectories.

    Examples
    --------
    >>> import openturns as ot
    >>> import otmorris
    >>> ot.RandomGenerator.SetSeed(1)
    >>> r = 5
    >>> # Define experiments in [0,1]^2
    >>> size = 20
    >>> # Generate an LHS design
    >>> dist = ot.ComposedDistribution([ot.Uniform(0, 1)] * 2)
    >>> # should be centered so randomShift=False
    >>> lhs_experiment = ot.LHSExperiment(dist, size, True, False)
    >>> lhsDesign = lhs_experiment.generate()
    >>> experiment = otmorris.MorrisExperimentLHS(lhsDesign, r)
    >>> X = experiment.generate()

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def getClassName(self):
        r"""
        Accessor to the object's name.

        Returns
        -------
        class_name : str
            The object class name (`object.__class__.__name__`).
        """
        return _otmorris.MorrisExperimentLHS_getClassName(self)

    def generate(self):
        r"""
        Generate points according to the type of the experiment.

        Returns
        -------
        sample : :py:class:`openturns.Sample`
            Points that constitute the design of experiment, of size :math:`N \times (p+1)`

        """
        return _otmorris.MorrisExperimentLHS_generate(self)

    def __repr__(self):
        return _otmorris.MorrisExperimentLHS___repr__(self)

    def __init__(self, *args):
        _otmorris.MorrisExperimentLHS_swiginit(self, _otmorris.new_MorrisExperimentLHS(*args))
    __swig_destroy__ = _otmorris.delete_MorrisExperimentLHS

# Register MorrisExperimentLHS in _otmorris:
_otmorris.MorrisExperimentLHS_swigregister(MorrisExperimentLHS)

class Morris(openturns.common.PersistentObject):
    r"""
    Morris method.

    Available constructors:

        Morris(*inputSample, outputSample, interval*)

        Morris(*experiment, model*)

    Parameters
    ----------
    inputSample : :py:class:`openturns.Sample`
        Experiment generated thanks to the `generate` method of the :class:`~otmorris.MorrisExperiment`
    outputSample : :py:class:`openturns.Sample`
        Response model applied on `inputSample`
    interval : :py:class:`openturns.Interval`
        Bounds of the experiment inputs.
    experiment : :py:class:`otmorris.MorrisExperiment`
        Morris experiment
    model : :py:class:`openturns.Function`
        Response model to be applied on input data

    Notes
    -----
    We note :math:`\cM:\Rset^p \mapsto \Rset^q` with :math:`\cM(\vect{x})= \vect{y}`.

    The Morris method is a screening method, which is known to be very efficient in case of huge number of input parameters (p >> 1).
    It is a qualitative sensitivity analysis method which is based on design of experiments and allows to identify the few important factors at a cost of r * (p + 1) simulations.
    The experiments are of type OAT (One At Time); i.e. only one parameter vary at a time.

    The method helps to split input parameters into three groups:

     - Those with negligible effects on the output,
     - Those with significant and linear effects on the output,
     - Those with significant and non linear (or with interactions) effects on the
       output.

     The method rely on input designs defined in the hypersphere unit. To sum up the key points of the method, we consider a point named :math:`\vect{x^*}` in this hypersphere and a parameter :math:`\delta` (parameter of discretization if we consider a regular experiment for example). Starting from the point, we choose randomly one direction by increasing\slash decreasing one component one component of the point :math:`\vect{x^*}` with :math:`\delta`. Conditionnaly to this direction, we choose then the p-1 directions by randomly selecting one direction at time. We get then a trajectory (path).

    The Morris method rely on the evaluation of elementary effects which are defined as follow:

    .. math::

        d_{i}(\vect{x}^k) = \frac{\cM(x_1^k,\hdots, x_{i-1}^k, x_i^k + \delta,\hdots, x_p^k) - \cM(x_1^k,\hdots, x_{i-1}^k, x_i^k,\hdots, x_p^k)}{\delta}

    With :math:`N` trajectories, we get the mean and standard deviation of these effects (we consider the mean of absolute mean effects in our case). The mean explains the sensitivity wheras the standard deviation explains the interactions and non linear effects.

    With the first constructor, we consider that input experiment has been generated thanks to the :class:`~otmorris.MorrisExperiment` and output is evaluated outside the platform.
    With second constructor, the output is evaluated inside the platform.

    Examples
    --------
    >>> import openturns as ot
    >>> import otmorris
    >>> # Define model
    >>> ot.RandomGenerator.SetSeed(1)
    >>> alpha = ot.DistFunc.rNormal(10)
    >>> beta = ot.DistFunc.rNormal(84)
    >>> gamma = ot.DistFunc.rNormal(280)
    >>> b0 = ot.DistFunc.rNormal()
    >>> model = otmorris.MorrisFunction(alpha, beta, gamma, b0)
    >>> # Number of trajectories
    >>> r = 5
    >>> # Define a k-grid level (so delta = 1/(k-1))
    >>> k = 5
    >>> morris_experiment = otmorris.MorrisExperimentGrid([k] * 20, r)
    >>> X = morris_experiment.generate()
    >>> # Evaluation of the model on the design: evaluation outside OT
    >>> Y = model(X)
    >>> # need the bounds when using X and Y
    >>> bounds = morris_experiment.getBounds()
    >>> # Evaluation of Morris effects
    >>> morris = otmorris.Morris(X, Y, bounds)
    >>> # Get mean/sigma effects
    >>> mean_effects = morris.getMeanElementaryEffects()
    >>> mean_abs_effects = morris.getMeanAbsoluteElementaryEffects()
    >>> sigma_effects = morris.getStandardDeviationElementaryEffects()

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def getClassName(self):
        r"""
        Accessor to the object's name.

        Returns
        -------
        class_name : str
            The object class name (`object.__class__.__name__`).
        """
        return _otmorris.Morris_getClassName(self)

    def getMeanAbsoluteElementaryEffects(self, outputMarginal=0):
        r"""
        Get the mean of absolute elementary effects.

        Parameters
        ----------
        marginal : int
            Output marginal of interest

        Returns
        -------
        mean: :py:class:`openturns.Point`
            The mean effects.

        """
        return _otmorris.Morris_getMeanAbsoluteElementaryEffects(self, outputMarginal)

    def getMeanElementaryEffects(self, outputMarginal=0):
        r"""
        Get the mean of elementary effects.

        Parameters
        ----------
        marginal : int
            Output marginal of interest

        Returns
        -------
        mean: :py:class:`openturns.Point`
            The mean effects.

        """
        return _otmorris.Morris_getMeanElementaryEffects(self, outputMarginal)

    def getStandardDeviationElementaryEffects(self, outputMarginal=0):
        r"""
        Get the standard deviation of elementary effects.

        Parameters
        ----------
        marginal : int
            Output marginal of interest

        Returns
        -------
        mean: :py:class:`openturns.Point`
            The standard effects

        """
        return _otmorris.Morris_getStandardDeviationElementaryEffects(self, outputMarginal)

    def getInputSample(self):
        r"""
        Accessor to the input sample.

        Returns
        -------
        inputSample : :py:class:`openturns.Sample`
            The input sample

        """
        return _otmorris.Morris_getInputSample(self)

    def getOutputSample(self):
        r"""
        Accessor to the output sample.

        Returns
        -------
        inputSample : :py:class:`openturns.Sample`
            The output sample

        """
        return _otmorris.Morris_getOutputSample(self)

    def __repr__(self):
        return _otmorris.Morris___repr__(self)

    def __init__(self, *args):
        _otmorris.Morris_swiginit(self, _otmorris.new_Morris(*args))
    __swig_destroy__ = _otmorris.delete_Morris

# Register Morris in _otmorris:
_otmorris.Morris_swigregister(Morris)



import openturns as ot

class MorrisFunction(ot.OpenTURNSPythonFunction):
    """
    The non-monotonic function of Morris f: R^20 -> R

    Reference:
      M. D. Morris, 1991, Factorial sampling plans for preliminary
      computational experiments,Technometrics, 33, 161--174.

    Examples
    --------
    >>> import openturns as ot
    >>> ot.RandomGenerator.SetSeed(123)
    >>> b0 = ot.DistFunc.rNormal()
    >>> alpha = ot.DistFunc.rNormal(10)
    >>> beta =  ot.DistFunc.rNormal(6*14)
    >>> gamma =  ot.DistFunc.rNormal(20*14)
    >>> f = ot.Function(MorrisFunction(alpha, beta, gamma, b0))
    >>> input_sample = ot.ComposedDistribution([ot.Uniform(0,1)] * 20).getSample(20)
    >>> output_sample = f(input_sample)

    """
    def __init__(self, alpha = ot.Point(10), beta = ot.Point(14*6),\
                 gamma = ot.Point(20*14), b0 = 0.0):
        ot.OpenTURNSPythonFunction.__init__(self, 20, 1)
        self.b0 = float(b0)
# Check alpha dimension
        assert(len(alpha) == 10)
        self.b1 = [20] * 10 + list(alpha)
# Check beta and gamma dimension
        assert(len(beta) == 6 * 14)
        assert(len(gamma) == 20 * 14)
        self.b2 = [[0] *20] * 20
        for i in range(6):
            for j in range(6):
                self.b2[i][j] = -15.0
# Take into account beta
        k = 0
        for i in range(6):
            for j in range(14):
                self.b2[i][j + 6] = beta[k]
                k = k + 1
# Take into account gamma
        k = 0
        for i in range(6, 20):
            for j in range(20):
                self.b2[i][j] = gamma[k]

# b3
        self.b3 = [[[0]*20]*20]*20
        for i in range(5):
            for j in range(5):
                for k in range(5):
                    self.b3[i][j][k] = -10.0
# b4
        self.b4 = [[[[0]*20]*20]*20]*20
        for i in range(4):
            for j in range(4):
                for k in range(4):
                    for l in range(4):
                        self.b4[i][j][k][l] = 5

    def _exec(self, x):
        assert (len(x)==20)
        b1 = self.b1
        b2 = self.b2
        b3 = self.b3
        b4 = self.b4
# X is a list, transform it into array
        X = ot.Point(x)
        w = (X - [0.5]*20)*2
        for k in [2,4,6]:
           w[k] = 2.0 * (1.1 * X[k] / (X[k] + 0.1) - 0.5)
        y = 0.0
        y = w.dot(b1) if hasattr(w, 'dot') else ot.dot(w, b1) # moved in ot>=1.14
# Morris function
        for i in range(19):
            for j in range(i + 1, 20):
                y +=  b2[i][j] * w[i] * w[j]
        for i in range(18):
            for j in range(i + 1, 19):
                for k in range(j + 1, 20):
                    y += b3[i][j][k] * w[i] * w[j] * w[k]

        for i in range(17):
            for j in range(i + 1, 18):
                for k in range(j + 1, 20):
                    for l in range(k + 1, 20):
                        y += b4[i][j][k][l] * w[i] * w[j] * w[k] * w[l]

        return [y + self.b0]



