# 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.

"""otagr 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 _otagrum
else:
    import _otagrum

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 pyAgrum as gum

import pyAgrum
class Utils(object):
    r"""Utility functions"""

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

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr

    @staticmethod
    def Discretize(*args):
        r"""
        Discretize a continuous distribution.

        Compute a probability table according to the domains defined
        in a discretized aGrUM variable and a continuous OpenTURNS distribution.

        .. math::

           \big\{ p_i \big\} = \big\{ \Prob{t_i < X \leq t_{i+1}}, i \in \left[ 1, n \right] \big\}

        where :math:`$t_i$` are the aGrUM ticks, and :math:`$X$` is distributed according to the OpenTURNS distribution.

        Parameters
        ----------
        distribution : :py:class:`openturns.Distribution`
            An continuous 1-d distribution.
        v : :py:class:`pyAgrum.DiscretizedVariable`
            A discrete variable.

        Returns
        -------
        p : :py:class:`pyAgrum.Potential`
            The resulting potential.

        Examples
        --------
        >>> import pyAgrum as gum
        >>> import openturns as ot
        >>> import otagrum
        >>> height = gum.DiscretizedVariable('Height', 'plant growth', [0.0, 10.0, 20.0, 30.0])
        >>> height_dist = ot.Normal(18.0, 8.0)
        >>> str(otagrum.Utils.Discretize(height_dist, height))
        '<Height:[0;10[> :: 0.158997 /<Height:[10;20[> :: 0.477813 /<Height:[20;30]> :: 0.36319'
        """

        var = args[1]


        val = _otagrum.Utils_Discretize(*args)

        val._list_vars = [var]


        return val

    @staticmethod
    def FromMarginal(pot):
        r"""
        Convert an 1-d probability table to a distribution.

        Converts an univariate aGrUM probability table to an OpenTURNS distribution,
        either :py:class:`openturns.Histogram` or :py:class:`openturns.UserDefined`.

        Parameters
        ----------
        p : :py:class:`pyAgrum.Potential`
            A potential with one variable.

        Returns
        -------
        distribution : :py:class:`openturns.Distribution`
            A distribution.

        Examples
        --------
        >>> import pyAgrum as gum
        >>> import otagrum
        >>> light = gum.LabelizedVariable('Light', 'quality of light', 0).addLabel('Dim').addLabel('Bright')
        >>> pot = gum.Potential().add(light)
        >>> pot[:]= [0.25, 0.75]
        >>> str(otagrum.Utils.FromMarginal(pot))
        'UserDefined({x = [0], p = 0.25}, {x = [1], p = 0.75})'
        """
        return _otagrum.Utils_FromMarginal(pot)

    @staticmethod
    def FromPotential(pot):
        r"""
        Convert an n-d probability table to a distribution.

        Converts a multivariate aGrUM probability table to an OpenTURNS distribution,
        using :py:class:`openturns.MixedHistogramUserDefined`

        Parameters
        ----------
        p : :py:class:`pyAgrum.Potential`
            The potential.

        Returns
        -------
        distribution : :py:class:`openturns.Distribution`
            A distribution.

        Examples
        --------
        >>> import pyAgrum as gum
        >>> import otagrum
        >>> light = gum.LabelizedVariable('Light', 'light', 0).addLabel('Dim').addLabel('Bright')
        >>> moisture = gum.LabelizedVariable('Moisture', 'moisture', 0).addLabel('Dry').addLabel('Wet')
        >>> pot = gum.Potential().add(light).add(moisture)
        >>> pot[{'Light': 'Dim',    'Moisture': 'Dry'}] = 0.3
        >>> pot[{'Light': 'Dim',    'Moisture': 'Wet'}] = 0.2
        >>> pot[{'Light': 'Bright', 'Moisture': 'Dry'}] = 0.1
        >>> pot[{'Light': 'Bright', 'Moisture': 'Wet'}] = 0.4
        >>> str(otagrum.Utils.FromPotential(pot))
        'MixedHistogramUserDefined(ticksCollection = [[0,1],[0,1]], kind = [0,0], probabilityTable = [0.3,0.1,0.2,0.4])'
        """
        return _otagrum.Utils_FromPotential(pot)
    __swig_destroy__ = _otagrum.delete_Utils

# Register Utils in _otagrum:
_otagrum.Utils_swigregister(Utils)

def Utils_Discretize(*args):
    r"""
    Discretize a continuous distribution.

    Compute a probability table according to the domains defined
    in a discretized aGrUM variable and a continuous OpenTURNS distribution.

    .. math::

       \big\{ p_i \big\} = \big\{ \Prob{t_i < X \leq t_{i+1}}, i \in \left[ 1, n \right] \big\}

    where :math:`$t_i$` are the aGrUM ticks, and :math:`$X$` is distributed according to the OpenTURNS distribution.

    Parameters
    ----------
    distribution : :py:class:`openturns.Distribution`
        An continuous 1-d distribution.
    v : :py:class:`pyAgrum.DiscretizedVariable`
        A discrete variable.

    Returns
    -------
    p : :py:class:`pyAgrum.Potential`
        The resulting potential.

    Examples
    --------
    >>> import pyAgrum as gum
    >>> import openturns as ot
    >>> import otagrum
    >>> height = gum.DiscretizedVariable('Height', 'plant growth', [0.0, 10.0, 20.0, 30.0])
    >>> height_dist = ot.Normal(18.0, 8.0)
    >>> str(otagrum.Utils.Discretize(height_dist, height))
    '<Height:[0;10[> :: 0.158997 /<Height:[10;20[> :: 0.477813 /<Height:[20;30]> :: 0.36319'
    """

    var = args[1]


    val = _otagrum.Utils_Discretize(*args)

    val._list_vars = [var]


    return val

def Utils_FromMarginal(pot):
    r"""
    Convert an 1-d probability table to a distribution.

    Converts an univariate aGrUM probability table to an OpenTURNS distribution,
    either :py:class:`openturns.Histogram` or :py:class:`openturns.UserDefined`.

    Parameters
    ----------
    p : :py:class:`pyAgrum.Potential`
        A potential with one variable.

    Returns
    -------
    distribution : :py:class:`openturns.Distribution`
        A distribution.

    Examples
    --------
    >>> import pyAgrum as gum
    >>> import otagrum
    >>> light = gum.LabelizedVariable('Light', 'quality of light', 0).addLabel('Dim').addLabel('Bright')
    >>> pot = gum.Potential().add(light)
    >>> pot[:]= [0.25, 0.75]
    >>> str(otagrum.Utils.FromMarginal(pot))
    'UserDefined({x = [0], p = 0.25}, {x = [1], p = 0.75})'
    """
    return _otagrum.Utils_FromMarginal(pot)

def Utils_FromPotential(pot):
    r"""
    Convert an n-d probability table to a distribution.

    Converts a multivariate aGrUM probability table to an OpenTURNS distribution,
    using :py:class:`openturns.MixedHistogramUserDefined`

    Parameters
    ----------
    p : :py:class:`pyAgrum.Potential`
        The potential.

    Returns
    -------
    distribution : :py:class:`openturns.Distribution`
        A distribution.

    Examples
    --------
    >>> import pyAgrum as gum
    >>> import otagrum
    >>> light = gum.LabelizedVariable('Light', 'light', 0).addLabel('Dim').addLabel('Bright')
    >>> moisture = gum.LabelizedVariable('Moisture', 'moisture', 0).addLabel('Dry').addLabel('Wet')
    >>> pot = gum.Potential().add(light).add(moisture)
    >>> pot[{'Light': 'Dim',    'Moisture': 'Dry'}] = 0.3
    >>> pot[{'Light': 'Dim',    'Moisture': 'Wet'}] = 0.2
    >>> pot[{'Light': 'Bright', 'Moisture': 'Dry'}] = 0.1
    >>> pot[{'Light': 'Bright', 'Moisture': 'Wet'}] = 0.4
    >>> str(otagrum.Utils.FromPotential(pot))
    'MixedHistogramUserDefined(ticksCollection = [[0,1],[0,1]], kind = [0,0], probabilityTable = [0.3,0.1,0.2,0.4])'
    """
    return _otagrum.Utils_FromPotential(pot)

class IndicesList(object):
    r"""
    Collection.

    Examples
    --------
    >>> import openturns as ot

    - Collection of **real values**:

    >>> ot.ScalarCollection(2)
    [0,0]
    >>> ot.ScalarCollection(2, 3.25)
    [3.25,3.25]
    >>> vector = ot.ScalarCollection([2.0, 1.5, 2.6])
    >>> vector
    [2,1.5,2.6]
    >>> vector[1] = 4.2
    >>> vector
    [2,4.2,2.6]
    >>> vector.add(3.8)
    >>> vector
    [2,4.2,2.6,3.8]

    - Collection of **complex values**:

    >>> ot.ComplexCollection(2)
    [(0,0),(0,0)]
    >>> ot.ComplexCollection(2, 3+4j)
    [(3,4),(3,4)]
    >>> vector = ot.ComplexCollection([2+3j, 1-4j, 3.0])
    >>> vector
    [(2,3),(1,-4),(3,0)]
    >>> vector[1] = 4+3j
    >>> vector
    [(2,3),(4,3),(3,0)]
    >>> vector.add(5+1j)
    >>> vector
    [(2,3),(4,3),(3,0),(5,1)]

    - Collection of **booleans**:

    >>> ot.BoolCollection(3)
    [0,0,0]
    >>> ot.BoolCollection(3, 1)
    [1,1,1]
    >>> vector = ot.BoolCollection([0, 1, 0])
    >>> vector
    [0,1,0]
    >>> vector[1] = 0
    >>> vector
    [0,0,0]
    >>> vector.add(1)
    >>> vector
    [0,0,0,1]

    - Collection of **distributions**:

    >>> print(ot.DistributionCollection(2))
    [Uniform(a = -1, b = 1),Uniform(a = -1, b = 1)]
    >>> print(ot.DistributionCollection(2, ot.Gamma(2.75, 1.0)))
    [Gamma(k = 2.75, lambda = 1, gamma = 0),Gamma(k = 2.75, lambda = 1, gamma = 0)]
    >>> vector = ot.DistributionCollection([ot.Normal(), ot.Uniform()])
    >>> print(vector)
    [Normal(mu = 0, sigma = 1),Uniform(a = -1, b = 1)]
    >>> vector[1] = ot.Uniform(-0.5, 1)
    >>> print(vector)
    [Normal(mu = 0, sigma = 1),Uniform(a = -0.5, b = 1)]
    >>> vector.add(ot.Gamma(2.75, 1.0))
    >>> print(vector)
    [Normal(mu = 0, sigma = 1),Uniform(a = -0.5, b = 1),Gamma(k = 2.75, lambda = 1, gamma = 0)]
    """

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

    def clear(self):
        r"""
        Reset the collection to zero dimension.

        Examples
        --------
        >>> import openturns as ot
        >>> x = ot.Point(2)
        >>> x.clear()
        >>> x
        class=Point name=Unnamed dimension=0 values=[]
        """
        return _otagrum.IndicesList_clear(self)

    def __len__(self):
        return _otagrum.IndicesList___len__(self)

    def __eq__(self, rhs):
        return _otagrum.IndicesList___eq__(self, rhs)

    def __contains__(self, val):
        return _otagrum.IndicesList___contains__(self, val)

    def __getitem__(self, i):
        return _otagrum.IndicesList___getitem__(self, i)

    def __setitem__(self, i, val):
        return _otagrum.IndicesList___setitem__(self, i, val)

    def __delitem__(self, i):
        return _otagrum.IndicesList___delitem__(self, i)

    def at(self, *args):
        r"""
        Access to an element of the collection.

        Parameters
        ----------
        index : positive int
            Position of the element to access.

        Returns
        -------
        element : type depends on the type of the collection
            Element of the collection at the position *index*.
        """
        return _otagrum.IndicesList_at(self, *args)

    def add(self, *args):
        r"""
        Append a component (in-place).

        Parameters
        ----------
        value : type depends on the type of the collection.
            The component to append.

        Examples
        --------
        >>> import openturns as ot
        >>> x = ot.Point(2)
        >>> x.add(1.)
        >>> print(x)
        [0,0,1]
        """
        return _otagrum.IndicesList_add(self, *args)

    def getSize(self):
        r"""
        Get the collection's dimension (or size).

        Returns
        -------
        n : int
            The number of components in the collection.
        """
        return _otagrum.IndicesList_getSize(self)

    def resize(self, newSize):
        r"""
        Change the size of the collection.

        Parameters
        ----------
        newSize : positive int
            New size of the collection.

        Notes
        -----
        If the new size is smaller than the older one, the last elements are thrown
        away, else the new elements are set to the default value of the element type.

        Examples
        --------
        >>> import openturns as ot
        >>> x = ot.Point(2, 4)
        >>> print(x)
        [4,4]
        >>> x.resize(1)
        >>> print(x)
        [4]
        >>> x.resize(4)
        >>> print(x)
        [4,0,0,0]
        """
        return _otagrum.IndicesList_resize(self, newSize)

    def isEmpty(self):
        r"""
        Tell if the collection is empty.

        Returns
        -------
        isEmpty : bool
            *True* if there is no element in the collection.

        Examples
        --------
        >>> import openturns as ot
        >>> x = ot.Point(2)
        >>> x.isEmpty()
        False
        >>> x.clear()
        >>> x.isEmpty()
        True
        """
        return _otagrum.IndicesList_isEmpty(self)

    def find(self, val):
        r"""
        Find the index of a given value.

        Parameters
        ----------
        val : collection value type
            The value to find

        Returns
        -------
        index : int
            The index of the first occurence of the value,
            or the size of the container if not found.
            When several values match, only the first index is returned.
        """
        return _otagrum.IndicesList_find(self, val)

    def __repr__(self):
        return _otagrum.IndicesList___repr__(self)

    def __str__(self, *args):
        return _otagrum.IndicesList___str__(self, *args)

    def __init__(self, *args):
        _otagrum.IndicesList_swiginit(self, _otagrum.new_IndicesList(*args))

# Register IndicesList in _otagrum:
_otagrum.IndicesList_swigregister(IndicesList)

class NamedJunctionTree(openturns.common.Object):
    r"""
    NamedJunctionTree interface.

    Available constuctors:
        NamedJunctionTree(*jt, names*)

        NamedJunctionTree(*jt, bn*)

    Parameters
    ----------
    jt : :py:class:`pyAgrum.CliqueGraph`
        A junction tree.
    bn : :py:class:`pyAgrum.BayesNet`
        A bayesian network.
    names : list
        A list of node names.

    Examples
    --------
    >>> import otagrum
    >>> import pyAgrum as gum
    >>> bn = gum.BayesNet.fastPrototype('0->1->2->3;1->4->3;4->5;6->5;7->5')
    >>> ie = gum.LazyPropagation(bn)
    >>> jtagr = ie.junctionTree()
    >>> njt = otagrum.NamedJunctionTree(jtagr, bn)
    """

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

    def getSize(self):
        r"""
        Return size of the named junction tree.

        Returns
        -------
        size : int
            The number of nodes in the junction tree.
        """
        return _otagrum.NamedJunctionTree_getSize(self)

    def getDescription(self):
        r"""
        Return the description of the named junction tree.

        Returns
        -------
        names : list
            The list of variable names.
        """
        return _otagrum.NamedJunctionTree_getDescription(self)

    def getClique(self, nod):
        r"""
        Return id of the variables in the clique.

        Parameters
        ----------
        node : int
            Id of the desired node clique.

        Returns
        -------
        clique : :py:class:`~openturns.Indices`
            Indices of the variables in the desired clique node.
        """
        return _otagrum.NamedJunctionTree_getClique(self, nod)

    def getSeparator(self, nod1, nod2):
        r"""
        Return the separator associated to an edge of the junction tree.

        Parameters
        ----------
        node1 : int
            Id of one end of the desired edge.
        node2 : int
            Id of the other end of the desired edge.

        Returns
        -------
        separator : :py:class:`~openturns.Indices`
            Separator associated to the desired edge.
        """
        return _otagrum.NamedJunctionTree_getSeparator(self, nod1, nod2)

    def getNeighbours(self, id):
        r"""
        Return the neighbours of a clique node.

        Parameters
        ----------
        node : int
            Id of a clique node  in the junction tree.

        Returns
        -------
        neighbours : :py:class:`~openturns.Indices`
            Neighbours of the desired clique node.
        """
        return _otagrum.NamedJunctionTree_getNeighbours(self, id)

    def getNodes(self):
        r"""
        Return ids of the clique nodes in the junction tree.

        Returns
        -------
        nodes : :py:class:`~openturns.Indices`
            Ids of the clique nodes
        """
        return _otagrum.NamedJunctionTree_getNodes(self)

    def getCliquesCollection(self):
        r"""
        Cliques accessor

        Returns
        -------
        cliques : sequence of :py:class:`openturns.Indices`
            List of cliques
        """
        return _otagrum.NamedJunctionTree_getCliquesCollection(self)

    def getSeparatorsCollection(self):
        r"""
        Separators accessor

        Returns
        -------
        separators : sequence of :py:class:`openturns.Indices`
            List of separators
        """
        return _otagrum.NamedJunctionTree_getSeparatorsCollection(self)

    def getMarginal(self, indices):
        r"""
        Return the marginal junction tree on desired variables.

        Parameters
        ----------
        nodes : :py:class:`~openturns.Indices`
            Ids of target variables.

        Returns
        -------
        marginal : :class:`~otagrum.NamedJunctionTree`
            Marginal junction tree on target variables.
        """
        return _otagrum.NamedJunctionTree_getMarginal(self, indices)

    def __str__(self, *args):
        return _otagrum.NamedJunctionTree___str__(self, *args)

    def getOrderMaxFirst(self):
        r"""
        Return an order on the junction tree beginning with the largest clique.

        Returns
        -------
        order : :class:`~openturns.Indices`
            The order.

        """
        return _otagrum.NamedJunctionTree_getOrderMaxFirst(self)

    def __init__(self, *args):
        _otagrum.NamedJunctionTree_swiginit(self, _otagrum.new_NamedJunctionTree(*args))
    __swig_destroy__ = _otagrum.delete_NamedJunctionTree

# Register NamedJunctionTree in _otagrum:
_otagrum.NamedJunctionTree_swigregister(NamedJunctionTree)

class NamedDAG(openturns.common.PersistentObject):
    r"""
    NamedDAG represents a directed acyclic graph (DAG) whose nodes have an
    associated name.

    Available constructors:
        NamedDAG(*bn*)

        NamedDAG(*dag,names*)

    Parameters
    ----------
    bn : :py:class:`pyAgrum.BayesNet`
        Bayesian network
    dag : :py:class:`pyAgrum.DAG`
        Directed Acyclic Graph
    names : sequence of str
        Node names
    """

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

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

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

    def getSize(self):
        r"""
        The number of nodes in the DAG.

        Returns
        -------
        size : int
            The DAG size
        """
        return _otagrum.NamedDAG_getSize(self)

    def getDescription(self):
        r"""
        The names of the DAG variables.

        Returns
        -------
        names : list
            The list of node names
        """
        return _otagrum.NamedDAG_getDescription(self)

    def getParents(self, nod):
        r"""
        The parents of a node.

        Parameters
        ----------
        node : int
            Node id

        Returns
        -------
        parents : :py:class:`openturns.Indices`
            Indices of parent nodes

        """
        return _otagrum.NamedDAG_getParents(self, nod)

    def getChildren(self, nod):
        r"""
        The children of a node.

        Parameters
        ----------
        node : int
            Node id

        Returns
        -------
        children : :py:class:`openturns.Indices`
            Indices of children nodes

        """
        return _otagrum.NamedDAG_getChildren(self, nod)

    def getTopologicalOrder(self):
        r"""
        The list of the nodes IDs in a topological order.

        Returns
        -------
        nodes : :py:class:`openturns.Indices`
            Indices of nodes

        """
        return _otagrum.NamedDAG_getTopologicalOrder(self)

    def getDAG(self):
        return _otagrum.NamedDAG_getDAG(self)

    def __str__(self, *args):
        return _otagrum.NamedDAG___str__(self, *args)

    def toDot(self):
        r"""
        Displays the graph in DOT format.

        Returns
        -------
        dot : str
            DOT graph

        """
        return _otagrum.NamedDAG_toDot(self)

    def __init__(self, *args):
        _otagrum.NamedDAG_swiginit(self, _otagrum.new_NamedDAG(*args))
    __swig_destroy__ = _otagrum.delete_NamedDAG

# Register NamedDAG in _otagrum:
_otagrum.NamedDAG_swigregister(NamedDAG)

class JunctionTreeBernsteinCopula(openturns.model_copula.ContinuousDistribution):
    r"""
    JunctionTreeBernsteinCopula distribution

    Available constructors:
        JunctionTreeBernsteinCopula(*junctionTree, copulaSample, binNumber, isCopulaSample*)

        JunctionTreeBernsteinCopula(*cliquesCollection, separatorsCollection, binNumber, isCopulaSample*)

    Parameters
    ----------
    junctionTree : a :class:`~otagrum.NamedJunctionTree`
        The junction tree describing the dependence structure of the copula.
    copulaSample : a 2-d sequence of float.
        The sample defining the copula
    binNumber : int
        The common number of bins for all the Bernstein copulas involved in modelling
        cliques and separators copulas.
    isCopulaSample : bool
        Flag to tell if the given sample is already in the normalized rank space.

    Notes
    -----
    This class allows to build a nonparametric copula from a given sample, a bin
    count and a junction tree describing the conditional independencies in the data.
    It is based on a Bernstein estimation of each sub-copulas of the model.

    Examples
    --------
    >>> import otagrum
    >>> import openturns as ot
    >>> import pyAgrum as gum
    >>> bn = gum.BayesNet.fastPrototype('0->1->2->3;1->4->3;4->5;6->5;7->5')
    >>> ie = gum.LazyPropagation(bn)
    >>> jtagr = ie.junctionTree()
    >>> jt = otagrum.NamedJunctionTree(jtagr, bn.names())
    >>> sample = ot.Normal(5).getSample(1000)
    >>> binNumber = 5
    >>> copula = otagrum.JunctionTreeBernsteinCopula(jt, sample, binNumber, False)
    """

    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 _otagrum.JunctionTreeBernsteinCopula_getClassName(self)

    def __eq__(self, *args):
        return _otagrum.JunctionTreeBernsteinCopula___eq__(self, *args)

    def __repr__(self):
        return _otagrum.JunctionTreeBernsteinCopula___repr__(self)

    def __str__(self, *args):
        return _otagrum.JunctionTreeBernsteinCopula___str__(self, *args)

    def getRealization(self):
        r"""
        Accessor to a pseudo-random realization from the distribution.

        Refer to :ref:`distribution_realization`.

        Returns
        -------
        point : :class:`~openturns.Point`
            A pseudo-random realization of the distribution.

        See Also
        --------
        getSample, RandomGenerator
        """
        return _otagrum.JunctionTreeBernsteinCopula_getRealization(self)

    def computePDF(self, *args):
        r"""
        Compute the probability density function.

        Parameters
        ----------
        X : sequence of float, 2-d sequence of float
            PDF input(s).

        Returns
        -------
        f : float, :class:`~openturns.Point`
            PDF value(s) at input(s) :math:`X`.

        Notes
        -----
        The probability density function is defined as follows:

        .. math::

            f_{\vect{X}}(\vect{x}) = \frac{\partial^n F_{\vect{X}}(\vect{x})}
                                          {\prod_{i=1}^n \partial x_i},
                                     \quad \vect{x} \in \supp{\vect{X}}
        """
        return _otagrum.JunctionTreeBernsteinCopula_computePDF(self, *args)

    def setCopulaSample(self, copulaSample, isEmpiricalCopulaSample=False):
        r"""
        Set the sample defining the (Bernstein) copula.

        Parameters
        ----------
        sample : 2-d sequence of float
            The sample defining the copula.
        isCopulaSample : bool
            Flag to tell if the given sample is already in the normalized rank space.

        """
        return _otagrum.JunctionTreeBernsteinCopula_setCopulaSample(self, copulaSample, isEmpiricalCopulaSample)

    def getCopulaSample(self):
        r"""
        Return the sample defining the (Bernstein) copula.

        Returns
        -------
        copulaSample : :py:class:`openturns.Sample`
            Sample in the normalized rank space.
        """
        return _otagrum.JunctionTreeBernsteinCopula_getCopulaSample(self)

    def setCliquesOrder(self, cliquesOrder):
        r"""
        Set the order according to which the cliques are traversed.

        Parameters
        ----------
        order : :class:`~openturns.Indices`
          The order.

        """
        return _otagrum.JunctionTreeBernsteinCopula_setCliquesOrder(self, cliquesOrder)

    def getBinNumber(self):
        r"""
        Return the number of bin which is common to all the local Bernstein copula.
        It corresponds to the number of cells into which each dimension of the unit hypercube
        is divided to cluster the empirical copula sample.

        Returns
        -------
        binNumber : int
            The number of bins. 

        """
        return _otagrum.JunctionTreeBernsteinCopula_getBinNumber(self)

    def getMarginal(self, *args):
        r"""
        Accessor to marginal distributions.

        Parameters
        ----------
        i : int or list of ints, :math:`1 \leq i \leq n`
            Component(s) indice(s).

        Returns
        -------
        distribution : :class:`~openturns.Distribution`
            The marginal distribution of the selected component(s).
        """
        return _otagrum.JunctionTreeBernsteinCopula_getMarginal(self, *args)

    def __init__(self, *args):
        _otagrum.JunctionTreeBernsteinCopula_swiginit(self, _otagrum.new_JunctionTreeBernsteinCopula(*args))
    __swig_destroy__ = _otagrum.delete_JunctionTreeBernsteinCopula

# Register JunctionTreeBernsteinCopula in _otagrum:
_otagrum.JunctionTreeBernsteinCopula_swigregister(JunctionTreeBernsteinCopula)

class JunctionTreeBernsteinCopulaFactory(openturns.model_copula.DistributionFactoryImplementation):
    r"""
    Estimate a Junction-Tree Bernstein Copula.

    Parameters
    ----------
    nbBins : int
        Number of bins.
    alpha : float
        Threshold.
    maximumConditioningSetSize : int
        Maximum conditional set size.

    Examples
    --------
    >>> import otagrum
    >>> factory = otagrum.JunctionTreeBernsteinCopulaFactory(5, 0.1, 5)
    """

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

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

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

    def build(self, *args):
        r"""
        Build the distribution.

        **Available usages**:

            build(*sample*)

            build(*param*)

        Parameters
        ----------
        sample : 2-d sequence of float
            Sample from which the distribution parameters are estimated.
        param : Collection of :class:`~openturns.PointWithDescription`
            A vector of parameters of the distribution.

        Returns
        -------
        dist : :class:`~openturns.Distribution`
            The built distribution.
        """
        return _otagrum.JunctionTreeBernsteinCopulaFactory_build(self, *args)

    def buildAsJunctionTreeBernsteinCopula(self, *args):
        r"""
        Build a JunctionTreeBernsteinCopula distribution estimated from a sample.

        Parameters
        ----------
        sample : :py:class:`openturns.Sample`
            Input sample.

        Returns
        -------
        distribution : :class:`~otagrum.JunctionTreeBernsteinCopula`
            The estimated JunctionTreeBernsteinCopula distribution.
        """
        return _otagrum.JunctionTreeBernsteinCopulaFactory_buildAsJunctionTreeBernsteinCopula(self, *args)

    def __init__(self, *args):
        _otagrum.JunctionTreeBernsteinCopulaFactory_swiginit(self, _otagrum.new_JunctionTreeBernsteinCopulaFactory(*args))
    __swig_destroy__ = _otagrum.delete_JunctionTreeBernsteinCopulaFactory

# Register JunctionTreeBernsteinCopulaFactory in _otagrum:
_otagrum.JunctionTreeBernsteinCopulaFactory_swigregister(JunctionTreeBernsteinCopulaFactory)

class ContinuousTTest(openturns.common.Object):
    r"""
    ContinuousTTest class.

    Parameters
    ----------
    data : 2-d sequence of float
        The data from which the t-test statistics are extracted.
    alpha : float
        The confidence level. If not specified, its value is set to 0.1.
    """

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

    def __init__(self, data, alpha=0.1):
        _otagrum.ContinuousTTest_swiginit(self, _otagrum.new_ContinuousTTest(data, alpha))

    def setAlpha(self, alpha):
        r"""
        Change the hypothesis test threshold.

        Parameters
        ----------
        alpha : float, :math:`\alpha \in [0, 1]`
            New value of the hypothesis test threshold.
        """
        return _otagrum.ContinuousTTest_setAlpha(self, alpha)

    def getAlpha(self):
        r"""
        Return the hypothesis test threshold.

        Returns
        -------
        alpha : float
            Hypothesis test threshold
        """
        return _otagrum.ContinuousTTest_getAlpha(self)

    def getTTest(self, Y, Z, X):
        r"""
        Return the value of t-test statistics for the hypothesis Y indep Z | X.

        Parameters
        ----------
        Y : int
            Y node id.
        Z : int
            Z node id.
        X : list
            list of node ids in the set X.

        Returns
        -------
        ttest : float
            Value of the t-test statistics.
        """
        return _otagrum.ContinuousTTest_getTTest(self, Y, Z, X)

    def getTTestWithoutCorrections(self, Y, Z, X):
        r"""
        Return the value of t-test statistics without corrections for the hypothesis
        Y indep Z | X.

        Parameters
        ----------
        Y : int
            Y node id.
        Z : int
            Z node id.
        X : list
            list of node ids in the set X.

        Returns
        -------
        ttest : float
            Value of the raw t-test statistics
        """
        return _otagrum.ContinuousTTest_getTTestWithoutCorrections(self, Y, Z, X)

    @staticmethod
    def isIndepFromTest(t, alpha):
        r"""
        Test independence from a given t-test statistics value and a given confidence
        threshold.

        Parameters
        ----------
        t : float
            A value of t-test statistics.
        alpha : float
            A confidence threshold.

        Returns
        -------
        result : tuple
            (t-test, p-value, independent?)
        """
        return _otagrum.ContinuousTTest_isIndepFromTest(t, alpha)

    def isIndep(self, Y, Z, X):
        r"""
        Test the hypothesis Y indep Z | X.

        Parameters
        ----------
        Y : int
            Y node id.
        Z : int
            Z node id.
        X : list
            list of node ids in the set X.

        Returns
        -------
        result : tuple
            (t-test, p-value, independent?)
        """
        return _otagrum.ContinuousTTest_isIndep(self, Y, Z, X)

    def __str__(self, *args):
        return _otagrum.ContinuousTTest___str__(self, *args)

    def clearCache(self):
        r"""
        Clear cache containing the logPDFs of conditional empirical Bernstein copula
        (X,Y|Z) that are used to compute the test statistics.
        """
        return _otagrum.ContinuousTTest_clearCache(self)

    def clearCacheLevel(self, level):
        r"""
        Clear cache for a fixed size of conditioning set (cache level).

        Parameters
        ----------
        level : int
            The cache level.
        """
        return _otagrum.ContinuousTTest_clearCacheLevel(self, level)

    def getDimension(self):
        r"""
        Return the dimension of the underlying data set.

        Returns
        -------
        dimension : int
            Dimension of the data set.
        """
        return _otagrum.ContinuousTTest_getDimension(self)

    def getDataDescription(self):
        r"""
        Return the description (variable names) of the underlying data set.

        Returns
        -------
        description : :class:`~openturns.Description`
            Data description.
        """
        return _otagrum.ContinuousTTest_getDataDescription(self)

    @staticmethod
    def GetK(size, dimension):
        r"""
        Static method to compute the bin number of an empirical Bernstein copula.

        Parameters
        ----------
        size : int
            Size of the sample from which the empirical Bernstein copula is extracted.
        dimension : int
            Dimension of the sample from which the empirical Bernstein copula is extracted.

        Returns
        -------
        K : int
            The number of cells into which each dimension of the unit hypercube is divided
            to cluster the empirical copula sample.
        """
        return _otagrum.ContinuousTTest_GetK(size, dimension)
    __swig_destroy__ = _otagrum.delete_ContinuousTTest

# Register ContinuousTTest in _otagrum:
_otagrum.ContinuousTTest_swigregister(ContinuousTTest)

def ContinuousTTest_isIndepFromTest(t, alpha):
    r"""
    Test independence from a given t-test statistics value and a given confidence
    threshold.

    Parameters
    ----------
    t : float
        A value of t-test statistics.
    alpha : float
        A confidence threshold.

    Returns
    -------
    result : tuple
        (t-test, p-value, independent?)
    """
    return _otagrum.ContinuousTTest_isIndepFromTest(t, alpha)

def ContinuousTTest_GetK(size, dimension):
    r"""
    Static method to compute the bin number of an empirical Bernstein copula.

    Parameters
    ----------
    size : int
        Size of the sample from which the empirical Bernstein copula is extracted.
    dimension : int
        Dimension of the sample from which the empirical Bernstein copula is extracted.

    Returns
    -------
    K : int
        The number of cells into which each dimension of the unit hypercube is divided
        to cluster the empirical copula sample.
    """
    return _otagrum.ContinuousTTest_GetK(size, dimension)

class ContinuousPC(openturns.common.Object):
    r"""
    ContinuousPC learner.

    Parameters
    ----------
    data : 2-d sequence of float
        The data
    maxConditioningSetSize : int, optional
        The maximum conditioning set for independecy test
    alpha : float
        Hypothesis test threshold

    Notes
    -----
    PC algorithm is a constrained method allowing to learn the structure of a bayesian
    network. It consists in three steps : skeleton learning, V-structure searching
    and constraint propagation.
    """

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

    def __init__(self, data, maxConditioningSetSize=5, alpha=0.1):
        _otagrum.ContinuousPC_swiginit(self, _otagrum.new_ContinuousPC(data, maxConditioningSetSize, alpha))

    def learnSkeleton(self):
        r"""
        Learn the skeleton.

        Returns
        -------
        gum::UndiGraph : :py:class:`pyAgrum.UndiGraph`
            The learned skeleton

        Notes
        -----
        This step consists in taking the complete undirected graph on the set of variables
        and to remove an edge if the linked variables are independent conditionnaly to
        a subset of their neighbors.
        """
        return _otagrum.ContinuousPC_learnSkeleton(self)

    def learnPDAG(self):
        r"""
        Learn the PDAG.

        Returns
        -------
        gum::MixedGraph : :py:class:`pyAgrum.MixedGraph`
            the learned PDAG

        Notes
        -----
        This step starts with the learned skeleton and looks at each triplet of variables
        X, Y, Z such that X-Z-Y and there is no edge between X and Y. If Z is in the sepset
        of X and Y, that is if it was in the conditional set that allowed to remove the edge
        between X and Y then we orient the triplet as X->Z<-Y.
        """
        return _otagrum.ContinuousPC_learnPDAG(self)

    def learnJunctionTree(self):
        r"""
        Learn the junction tree.

        Returns
        -------
        njt : :class:`~otagrum.NamedJunctionTree`
            the learned junction tree

        Notes
        -----
        In order to learn the junction tree, the PDAG is moralized and then triangulated
        giving an undirected graph. Each clique in this graph is then associated to a
        node in the junction tree and there is an edge between nodes sharing common
        variables. Finally to each edge is associated a separator containing the intersection
        of variables in the two linked nodes.
        """
        return _otagrum.ContinuousPC_learnJunctionTree(self)

    def learnDAG(self):
        r"""
        Learn the DAG.

        Returns
        -------
        dag : :class:`~otagrum.NamedDAG`
            the learned DAG

        Notes
        -----
        This step starts with the learned PDAG and orient the remaining undirected edges
        by avoiding to add new V-structures unless it implies to create an oriented circle.
        """
        return _otagrum.ContinuousPC_learnDAG(self)

    def setVerbosity(self, verbose):
        r"""
        Change the value of verbosity flag. 

        Parameters
        ----------
        verbose : bool
            New verbosity flag value. If True, a lot of details about the learning procedure
            are printed.
        """
        return _otagrum.ContinuousPC_setVerbosity(self, verbose)

    def getVerbosity(self):
        r"""
        Returns the verbosity flag value.

        Returns
        -------
        verbose : bool
            Verbosity flag value
        """
        return _otagrum.ContinuousPC_getVerbosity(self)

    def getSepset(self, x, y):
        r"""
        Separator set indices accessor.

        Parameters
        ----------
        x : int
            Node id
        y : int
            Node id

        Returns
        -------
        sep_set : :py:class:`openturns.Indices`
            Indices of variables in the separator set of variables x and y
        """
        return _otagrum.ContinuousPC_getSepset(self, x, y)

    def getPValue(self, *args):
        r"""
        P-value accessor.

        Parameters
        ----------
        x : str
            A variable's name
        y : str
            A variable's name
        x : int
            A variable's id
        y : int
            A variable's id

        Returns
        -------
        p_value : float
            P-value of edge x - y
        """
        return _otagrum.ContinuousPC_getPValue(self, *args)

    def getTTest(self, *args):
        r"""
        T-Test statistics accessor.

        Parameters
        ----------
        x : str
            A variable's name
        y : str
            A variable's name
        x : int
            A variable's id
        y : int
            A variable's id

        Returns
        -------
        ttest : float
            T-Test statistics value of edge x - y
        """
        return _otagrum.ContinuousPC_getTTest(self, *args)

    def getSepsetNames(self, x, y):
        r"""
        Separator set names accessor.

        Parameters
        ----------
        x : str
            A variable's name
        y : str
            A variables's name

        Returns
        -------
        sepset_names : :py:class:`openturns.Description`
            The names of variables in the separator set of variables x and y
        """
        return _otagrum.ContinuousPC_getSepsetNames(self, x, y)

    def idFromName(self, n):
        r"""
        Id accessor.

        Parameters
        ----------
        n : str
            Node name

        Returns
        -------
        id : int
            Id of the node
        """
        return _otagrum.ContinuousPC_idFromName(self, n)

    def isRemoved(self, *args):
        r"""
        Test if an arc is removed.

        Parameters
        ----------
        x : str
            A variable's name
        y : str
            A variable's name
        x : int
            A variable's id
        y : int
            A variable's id

        Returns
        -------
        removed : bool
            Whether the arc x-y has been removed, this is equivalent to x and y
            being independent
        """
        return _otagrum.ContinuousPC_isRemoved(self, *args)

    def skeletonToDot(self, skeleton):
        r"""
        Displays the skeleton graph to dot

        Parameters
        ----------
        pdag : :py:class:`pyAgrum.UndiGraph`
            dag

        Returns
        -------
        dot : str
            Dot format representation
        """
        return _otagrum.ContinuousPC_skeletonToDot(self, skeleton)

    def PDAGtoDot(self, pdag):
        r"""
        Displays the PDAG in DOT format.

        Parameters
        ----------
        pdag : :py:class:`pyAgrum.MixedGraph`
            dag

        Returns
        -------
        dot : str
            Dot format representation
        """
        return _otagrum.ContinuousPC_PDAGtoDot(self, pdag)

    def getTrace(self):
        r"""
        Returns a summary of the learning algorithm containing which conditional indepences
        have been found and the associated T-test and p-values.

        Returns
        -------
        trace : :py:class:`openturns.Description`
            Trace of the learning algorithm
        """
        return _otagrum.ContinuousPC_getTrace(self)
    __swig_destroy__ = _otagrum.delete_ContinuousPC

# Register ContinuousPC in _otagrum:
_otagrum.ContinuousPC_swigregister(ContinuousPC)

class CorrectedMutualInformation(openturns.common.Object):
    r"""
    CorrectedMutualInformation class.

    Parameters
    ----------
    data : 2-d sequence of float
        The data set.
    """

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

    def __init__(self, data):
        _otagrum.CorrectedMutualInformation_swiginit(self, _otagrum.new_CorrectedMutualInformation(data))

    def setAlpha(self, alpha):
        r"""
        Displays the skeleton graph to dot

        Parameters
        ----------
        pdag : :py:class:`pyAgrum.UndiGraph`
            dag

        Returns
        -------
        dot : str
            Dot format representation
        """
        return _otagrum.CorrectedMutualInformation_setAlpha(self, alpha)

    def getAlpha(self):
        r"""
        Returns the alpha correction value of mutual information when using the Naive KMode.

        Returns
        -------
        alpha : float
            Correction value.
        """
        return _otagrum.CorrectedMutualInformation_getAlpha(self)

    def getSize(self):
        r"""
        Returns the size of the underlying data set.

        Returns
        -------
        size : int
            Size of the data set.
        """
        return _otagrum.CorrectedMutualInformation_getSize(self)

    def getDimension(self):
        r"""
        Returns the dimension of the underlying data set.

        Returns
        -------
        dimension : int
            Dimension of the data set.
        """
        return _otagrum.CorrectedMutualInformation_getDimension(self)

    def getDataDescription(self):
        r"""
        Return the description (variable names) of the underlying data set.

        Returns
        -------
        description : :class:`~openturns.Description`
            Data description.
        """
        return _otagrum.CorrectedMutualInformation_getDataDescription(self)

    def clearCaches(self):
        r"""Clear cache containing the cross-entropies that are used to compute mutual information."""
        return _otagrum.CorrectedMutualInformation_clearCaches(self)

    def compute2PtCorrectedInformation(self, *args):
        r"""
        Return the corrected mutual information between variables X and Y conditionally
        to the variable set U (possibly empty).

        Parameters
        ----------
        X : int
            X node id.
        Y : int
            Y node id.
        U : list
            List of node ids in the (possibly empty) set U

        Returns
        -------
        info : float
            The corrected mutual information I'(X;Y|U).

        Notes
        -----
        The mutual information is computed from the cross-entropy H of the copula using the relation
        I(X;Y|U) = H(X,U) + H(Y,U) - H(X,Y,U) - H(U).
        """
        return _otagrum.CorrectedMutualInformation_compute2PtCorrectedInformation(self, *args)

    def compute3PtCorrectedInformation(self, *args):
        r"""
        Return the corrected three-point information between variables X, Y and Z conditionally
        to the variable set U (possibly empty).

        Parameters
        ----------
        X : int
            X node id.
        Y : int
            Y node id.
        Z : int
            Z node id.
        U : list
            List of node ids in the (possibly empty) set U

        Returns
        -------
        info : float
            The corrected three-point information I'(X;Y;Z|U).

        Notes
        -----
        The three-point information is computed from mutual information using the relation
        I(X;Y;Z|U) = I(X;Y|U) - I(X;Y|U,Z).
        """
        return _otagrum.CorrectedMutualInformation_compute3PtCorrectedInformation(self, *args)
    KModeTypes_NoCorr = _otagrum.CorrectedMutualInformation_KModeTypes_NoCorr
    KModeTypes_Naive = _otagrum.CorrectedMutualInformation_KModeTypes_Naive
    CModeTypes_Gaussian = _otagrum.CorrectedMutualInformation_CModeTypes_Gaussian
    CModeTypes_Bernstein = _otagrum.CorrectedMutualInformation_CModeTypes_Bernstein

    def setKMode(self, kmode):
        r"""
        Change the correction mode for mutual information.

        Parameters
        ----------
        kmode : CorrectedMutualInformation.KModeTypes
            Correction mode (NoCorr or Naive)
        """
        return _otagrum.CorrectedMutualInformation_setKMode(self, kmode)

    def setCMode(self, cmode):
        r"""
        Change the copula model used for computing corrected mutual information.

        Parameters
        ----------
        cmode : CorrectedMutualInformation.CModeTypes
            Copula model (Gaussian or Bernstein).
        """
        return _otagrum.CorrectedMutualInformation_setCMode(self, cmode)

    def getKMode(self):
        return _otagrum.CorrectedMutualInformation_getKMode(self)

    def getCMode(self):
        return _otagrum.CorrectedMutualInformation_getCMode(self)
    __swig_destroy__ = _otagrum.delete_CorrectedMutualInformation

# Register CorrectedMutualInformation in _otagrum:
_otagrum.CorrectedMutualInformation_swigregister(CorrectedMutualInformation)

class GreaterPairOn2nd(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __call__(self, e1, e2):
        return _otagrum.GreaterPairOn2nd___call__(self, e1, e2)

    def __init__(self):
        _otagrum.GreaterPairOn2nd_swiginit(self, _otagrum.new_GreaterPairOn2nd())
    __swig_destroy__ = _otagrum.delete_GreaterPairOn2nd

# Register GreaterPairOn2nd in _otagrum:
_otagrum.GreaterPairOn2nd_swigregister(GreaterPairOn2nd)

class GreaterTupleOnLast(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __call__(self, e1, e2):
        return _otagrum.GreaterTupleOnLast___call__(self, e1, e2)

    def __init__(self):
        _otagrum.GreaterTupleOnLast_swiginit(self, _otagrum.new_GreaterTupleOnLast())
    __swig_destroy__ = _otagrum.delete_GreaterTupleOnLast

# Register GreaterTupleOnLast in _otagrum:
_otagrum.GreaterTupleOnLast_swigregister(GreaterTupleOnLast)

class ContinuousMIIC(openturns.common.Object):
    r"""
    ContinuousMIIC learner.

    Parameters
    ----------
    data : 2-d sequence of float
        The data

    Notes
    -----
    MIIC algorithm is a hybrid method between contrained and score based methods.
    It allows to learn the structure of a bayesian network and consists in three steps :
    skeleton learning, V-structure searching and constraint propagation. These steps
    rely on an information theoretic score.
    """

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

    def __init__(self, data):
        _otagrum.ContinuousMIIC_swiginit(self, _otagrum.new_ContinuousMIIC(data))

    def learnSkeleton(self):
        r"""
        Learn the skeleton from data.

        Returns
        -------
        gum::UndiGraph : :py:class:`pyAgrum.UndiGraph`
            The learned skeleton

        Notes
        -----
        The skeleton is obtained starting from the complete undirected graph on the set of variables
        and removing edges which (corrected) conditional mutual information is negative.
        """
        return _otagrum.ContinuousMIIC_learnSkeleton(self)

    def learnPDAG(self):
        r"""
        Learn the PDAG from data.

        Returns
        -------
        gum::MixedGraph : :py:class:`pyAgrum.MixedGraph`
            the learned PDAG

        Notes
        -----
        Starting with the learned skeleton, each triplet of variables
        X, Y, Z such that X-Z-Y and such that there is no edge between X and Y is oriented
        as X->Z<-Y if its (corrected) three-point conditional information is negative and 
        as X->Z->Y (or X<-Z<-Y) if not.
        """
        return _otagrum.ContinuousMIIC_learnPDAG(self)

    def learnDAG(self):
        r"""
        Learn the DAG from data.

        Returns
        -------
        dag : :class:`~otagrum.NamedDAG`
            the learned DAG

        Notes
        -----
        This step starts with the learned PDAG and orient the remaining undirected edges
        by avoiding to add new V-structures unless it implies to create an oriented circle.
        """
        return _otagrum.ContinuousMIIC_learnDAG(self)

    def getLatentVariables(self):
        r"""
        Latent variables accessor.

        Returns
        --------
        vars : sequence of :py:class:`pyAgrum.Arc`
        """
        return _otagrum.ContinuousMIIC_getLatentVariables(self)

    def addForbiddenArc(self, *args):
        r"""
        The arc will not be added in the learned DAG.

        Parameters
        ----------
        arc : :py:class:`pyAgrum.Arc`
        head : int
            Head node id
        tail : int
            Tail node id
        head : str
            Name of the head node
        tail : str
            Name of the tail node
        """
        return _otagrum.ContinuousMIIC_addForbiddenArc(self, *args)

    def addMandatoryArc(self, *args):
        r"""
        The arc will be added in the learned DAG. This allows to add prior structural
        knowledge.

        Parameters
        ----------
        arc : :py:class:`pyAgrum.Arc`
        head : int
            Head node id
        tail : int
            Tail node id
        head : str
            Name of the head node
        tail : str
            Name of the tail node
        """
        return _otagrum.ContinuousMIIC_addMandatoryArc(self, *args)

    def setCMode(self, cmode):
        r"""
        Change the copula model used for computing corrected mutual information.

        Parameters
        ----------
        cmode : CorrectedMutualInformation.CModeTypes
            Copula model (Gaussian or Bernstein)
        """
        return _otagrum.ContinuousMIIC_setCMode(self, cmode)

    def setKMode(self, kmode):
        r"""
        Change the correction mode for mutual information.

        Parameters
        ----------
        kmode : CorrectedMutualInformation.CModeTypes
            Correction mode (NoCorr or Naive)
        """
        return _otagrum.ContinuousMIIC_setKMode(self, kmode)

    def setVerbosity(self, verbose):
        r"""
        Change the value of verbosity flag. 

        Parameters
        ----------
        verbose : bool
            New verbosity flag value. If True, a lot of details about the learning procedure
            are printed.
        """
        return _otagrum.ContinuousMIIC_setVerbosity(self, verbose)

    def getVerbosity(self):
        r"""
        Returns the verbosity flag value.

        Returns
        -------
        verbose : bool
            Verbosity flag value
        """
        return _otagrum.ContinuousMIIC_getVerbosity(self)

    def setAlpha(self, alpha):
        r"""
        Set the alpha correction value of mutual information when using
        the naive KMode.

        Parameters
        ----------
        alpha : float
            Correction value
        """
        return _otagrum.ContinuousMIIC_setAlpha(self, alpha)

    def getAlpha(self):
        r"""
        Returns the alpha correction value of mutual information when using
        the naive KMode.

        Returns
        -------
        alpha : float
            Correction value
        """
        return _otagrum.ContinuousMIIC_getAlpha(self)
    __swig_destroy__ = _otagrum.delete_ContinuousMIIC

# Register ContinuousMIIC in _otagrum:
_otagrum.ContinuousMIIC_swigregister(ContinuousMIIC)

class TabuList(openturns.common.Object):
    r"""
    TabuList learner.

    Parameters
    ----------
    data : 2-d sequence of float
        The data
    initial_dag: :class:`~otagrum.NamedDAG`
        The Initial DAG for the algorithm
    max_parents : int
        Maximum parents that a node can have
    restarts : int
        Number of random restarts
    tabu_list_size : int
        Size of the TABU list

    Notes
    -----
    The TABU list algorithm is used with the BIC score and Gaussian copulas to learn the 
    structure of a CBN from data. Moreover, it uses the decomposition of BIC score
    to avoid computing score over the entire graph.
    """

    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):
        _otagrum.TabuList_swiginit(self, _otagrum.new_TabuList(*args))

    def setVerbosity(self, verbose):
        r"""
        Change the value of verbosity flag. 

        Parameters
        ----------
        verbose : bool
            New verbosity flag value. If True, a lot of details about the learning procedure
            are printed.
        """
        return _otagrum.TabuList_setVerbosity(self, verbose)

    def getVerbosity(self):
        r"""
        Returns the verbosity flag value.

        Returns
        -------
        verbose : bool
            Verbosity flag value
        """
        return _otagrum.TabuList_getVerbosity(self)

    def setCMode(self, cmode):
        r"""
        Changes the copula model (Bernstein or Gaussian) used for computing the BIC score.

        Returns
        -------
        verbose : CorrectedMutualInformation.CModeTypes
            Copula model (Gaussian or Bernstein)
        """
        return _otagrum.TabuList_setCMode(self, cmode)

    def getMaxParents(self):
        r"""
        Returns the value of the parameter max_parents.

        Returns
        -------
        max_parents : int
            Maximum number of parents
        """
        return _otagrum.TabuList_getMaxParents(self)

    def getRestarts(self):
        r"""
        Returns the value of the parameter restarts.

        Returns
        -------
        restarts : int
            Restarts value
        """
        return _otagrum.TabuList_getRestarts(self)

    def getBestScore(self):
        r"""
        Returns the final score value.

        Returns
        -------
        score : double
            Final score value
        """
        return _otagrum.TabuList_getBestScore(self)

    def learnDAG(self):
        r"""
        Learn the DAG from data.

        Returns
        -------
        dag : :class:`~otagrum.NamedDAG`
            the learned DAG

        Notes
        -----
        This step starts with the learned PDAG and orient the remaining undirected edges
        by avoiding to add new V-structures unless it implies to create an oriented circle.
        """
        return _otagrum.TabuList_learnDAG(self)
    __swig_destroy__ = _otagrum.delete_TabuList

# Register TabuList in _otagrum:
_otagrum.TabuList_swigregister(TabuList)

class ContinuousBayesianNetwork(openturns.model_copula.ContinuousDistribution):
    r"""
    ContinuousBayesianNetwork class represents a continuous bayesian network (CBN),
    that is a bayesian network parameterized by marginal distributions and local
    copulas for each node from which conditional copulas are
    extracted. The scope of each copula is the node and its parents.

    Available constructor:
        ContinuousBayesianNetwork(*dag, marginals, copulas*)

    Parameters
    ----------
    dag : :class:`~otagrum.NamedDAG`
        The structure of the CBN
    marginals : sequence of :py:class:`openturns.Distribution`
        Collection of univariate marginal distributions
    copulas : sequence of :py:class:`openturns.Distribution`
        Collection of local conditional copula functions. The copula is
        unused for nodes with no parents.

    Examples
    --------
    Create a CBN from a DAG structure and a collection of distributions

    >>> import otagrum
    >>> import openturns as ot
    >>> import pyAgrum as gum
    >>> bn = gum.BayesNet.fastPrototype('A->C->B;')
    >>> ndag = otagrum.NamedDAG(bn)
    >>> marginals = [ot.Uniform(0.0, 1.0) for i in range(ndag.getSize())]
    >>> copulas = []
    >>> for i in range(ndag.getSize()):
    ...     dim = 1 + ndag.getParents(i).getSize()
    ...     R = ot.CorrelationMatrix(dim)
    ...     for j in range(dim):
    ...         for k in range(j):
    ...             R[j, k] = 0.8
    ...     copulas.append(ot.Normal([0.0]*dim, [1.0]*dim, R).getCopula())
    >>> cbn = otagrum.ContinuousBayesianNetwork(ndag, marginals, copulas)

    Draw a sample from the joint distribution encoded by the CBN

    >>> sample = cbn.getSample(100)
    """

    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 _otagrum.ContinuousBayesianNetwork_getClassName(self)

    def __eq__(self, *args):
        return _otagrum.ContinuousBayesianNetwork___eq__(self, *args)

    def __repr__(self):
        return _otagrum.ContinuousBayesianNetwork___repr__(self)

    def __str__(self, *args):
        return _otagrum.ContinuousBayesianNetwork___str__(self, *args)

    def getRealization(self):
        r"""
        Accessor to a pseudo-random realization from the distribution.

        Refer to :ref:`distribution_realization`.

        Returns
        -------
        point : :class:`~openturns.Point`
            A pseudo-random realization of the distribution.

        See Also
        --------
        getSample, RandomGenerator
        """
        return _otagrum.ContinuousBayesianNetwork_getRealization(self)

    def computePDF(self, *args):
        r"""
        Compute the probability density function.

        Parameters
        ----------
        X : sequence of float, 2-d sequence of float
            PDF input(s).

        Returns
        -------
        f : float, :class:`~openturns.Point`
            PDF value(s) at input(s) :math:`X`.

        Notes
        -----
        The probability density function is defined as follows:

        .. math::

            f_{\vect{X}}(\vect{x}) = \frac{\partial^n F_{\vect{X}}(\vect{x})}
                                          {\prod_{i=1}^n \partial x_i},
                                     \quad \vect{x} \in \supp{\vect{X}}
        """
        return _otagrum.ContinuousBayesianNetwork_computePDF(self, *args)

    def setDAGAndMarginalsAndCopulas(self, dag, marginals, copulas):
        r"""
        Accessor to the DAG, the marginals and the local copulas collections.

        Parameters
        ----------
        dag : :class:`~otagrum.NamedDAG`
            The underlying NamedDAG
        marginals : sequence of :py:class:`openturns.Distribution`
            The collection of univariate marginal distributions
        copulas : sequence of :py:class:`openturns.Distribution`
            The collection of local conditional copulas
        """
        return _otagrum.ContinuousBayesianNetwork_setDAGAndMarginalsAndCopulas(self, dag, marginals, copulas)

    def getNamedDAG(self):
        r"""
        The CBN structure.

        Returns
        -------
        dag : :class:`~otagrum.NamedDAG`
            The underlying NamedDAG
        """
        return _otagrum.ContinuousBayesianNetwork_getNamedDAG(self)

    def getMarginals(self):
        r"""
        The collection of univariate marginal distributions.

        Returns
        -------
        marginals : sequence of :py:class:`openturns.Distribution`
            Collection of univariate marginal distributions

        """
        return _otagrum.ContinuousBayesianNetwork_getMarginals(self)

    def getCopulas(self):
        r"""
        The collection of local conditional copulas.

        Returns
        -------
        copulas : sequence of :py:class:`openturns.Distribution`
            Collection of local conditional copulas

        """
        return _otagrum.ContinuousBayesianNetwork_getCopulas(self)

    def __init__(self, *args):
        _otagrum.ContinuousBayesianNetwork_swiginit(self, _otagrum.new_ContinuousBayesianNetwork(*args))
    __swig_destroy__ = _otagrum.delete_ContinuousBayesianNetwork

# Register ContinuousBayesianNetwork in _otagrum:
_otagrum.ContinuousBayesianNetwork_swigregister(ContinuousBayesianNetwork)

class ContinuousBayesianNetworkFactory(openturns.model_copula.DistributionFactoryImplementation):
    r"""
    Estimate a ContinuousBayesianNetwork distribution.

    Parameters
    ----------
    marginalsFactory : :class:`~openturns.DistributionFactory`
        The model used to estimate each univariate marginal distribution. Default value is
        :class:`~openturns.HistogramFactory`.
    copulasFactory : :class:`~openturns.DistributionFactory`
        The model used to estimate each local conditional copula. Default value is
        :class:`~openturns.BernsteinCopulaFactory`.
    namedDAG : :class:`~otagrum.NamedDAG`
        The structure of the underlying graphical model. Default value is
        :class:`~otagrum.NamedDAG()`
    alpha : float
        Threshold on the p-value for the conditional independence tests. Default
        value is *0.1*.
    maximumConditioningSetSize : int
        Maximum conditional set size. Default value is *5*.

    Notes
    -----
        A *namedDAG* parameter of size 0 (ie equal to NamedDAG(), default value) means
        that the structure has also to be learnt, using the
        :class:`~otagrum.ContinuousPC` algorithm.
        The parameters *alpha* and *maximumConditioningSetSize* are used only if the
        :class:`~otagrum.NamedDAG` has to be learnt.
        The following keys in :class:`~openturns.ResourceMap` can be used to fine-tune
        the learning process:

        - *'ContinuousBayesianNetworkFactory-DefaultAlpha'* to set the p-value
          threshold for the independence test in :class:`~otagrum.ContinuousPC`.
          Default value is *0.1*.
        - *'ContinuousBayesianNetworkFactory-DefaultMaximumConditioningSetSize'*
          to set the maximum dimension of the parents in the Bayesian network.
          Default value is *5*.
        - *'ContinuousBayesianNetworkFactory-WorkInCopulaSpace'* to indicate if the
          estimated distribution should be a copula. Default value is *True*
        - *'ContinuousBayesianNetworkFactory-LearningRatio'* to set the proportion of
          the given sample to be used for the learning phase. Default value is *0.5*.

    Examples
    --------
    >>> import otagrum
    >>> import openturns as ot
    >>> marginalsFactory = ot.NormalFactory()
    >>> copulasFactory = ot.NormalCopulaFactory()
    >>> ndag = otagrum.NamedDAG()
    >>> threshold = 0.1
    >>> maxParents = 5
    >>> factory = otagrum.ContinuousBayesianNetworkFactory(marginalsFactory, copulasFactory, ndag, threshold, maxParents)
    """

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

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

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

    def build(self, *args):
        r"""
        Build the distribution.

        **Available usages**:

            build(*sample*)

            build(*param*)

        Parameters
        ----------
        sample : 2-d sequence of float
            Sample from which the distribution parameters are estimated.
        param : Collection of :class:`~openturns.PointWithDescription`
            A vector of parameters of the distribution.

        Returns
        -------
        dist : :class:`~openturns.Distribution`
            The built distribution.
        """
        return _otagrum.ContinuousBayesianNetworkFactory_build(self, *args)

    def buildAsContinuousBayesianNetwork(self, *args):
        r"""
        Build as ContinuousBayesianNetwork distribution.

        Parameters
        ----------
        sample : :py:class:`openturns.Sample`
            Input sample.

        Returns
        -------
        distribution : :class:`~otagrum.ContinuousBayesianNetwork`
            Estimated distribution.
        """
        return _otagrum.ContinuousBayesianNetworkFactory_buildAsContinuousBayesianNetwork(self, *args)

    def __init__(self, *args):
        _otagrum.ContinuousBayesianNetworkFactory_swiginit(self, _otagrum.new_ContinuousBayesianNetworkFactory(*args))
    __swig_destroy__ = _otagrum.delete_ContinuousBayesianNetworkFactory

# Register ContinuousBayesianNetworkFactory in _otagrum:
_otagrum.ContinuousBayesianNetworkFactory_swigregister(ContinuousBayesianNetworkFactory)



