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

"""pyAgrum is a scientific C++ and Python library dedicated to Bayesian Networks and other Probabilistic Graphical Models.  It provides a high-level interface to the part of the C++ aGrUM library allowing to create, model, learn, use, calculate with and embed Bayesian Networks and other graphical models. Some specific (python and C++) codes are added in order to simplify and extend the aGrUM API. The module is mainly generated by the SWIG interface generator."""

from sys import version_info as _swig_python_version_info
if _swig_python_version_info < (3, 0):
    raise RuntimeError("Python 3.x or later required")

## added by passForType (pyAgrum)
from typing import List,Set,Dict,Tuple
## end of added by passForType (pyAgrum)

## added by passForType (pyAgrum)
from typing import List,Set,Dict,Tuple
## end of added by passForType (pyAgrum)

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

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 weakref

class SwigPyIterator(object):
    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_SwigPyIterator

    def value(self) -> object:
        return _pyAgrum.SwigPyIterator_value(self)

    def incr(self, n: int=1) -> "swig::SwigPyIterator *":
        return _pyAgrum.SwigPyIterator_incr(self, n)

    def decr(self, n: int=1) -> "swig::SwigPyIterator *":
        return _pyAgrum.SwigPyIterator_decr(self, n)

    def distance(self, x: "SwigPyIterator") -> "ptrdiff_t":
        return _pyAgrum.SwigPyIterator_distance(self, x)

    def equal(self, x: "SwigPyIterator") -> bool:
        return _pyAgrum.SwigPyIterator_equal(self, x)

    def copy(self) -> "swig::SwigPyIterator *":
        return _pyAgrum.SwigPyIterator_copy(self)

    def next(self) -> object:
        return _pyAgrum.SwigPyIterator_next(self)

    def __next__(self) -> object:
        return _pyAgrum.SwigPyIterator___next__(self)

    def previous(self) -> object:
        return _pyAgrum.SwigPyIterator_previous(self)

    def advance(self, n: "ptrdiff_t") -> "swig::SwigPyIterator *":
        return _pyAgrum.SwigPyIterator_advance(self, n)

    def __eq__(self, x: "SwigPyIterator") -> bool:
        return _pyAgrum.SwigPyIterator___eq__(self, x)

    def __ne__(self, x: "SwigPyIterator") -> bool:
        return _pyAgrum.SwigPyIterator___ne__(self, x)

    def __iadd__(self, n: "ptrdiff_t") -> "swig::SwigPyIterator &":
        return _pyAgrum.SwigPyIterator___iadd__(self, n)

    def __isub__(self, n: "ptrdiff_t") -> "swig::SwigPyIterator &":
        return _pyAgrum.SwigPyIterator___isub__(self, n)

    def __add__(self, n: "ptrdiff_t") -> "swig::SwigPyIterator *":
        return _pyAgrum.SwigPyIterator___add__(self, n)

    def __sub__(self, *args) -> "ptrdiff_t":
        return _pyAgrum.SwigPyIterator___sub__(self, *args)
    def __iter__(self):
        return self

# Register SwigPyIterator in _pyAgrum:
_pyAgrum.SwigPyIterator_swigregister(SwigPyIterator)


import numpy
from numbers import Number

class JunctionTreeGenerator(object):
    r"""

    JunctionTreeGenerator is use to generate junction tree or binary junction tree from Bayesian networks.

    JunctionTreeGenerator() -> JunctionTreeGenerator
        default constructor

    """

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

    def junctionTree(self, *args) -> "pyAgrum.JunctionTree":
        r"""

        Computes the junction tree for its parameters. If the first parameter is a graph, the heurisitcs assume that all the node have the same domain size (2). If given, the heuristic takes into account the partial order for its elimination order.

        Parameters
        ----------
        g : pyAgrum.UndiGraph
        	a undirected graph

        dag : pyAgrum.DAG
        	a dag

        bn : pyAgrum.BayesNet
        	a BayesianNetwork

        partial_order: List[List[int]]
        	a partial order among the nodeIDs

        Returns
        -------
        pyAgrum.CliqueGraph
        	the current junction tree. 

        """
        return _pyAgrum.JunctionTreeGenerator_junctionTree(self, *args)

    def eliminationOrder(self, *args) -> object:
        r"""

        Computes the elimination for its parameters. If the first parameter is a graph, the heurisitcs assume that all the node have the same domain size (2). If given, the heuristic takes into account the partial order for its elimination order.

        Parameters
        ----------
        g : pyAgrum.UndiGraph
        	a undirected graph

        dag : pyAgrum.DAG
        	a dag

        bn : pyAgrum.BayesNet
        	a BayesianNetwork

        partial_order: List[List[int]]
        	a partial order among the nodeIDs

        Returns
        -------
        pyAgrum.CliqueGraph
        	the current elimination order.

        """
        return _pyAgrum.JunctionTreeGenerator_eliminationOrder(self, *args)

    def binaryJoinTree(self, *args) -> "pyAgrum.JunctionTree":
        r"""

        Computes the binary joint tree for its parameters. If the first parameter is a graph, the heurisitcs assume that all the node have the same domain size (2). If given, the heuristic takes into account the partial order for its elimination order.

        Parameters
        ----------
        g : pyAgrum.UndiGraph
        	a undirected graph

        dag : pyAgrum.DAG
        	a dag

        bn : pyAgrum.BayesNet
        	a BayesianNetwork

        partial_order: List[List[int]]
        	a partial order among the nodeIDs

        Returns
        -------
        pyAgrum.CliqueGraph
        	the current binary joint tree 

        """
        return _pyAgrum.JunctionTreeGenerator_binaryJoinTree(self, *args)

    def __init__(self):
        r"""

        JunctionTreeGenerator is use to generate junction tree or binary junction tree from Bayesian networks.

        JunctionTreeGenerator() -> JunctionTreeGenerator
            default constructor

        """
        _pyAgrum.JunctionTreeGenerator_swiginit(self, _pyAgrum.new_JunctionTreeGenerator())
    __swig_destroy__ = _pyAgrum.delete_JunctionTreeGenerator

# Register JunctionTreeGenerator in _pyAgrum:
_pyAgrum.JunctionTreeGenerator_swigregister(JunctionTreeGenerator)

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

    def __init__(self, bn: "pyAgrum.BayesNet", vnm: "pyAgrum.VariableNodeMap"):
        _pyAgrum.PythonBNListener_swiginit(self, _pyAgrum.new_PythonBNListener(bn, vnm))
    __swig_destroy__ = _pyAgrum.delete_PythonBNListener

    def whenNodeAdded(self, source: object, id: int) -> None:
        return _pyAgrum.PythonBNListener_whenNodeAdded(self, source, id)

    def whenNodeDeleted(self, arg2: object, id: int) -> None:
        return _pyAgrum.PythonBNListener_whenNodeDeleted(self, arg2, id)

    def whenArcAdded(self, arg2: object, src: int, dst: int) -> None:
        return _pyAgrum.PythonBNListener_whenArcAdded(self, arg2, src, dst)

    def whenArcDeleted(self, arg2: object, src: int, dst: int) -> None:
        return _pyAgrum.PythonBNListener_whenArcDeleted(self, arg2, src, dst)

    def setWhenArcAdded(self, pyfunc: object) -> None:
        r"""



        """
        return _pyAgrum.PythonBNListener_setWhenArcAdded(self, pyfunc)

    def setWhenArcDeleted(self, pyfunc: object) -> None:
        r"""



        """
        return _pyAgrum.PythonBNListener_setWhenArcDeleted(self, pyfunc)

    def setWhenNodeAdded(self, pyfunc: object) -> None:
        r"""



        """
        return _pyAgrum.PythonBNListener_setWhenNodeAdded(self, pyfunc)

    def setWhenNodeDeleted(self, pyfunc: object) -> None:
        r"""



        """
        return _pyAgrum.PythonBNListener_setWhenNodeDeleted(self, pyfunc)

# Register PythonBNListener in _pyAgrum:
_pyAgrum.PythonBNListener_swigregister(PythonBNListener)

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

    def whenLoading(self, buffer: object, percent: int) -> None:
        return _pyAgrum.PythonLoadListener_whenLoading(self, buffer, percent)

    def setPythonListener(self, l: object) -> bool:
        r"""



        """
        return _pyAgrum.PythonLoadListener_setPythonListener(self, l)

    def __init__(self):
        _pyAgrum.PythonLoadListener_swiginit(self, _pyAgrum.new_PythonLoadListener())
    __swig_destroy__ = _pyAgrum.delete_PythonLoadListener

# Register PythonLoadListener in _pyAgrum:
_pyAgrum.PythonLoadListener_swigregister(PythonLoadListener)


def _fillLoadListeners_(py_listener: List["pyAgrum.PythonLoadListener"], l: object) -> int:
    return _pyAgrum._fillLoadListeners_(py_listener, l)
class PythonApproximationListener(object):
    r"""

    Parameters
    ----------
    algo : IApproximationSchemeConfiguration
    	an approxmation scheme

    """

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

    def __init__(self, algo: "IApproximationSchemeConfiguration"):
        r"""

        Parameters
        ----------
        algo : IApproximationSchemeConfiguration
        	an approxmation scheme

        """
        _pyAgrum.PythonApproximationListener_swiginit(self, _pyAgrum.new_PythonApproximationListener(algo))
    __swig_destroy__ = _pyAgrum.delete_PythonApproximationListener

    def whenProgress(self, src: object, step: int, error: float, duration: float) -> None:
        return _pyAgrum.PythonApproximationListener_whenProgress(self, src, step, error, duration)

    def whenStop(self, src: object, message: str) -> None:
        return _pyAgrum.PythonApproximationListener_whenStop(self, src, message)

    def setWhenProgress(self, pyfunc: object) -> None:
        r"""

        Parameters
        ----------
        pyfunc
        	the function to execute

        """
        return _pyAgrum.PythonApproximationListener_setWhenProgress(self, pyfunc)

    def setWhenStop(self, pyfunc: object) -> None:
        r"""

        Parameters
        ----------
        pyfunc
        	the function to execute

        """
        return _pyAgrum.PythonApproximationListener_setWhenStop(self, pyfunc)

# Register PythonApproximationListener in _pyAgrum:
_pyAgrum.PythonApproximationListener_swigregister(PythonApproximationListener)

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

    def __init__(self, notif: "BNDatabaseGenerator"):
        _pyAgrum.PythonDatabaseGeneratorListener_swiginit(self, _pyAgrum.new_PythonDatabaseGeneratorListener(notif))
    __swig_destroy__ = _pyAgrum.delete_PythonDatabaseGeneratorListener

    def whenProgress(self, src: object, step: int, duration: float) -> None:
        return _pyAgrum.PythonDatabaseGeneratorListener_whenProgress(self, src, step, duration)

    def whenStop(self, src: object, message: str) -> None:
        return _pyAgrum.PythonDatabaseGeneratorListener_whenStop(self, src, message)

    def setWhenProgress(self, pyfunc: object) -> None:
        return _pyAgrum.PythonDatabaseGeneratorListener_setWhenProgress(self, pyfunc)

    def setWhenStop(self, pyfunc: object) -> None:
        return _pyAgrum.PythonDatabaseGeneratorListener_setWhenStop(self, pyfunc)

# Register PythonDatabaseGeneratorListener in _pyAgrum:
_pyAgrum.PythonDatabaseGeneratorListener_swigregister(PythonDatabaseGeneratorListener)

class BNGenerator(object):
    r"""

    BNGenerator is used to easily generate Bayesian networks.

    BNGenerator() -> BNGenerator
        default constructor

    """

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

    def generate(self, n_nodes: int=10, n_arcs: int=15, n_modmax: int=4) -> "pyAgrum.BayesNet":
        r"""

        Generate a new Bayesian network 

        Parameters
        ----------
        n_nodes : int
        	the number of nodes (default=10)
        n_arcs : int
        	the number of arcs (default=15)
        n_nodmax : int
        	the max number of modalities for a node (default=4)

        Returns
        -------
        pyAgrum.BayesNet
        	the generated Bayesian network

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If n_modmax < 2
        pyAgrum.OperationNotAllowed
        	If n_arcs is incompatible with n_nodes (not enough arcs)

        """
        return _pyAgrum.BNGenerator_generate(self, n_nodes, n_arcs, n_modmax)

    def __init__(self):
        r"""

        BNGenerator is used to easily generate Bayesian networks.

        BNGenerator() -> BNGenerator
            default constructor

        """
        _pyAgrum.BNGenerator_swiginit(self, _pyAgrum.new_BNGenerator())
    __swig_destroy__ = _pyAgrum.delete_BNGenerator

# Register BNGenerator in _pyAgrum:
_pyAgrum.BNGenerator_swigregister(BNGenerator)

class IDGenerator(object):
    r"""

    IDGenerator is used to easily generate influence diagrams.

    IDGenerator() -> IDGenerator
        default constructor

    """

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

    def generate(self, nbrNodes: int=10, arcDensity: float=0.2, chanceNodeDensity: float=0.8, utilityNodeDensity: float=0.1, max_modality: int=2) -> "pyAgrum.InfluenceDiagram":
        r"""

        Generate a new influence diagram given the parameters.

        Parameters
        ----------
        nbrNodes : int
        	the number of node
        arcDensity : float
        	the density of arc (1 for a complete graph)
        chanceNodeDensity : float
        	the density of chance node
        utilityNodeDensity : float
        	the density of utility node
        max_modality : int
        	the maximum value for modalities

        Returns
        -------
        pyAgrum.InfluenceDiagram
        	the generated influence diagram

        """
        return _pyAgrum.IDGenerator_generate(self, nbrNodes, arcDensity, chanceNodeDensity, utilityNodeDensity, max_modality)

    def __init__(self):
        r"""

        IDGenerator is used to easily generate influence diagrams.

        IDGenerator() -> IDGenerator
            default constructor

        """
        _pyAgrum.IDGenerator_swiginit(self, _pyAgrum.new_IDGenerator())
    __swig_destroy__ = _pyAgrum.delete_IDGenerator

# Register IDGenerator in _pyAgrum:
_pyAgrum.IDGenerator_swigregister(IDGenerator)

class PRMexplorer(object):
    r"""

    PRMexplorer helps navigate through probabilistic relational models.

    PRMexplorer() -> PRMexplorer
        default constructor

    """

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

    def __init__(self):
        r"""

        PRMexplorer helps navigate through probabilistic relational models.

        PRMexplorer() -> PRMexplorer
            default constructor

        """
        _pyAgrum.PRMexplorer_swiginit(self, _pyAgrum.new_PRMexplorer())
    __swig_destroy__ = _pyAgrum.delete_PRMexplorer

    def load(self, *args) -> None:
        r"""

        Load a PRM into the explorer.

        Parameters
        ----------
        filename : str
        	the name of the o3prm file
        classpath : str
        	the classpath of the PRM

        Raises
        ------
        pyAgrum.FatalError
        	If file not found

        """
        return _pyAgrum.PRMexplorer_load(self, *args)

    def isType(self, name: str) -> object:
        r"""

        Parameters
        ----------
        name : str
        	an element name

        Returns
        -------
        bool
        	True if the parameter correspond to a type in the PRM

        """
        return _pyAgrum.PRMexplorer_isType(self, name)

    def isClass(self, name: str) -> object:
        r"""

        Parameters
        ----------
        name : str
        	an element name

        Returns
        -------
        bool
        	True if the parameter correspond to a class in the PRM

        """
        return _pyAgrum.PRMexplorer_isClass(self, name)

    def isInterface(self, name: str) -> object:
        r"""

        Parameters
        ----------
        name : str
        	an element name

        Returns
        -------
        bool
        	True if the parameter correspond to an interface in the PRM

        """
        return _pyAgrum.PRMexplorer_isInterface(self, name)

    def classes(self) -> object:
        r"""

        Returns
        -------
        list
        	the list of classes

        """
        return _pyAgrum.PRMexplorer_classes(self)

    def classAttributes(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of attributes

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_classAttributes(self, class_name)

    def isAttribute(self, class_name: str, att_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name
        att_name : str
        	the name of the attribute to be tested

        Returns
        -------
        bool
        	True if att_name is an attribute of class_name

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM
        pyAgrum.IndexError
        	If att_name is not an element of class_name

        """
        return _pyAgrum.PRMexplorer_isAttribute(self, class_name, att_name)

    def classReferences(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of references

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_classReferences(self, class_name)

    def classParameters(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of parameters

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_classParameters(self, class_name)

    def classImplements(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of interfaces implemented by the class

        """
        return _pyAgrum.PRMexplorer_classImplements(self, class_name)
    aggType = property(_pyAgrum.PRMexplorer_aggType_get, _pyAgrum.PRMexplorer_aggType_set, doc=r"""

    min/max/count/exists/forall/or/and/amplitude/median

    """)

    def classAggregates(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of aggregates in the class

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_classAggregates(self, class_name)

    def classSlotChains(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of class slot chains

        Raises
        ------
        pyAgrum.IndexError
        	if the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_classSlotChains(self, class_name)

    def classDag(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        tuple
        	a description of the DAG

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_classDag(self, class_name)

    def getalltheSystems(self) -> object:
        r"""

        Returns
        -------
        list
        	the list of all the systems and their components

        """
        return _pyAgrum.PRMexplorer_getalltheSystems(self)

    def getSuperClass(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        str
        	the class extended by class_name

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getSuperClass(self, class_name)

    def getDirectSubClass(self, class_name: str) -> object:
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        Returns
        -------
        list
        	the list of direct subclasses

        Raises
        ------
        pyAgrum.IndexError
        	If the class is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getDirectSubClass(self, class_name)

    def cpf(self, class_name: str, attribute: str) -> "pyAgrum.Potential":
        r"""

        Parameters
        ----------
        class_name : str
        	a class name

        attribute : str
        	an attribute

        Returns
        -------
        pyAgrum.Potential
        	the potential of the attribute

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the class element doesn't have any pyAgrum.Potential (like a gum::PRMReferenceSlot). 
        pyAgrum.IndexError
        	If the class is not in the PRM
        pyAgrum.IndexError
        	If the attribute in parameters does not exist 

        """
        return _pyAgrum.PRMexplorer_cpf(self, class_name, attribute)

    def types(self) -> object:
        r"""

        Returns
        -------
        list
        	the list of the custom types in the PRM 

        """
        return _pyAgrum.PRMexplorer_types(self)

    def getSuperType(self, type_name: str) -> object:
        r"""

        Parameters
        ----------
        type_name : str
        	a type name

        Returns
        -------
        str
        	the type extended by type_name

        Raises
        ------
        pyAgrum.IndexError
        	If the type is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getSuperType(self, type_name)

    def getDirectSubTypes(self, type_name: str) -> object:
        r"""

        Parameters
        ----------
        type_name : str
        	a type name

        Returns
        -------
        list
        	the list of direct subtypes

        Raises
        ------
        pyAgrum.IndexError
        	If the type is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getDirectSubTypes(self, type_name)

    def getLabels(self, type_name: str) -> object:
        r"""

        Parameters
        ----------
        type_name : str
        	a type name

        Returns
        -------
        list
        	the list of type labels

        Raises
        ------
        pyAgrum.IndexError
        	If the type is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getLabels(self, type_name)

    def getLabelMap(self, type_name: str) -> object:
        r"""

        Parameters
        ----------
        type_name : str
        	a type name

        Returns
        -------
        dict
        	a dict containing pairs of label and their values 

        Raises
        ------
        pyAgrum.IndexError
        	If the type is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getLabelMap(self, type_name)

    def interfaces(self) -> object:
        r"""

        Returns
        -------
        list
        	the list of interfaces in the PRM 

        """
        return _pyAgrum.PRMexplorer_interfaces(self)

    def interAttributes(self, interface_name: str, allAttributes: bool=False) -> object:
        r"""

        Parameters
        ----------
        interface_name : str
        	an interface

        allAttributes : bool
        	True if supertypes of a custom type should be indicated

        Returns
        -------
        list
        	the list of (<type>,<attribute_name>) for the given interface

        Raises
        ------
        pyAgrum.IndexError
        	If the type is not in the PRM

        """
        return _pyAgrum.PRMexplorer_interAttributes(self, interface_name, allAttributes)

    def interReferences(self, interface_name: str) -> object:
        r"""

        Parameters
        ----------
        interface_name : str
        	an interface

        Returns
        -------
        list
        	the list of (<reference_type>,<reference_name>,<True if the reference is an array>) for the given interface

        Raises
        ------
        pyAgrum.IndexError
        	If the type is not in the PRM

        """
        return _pyAgrum.PRMexplorer_interReferences(self, interface_name)

    def getSuperInterface(self, interface_name: str) -> object:
        r"""

        Parameters
        ----------
        interface_name : str
        	an interface name

        Returns
        -------
        str
        	the interace extended by interface_name

        Raises
        ------
        pyAgrum.IndexError
        	If the interface is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getSuperInterface(self, interface_name)

    def getDirectSubInterfaces(self, interface_name: str) -> object:
        r"""

        Parameters
        ----------
        interface_name : str
        	an interface name

        Returns
        -------
        list
        	the list of direct subinterfaces

        Raises
        ------
        pyAgrum.IndexError
        	If the interface is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getDirectSubInterfaces(self, interface_name)

    def getImplementations(self, interface_name: str) -> object:
        r"""

        Parameters
        ----------
        interface_name : str
        	an interface name

        Returns
        -------
        str
        	the list of classes implementing the interface 

        Raises
        ------
        pyAgrum.IndexError
        	If the interface is not in the PRM

        """
        return _pyAgrum.PRMexplorer_getImplementations(self, interface_name)

# Register PRMexplorer in _pyAgrum:
_pyAgrum.PRMexplorer_swigregister(PRMexplorer)

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

    def iterator(self) -> "swig::SwigPyIterator *":
        return _pyAgrum.Vector_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self) -> bool:
        return _pyAgrum.Vector___nonzero__(self)

    def __bool__(self) -> bool:
        return _pyAgrum.Vector___bool__(self)

    def __len__(self) -> int:
        return _pyAgrum.Vector___len__(self)

    def __getslice__(self, i: int, j: int) -> List[float]:
        return _pyAgrum.Vector___getslice__(self, i, j)

    def __setslice__(self, *args) -> None:
        return _pyAgrum.Vector___setslice__(self, *args)

    def __delslice__(self, i: int, j: int) -> None:
        return _pyAgrum.Vector___delslice__(self, i, j)

    def __delitem__(self, *args) -> None:
        return _pyAgrum.Vector___delitem__(self, *args)

    def __getitem__(self, *args) -> float:
        return _pyAgrum.Vector___getitem__(self, *args)

    def __setitem__(self, *args) -> None:
        return _pyAgrum.Vector___setitem__(self, *args)

    def pop(self) -> float:
        return _pyAgrum.Vector_pop(self)

    def append(self, x: float) -> None:
        return _pyAgrum.Vector_append(self, x)

    def empty(self) -> bool:
        return _pyAgrum.Vector_empty(self)

    def size(self) -> int:
        return _pyAgrum.Vector_size(self)

    def swap(self, v: "Vector") -> None:
        return _pyAgrum.Vector_swap(self, v)

    def begin(self) -> "std::vector< double >::iterator":
        return _pyAgrum.Vector_begin(self)

    def end(self) -> "std::vector< double >::iterator":
        return _pyAgrum.Vector_end(self)

    def rbegin(self) -> "std::vector< double >::reverse_iterator":
        return _pyAgrum.Vector_rbegin(self)

    def rend(self) -> "std::vector< double >::reverse_iterator":
        return _pyAgrum.Vector_rend(self)

    def clear(self) -> None:
        return _pyAgrum.Vector_clear(self)

    def get_allocator(self) -> "std::vector< double >::allocator_type":
        return _pyAgrum.Vector_get_allocator(self)

    def pop_back(self) -> None:
        return _pyAgrum.Vector_pop_back(self)

    def erase(self, *args) -> "std::vector< double >::iterator":
        return _pyAgrum.Vector_erase(self, *args)

    def __init__(self, *args):
        _pyAgrum.Vector_swiginit(self, _pyAgrum.new_Vector(*args))

    def push_back(self, x: float) -> None:
        return _pyAgrum.Vector_push_back(self, x)

    def front(self) -> float:
        return _pyAgrum.Vector_front(self)

    def back(self) -> float:
        return _pyAgrum.Vector_back(self)

    def assign(self, n: int, x: float) -> None:
        return _pyAgrum.Vector_assign(self, n, x)

    def resize(self, *args) -> None:
        return _pyAgrum.Vector_resize(self, *args)

    def insert(self, *args) -> None:
        return _pyAgrum.Vector_insert(self, *args)

    def reserve(self, n: int) -> None:
        return _pyAgrum.Vector_reserve(self, n)

    def capacity(self) -> int:
        return _pyAgrum.Vector_capacity(self)
    __swig_destroy__ = _pyAgrum.delete_Vector

# Register Vector in _pyAgrum:
_pyAgrum.Vector_swigregister(Vector)

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

    def iterator(self) -> "swig::SwigPyIterator *":
        return _pyAgrum.Vector_int_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self) -> bool:
        return _pyAgrum.Vector_int___nonzero__(self)

    def __bool__(self) -> bool:
        return _pyAgrum.Vector_int___bool__(self)

    def __len__(self) -> int:
        return _pyAgrum.Vector_int___len__(self)

    def __getslice__(self, i: int, j: int) -> List[int]:
        return _pyAgrum.Vector_int___getslice__(self, i, j)

    def __setslice__(self, *args) -> None:
        return _pyAgrum.Vector_int___setslice__(self, *args)

    def __delslice__(self, i: int, j: int) -> None:
        return _pyAgrum.Vector_int___delslice__(self, i, j)

    def __delitem__(self, *args) -> None:
        return _pyAgrum.Vector_int___delitem__(self, *args)

    def __getitem__(self, *args) -> int:
        return _pyAgrum.Vector_int___getitem__(self, *args)

    def __setitem__(self, *args) -> None:
        return _pyAgrum.Vector_int___setitem__(self, *args)

    def pop(self) -> int:
        return _pyAgrum.Vector_int_pop(self)

    def append(self, x: int) -> None:
        return _pyAgrum.Vector_int_append(self, x)

    def empty(self) -> bool:
        return _pyAgrum.Vector_int_empty(self)

    def size(self) -> int:
        return _pyAgrum.Vector_int_size(self)

    def swap(self, v: "Vector_int") -> None:
        return _pyAgrum.Vector_int_swap(self, v)

    def begin(self) -> "std::vector< int >::iterator":
        return _pyAgrum.Vector_int_begin(self)

    def end(self) -> "std::vector< int >::iterator":
        return _pyAgrum.Vector_int_end(self)

    def rbegin(self) -> "std::vector< int >::reverse_iterator":
        return _pyAgrum.Vector_int_rbegin(self)

    def rend(self) -> "std::vector< int >::reverse_iterator":
        return _pyAgrum.Vector_int_rend(self)

    def clear(self) -> None:
        return _pyAgrum.Vector_int_clear(self)

    def get_allocator(self) -> "std::vector< int >::allocator_type":
        return _pyAgrum.Vector_int_get_allocator(self)

    def pop_back(self) -> None:
        return _pyAgrum.Vector_int_pop_back(self)

    def erase(self, *args) -> "std::vector< int >::iterator":
        return _pyAgrum.Vector_int_erase(self, *args)

    def __init__(self, *args):
        _pyAgrum.Vector_int_swiginit(self, _pyAgrum.new_Vector_int(*args))

    def push_back(self, x: int) -> None:
        return _pyAgrum.Vector_int_push_back(self, x)

    def front(self) -> int:
        return _pyAgrum.Vector_int_front(self)

    def back(self) -> int:
        return _pyAgrum.Vector_int_back(self)

    def assign(self, n: int, x: int) -> None:
        return _pyAgrum.Vector_int_assign(self, n, x)

    def resize(self, *args) -> None:
        return _pyAgrum.Vector_int_resize(self, *args)

    def insert(self, *args) -> None:
        return _pyAgrum.Vector_int_insert(self, *args)

    def reserve(self, n: int) -> None:
        return _pyAgrum.Vector_int_reserve(self, n)

    def capacity(self) -> int:
        return _pyAgrum.Vector_int_capacity(self)
    __swig_destroy__ = _pyAgrum.delete_Vector_int

# Register Vector_int in _pyAgrum:
_pyAgrum.Vector_int_swigregister(Vector_int)

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

    def iterator(self) -> "swig::SwigPyIterator *":
        return _pyAgrum.Vector_string_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self) -> bool:
        return _pyAgrum.Vector_string___nonzero__(self)

    def __bool__(self) -> bool:
        return _pyAgrum.Vector_string___bool__(self)

    def __len__(self) -> "std::vector< str >::size_type":
        return _pyAgrum.Vector_string___len__(self)

    def __getslice__(self, i: "std::vector< str >::difference_type", j: "std::vector< str >::difference_type") -> List[str]:
        return _pyAgrum.Vector_string___getslice__(self, i, j)

    def __setslice__(self, *args) -> None:
        return _pyAgrum.Vector_string___setslice__(self, *args)

    def __delslice__(self, i: "std::vector< str >::difference_type", j: "std::vector< str >::difference_type") -> None:
        return _pyAgrum.Vector_string___delslice__(self, i, j)

    def __delitem__(self, *args) -> None:
        return _pyAgrum.Vector_string___delitem__(self, *args)

    def __getitem__(self, *args) -> str:
        return _pyAgrum.Vector_string___getitem__(self, *args)

    def __setitem__(self, *args) -> None:
        return _pyAgrum.Vector_string___setitem__(self, *args)

    def pop(self) -> str:
        return _pyAgrum.Vector_string_pop(self)

    def append(self, x: str) -> None:
        return _pyAgrum.Vector_string_append(self, x)

    def empty(self) -> bool:
        return _pyAgrum.Vector_string_empty(self)

    def size(self) -> "std::vector< str >::size_type":
        return _pyAgrum.Vector_string_size(self)

    def swap(self, v: "Vector_string") -> None:
        return _pyAgrum.Vector_string_swap(self, v)

    def begin(self) -> "std::vector< str >::iterator":
        return _pyAgrum.Vector_string_begin(self)

    def end(self) -> "std::vector< str >::iterator":
        return _pyAgrum.Vector_string_end(self)

    def rbegin(self) -> "std::vector< str >::reverse_iterator":
        return _pyAgrum.Vector_string_rbegin(self)

    def rend(self) -> "std::vector< str >::reverse_iterator":
        return _pyAgrum.Vector_string_rend(self)

    def clear(self) -> None:
        return _pyAgrum.Vector_string_clear(self)

    def get_allocator(self) -> "std::vector< str >::allocator_type":
        return _pyAgrum.Vector_string_get_allocator(self)

    def pop_back(self) -> None:
        return _pyAgrum.Vector_string_pop_back(self)

    def erase(self, *args) -> "std::vector< str >::iterator":
        return _pyAgrum.Vector_string_erase(self, *args)

    def __init__(self, *args):
        _pyAgrum.Vector_string_swiginit(self, _pyAgrum.new_Vector_string(*args))

    def push_back(self, x: str) -> None:
        return _pyAgrum.Vector_string_push_back(self, x)

    def front(self) -> str:
        return _pyAgrum.Vector_string_front(self)

    def back(self) -> str:
        return _pyAgrum.Vector_string_back(self)

    def assign(self, n: "std::vector< str >::size_type", x: str) -> None:
        return _pyAgrum.Vector_string_assign(self, n, x)

    def resize(self, *args) -> None:
        return _pyAgrum.Vector_string_resize(self, *args)

    def insert(self, *args) -> None:
        return _pyAgrum.Vector_string_insert(self, *args)

    def reserve(self, n: "std::vector< str >::size_type") -> None:
        return _pyAgrum.Vector_string_reserve(self, n)

    def capacity(self) -> "std::vector< str >::size_type":
        return _pyAgrum.Vector_string_capacity(self)
    __swig_destroy__ = _pyAgrum.delete_Vector_string

# Register Vector_string in _pyAgrum:
_pyAgrum.Vector_string_swigregister(Vector_string)

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

    def __init__(self):
        _pyAgrum.SetIteratorStaticEnd_swiginit(self, _pyAgrum.new_SetIteratorStaticEnd())
    __swig_destroy__ = _pyAgrum.delete_SetIteratorStaticEnd

# Register SetIteratorStaticEnd in _pyAgrum:
_pyAgrum.SetIteratorStaticEnd_swigregister(SetIteratorStaticEnd)

class GumException(Exception):
    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):
        _pyAgrum.GumException_swiginit(self, _pyAgrum.new_GumException(*args))
    __swig_destroy__ = _pyAgrum.delete_GumException

    def what(self) -> str:
        return _pyAgrum.GumException_what(self)

    def errorContent(self) -> str:
        r"""

        Returns
        -------
        str
        	the error content

        """
        return _pyAgrum.GumException_errorContent(self)

    def errorType(self) -> str:
        r"""

        Returns
        -------
        str
        	the error type

        """
        return _pyAgrum.GumException_errorType(self)

    def errorCallStack(self) -> str:
        r"""

        Returns
        -------
        str
        	the error call stack

        """
        return _pyAgrum.GumException_errorCallStack(self)

# Register GumException in _pyAgrum:
_pyAgrum.GumException_swigregister(GumException)


def _createMsg_(filename: str, function: str, line: int, msg: str) -> str:
    return _pyAgrum._createMsg_(filename, function, line, msg)
class FatalError(GumException):
    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):
        _pyAgrum.FatalError_swiginit(self, _pyAgrum.new_FatalError(*args))
    __swig_destroy__ = _pyAgrum.delete_FatalError

# Register FatalError in _pyAgrum:
_pyAgrum.FatalError_swigregister(FatalError)

class NotImplementedYet(GumException):
    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):
        _pyAgrum.NotImplementedYet_swiginit(self, _pyAgrum.new_NotImplementedYet(*args))
    __swig_destroy__ = _pyAgrum.delete_NotImplementedYet

# Register NotImplementedYet in _pyAgrum:
_pyAgrum.NotImplementedYet_swigregister(NotImplementedYet)

class IteratorError(GumException):
    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):
        _pyAgrum.IteratorError_swiginit(self, _pyAgrum.new_IteratorError(*args))
    __swig_destroy__ = _pyAgrum.delete_IteratorError

# Register IteratorError in _pyAgrum:
_pyAgrum.IteratorError_swigregister(IteratorError)

class UndefinedIteratorValue(IteratorError):
    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):
        _pyAgrum.UndefinedIteratorValue_swiginit(self, _pyAgrum.new_UndefinedIteratorValue(*args))
    __swig_destroy__ = _pyAgrum.delete_UndefinedIteratorValue

# Register UndefinedIteratorValue in _pyAgrum:
_pyAgrum.UndefinedIteratorValue_swigregister(UndefinedIteratorValue)

class UndefinedIteratorKey(IteratorError):
    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):
        _pyAgrum.UndefinedIteratorKey_swiginit(self, _pyAgrum.new_UndefinedIteratorKey(*args))
    __swig_destroy__ = _pyAgrum.delete_UndefinedIteratorKey

# Register UndefinedIteratorKey in _pyAgrum:
_pyAgrum.UndefinedIteratorKey_swigregister(UndefinedIteratorKey)

class NullElement(GumException):
    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):
        _pyAgrum.NullElement_swiginit(self, _pyAgrum.new_NullElement(*args))
    __swig_destroy__ = _pyAgrum.delete_NullElement

# Register NullElement in _pyAgrum:
_pyAgrum.NullElement_swigregister(NullElement)

class UndefinedElement(GumException):
    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):
        _pyAgrum.UndefinedElement_swiginit(self, _pyAgrum.new_UndefinedElement(*args))
    __swig_destroy__ = _pyAgrum.delete_UndefinedElement

# Register UndefinedElement in _pyAgrum:
_pyAgrum.UndefinedElement_swigregister(UndefinedElement)

class SizeError(GumException):
    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):
        _pyAgrum.SizeError_swiginit(self, _pyAgrum.new_SizeError(*args))
    __swig_destroy__ = _pyAgrum.delete_SizeError

# Register SizeError in _pyAgrum:
_pyAgrum.SizeError_swigregister(SizeError)

class ArgumentError(GumException):
    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):
        _pyAgrum.ArgumentError_swiginit(self, _pyAgrum.new_ArgumentError(*args))
    __swig_destroy__ = _pyAgrum.delete_ArgumentError

# Register ArgumentError in _pyAgrum:
_pyAgrum.ArgumentError_swigregister(ArgumentError)

class InvalidArgumentsNumber(ArgumentError):
    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):
        _pyAgrum.InvalidArgumentsNumber_swiginit(self, _pyAgrum.new_InvalidArgumentsNumber(*args))
    __swig_destroy__ = _pyAgrum.delete_InvalidArgumentsNumber

# Register InvalidArgumentsNumber in _pyAgrum:
_pyAgrum.InvalidArgumentsNumber_swigregister(InvalidArgumentsNumber)

class InvalidArgument(ArgumentError):
    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):
        _pyAgrum.InvalidArgument_swiginit(self, _pyAgrum.new_InvalidArgument(*args))
    __swig_destroy__ = _pyAgrum.delete_InvalidArgument

# Register InvalidArgument in _pyAgrum:
_pyAgrum.InvalidArgument_swigregister(InvalidArgument)

class IOError(GumException):
    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):
        _pyAgrum.IOError_swiginit(self, _pyAgrum.new_IOError(*args))
    __swig_destroy__ = _pyAgrum.delete_IOError

# Register IOError in _pyAgrum:
_pyAgrum.IOError_swigregister(IOError)

class FormatNotFound(IOError):
    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):
        _pyAgrum.FormatNotFound_swiginit(self, _pyAgrum.new_FormatNotFound(*args))
    __swig_destroy__ = _pyAgrum.delete_FormatNotFound

# Register FormatNotFound in _pyAgrum:
_pyAgrum.FormatNotFound_swigregister(FormatNotFound)

class OperationNotAllowed(GumException):
    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):
        _pyAgrum.OperationNotAllowed_swiginit(self, _pyAgrum.new_OperationNotAllowed(*args))
    __swig_destroy__ = _pyAgrum.delete_OperationNotAllowed

# Register OperationNotAllowed in _pyAgrum:
_pyAgrum.OperationNotAllowed_swigregister(OperationNotAllowed)

class NotFound(GumException):
    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):
        _pyAgrum.NotFound_swiginit(self, _pyAgrum.new_NotFound(*args))
    __swig_destroy__ = _pyAgrum.delete_NotFound

# Register NotFound in _pyAgrum:
_pyAgrum.NotFound_swigregister(NotFound)

class OutOfBounds(ArgumentError):
    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):
        _pyAgrum.OutOfBounds_swiginit(self, _pyAgrum.new_OutOfBounds(*args))
    __swig_destroy__ = _pyAgrum.delete_OutOfBounds

# Register OutOfBounds in _pyAgrum:
_pyAgrum.OutOfBounds_swigregister(OutOfBounds)

class DuplicateElement(ArgumentError):
    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):
        _pyAgrum.DuplicateElement_swiginit(self, _pyAgrum.new_DuplicateElement(*args))
    __swig_destroy__ = _pyAgrum.delete_DuplicateElement

# Register DuplicateElement in _pyAgrum:
_pyAgrum.DuplicateElement_swigregister(DuplicateElement)

class DuplicateLabel(ArgumentError):
    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):
        _pyAgrum.DuplicateLabel_swiginit(self, _pyAgrum.new_DuplicateLabel(*args))
    __swig_destroy__ = _pyAgrum.delete_DuplicateLabel

# Register DuplicateLabel in _pyAgrum:
_pyAgrum.DuplicateLabel_swigregister(DuplicateLabel)

class GraphError(GumException):
    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):
        _pyAgrum.GraphError_swiginit(self, _pyAgrum.new_GraphError(*args))
    __swig_destroy__ = _pyAgrum.delete_GraphError

# Register GraphError in _pyAgrum:
_pyAgrum.GraphError_swigregister(GraphError)

class NoNeighbour(GraphError):
    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):
        _pyAgrum.NoNeighbour_swiginit(self, _pyAgrum.new_NoNeighbour(*args))
    __swig_destroy__ = _pyAgrum.delete_NoNeighbour

# Register NoNeighbour in _pyAgrum:
_pyAgrum.NoNeighbour_swigregister(NoNeighbour)

class NoParent(GraphError):
    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):
        _pyAgrum.NoParent_swiginit(self, _pyAgrum.new_NoParent(*args))
    __swig_destroy__ = _pyAgrum.delete_NoParent

# Register NoParent in _pyAgrum:
_pyAgrum.NoParent_swigregister(NoParent)

class NoChild(GraphError):
    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):
        _pyAgrum.NoChild_swiginit(self, _pyAgrum.new_NoChild(*args))
    __swig_destroy__ = _pyAgrum.delete_NoChild

# Register NoChild in _pyAgrum:
_pyAgrum.NoChild_swigregister(NoChild)

class InvalidEdge(GraphError):
    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):
        _pyAgrum.InvalidEdge_swiginit(self, _pyAgrum.new_InvalidEdge(*args))
    __swig_destroy__ = _pyAgrum.delete_InvalidEdge

# Register InvalidEdge in _pyAgrum:
_pyAgrum.InvalidEdge_swigregister(InvalidEdge)

class InvalidArc(GraphError):
    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):
        _pyAgrum.InvalidArc_swiginit(self, _pyAgrum.new_InvalidArc(*args))
    __swig_destroy__ = _pyAgrum.delete_InvalidArc

# Register InvalidArc in _pyAgrum:
_pyAgrum.InvalidArc_swigregister(InvalidArc)

class InvalidNode(GraphError):
    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):
        _pyAgrum.InvalidNode_swiginit(self, _pyAgrum.new_InvalidNode(*args))
    __swig_destroy__ = _pyAgrum.delete_InvalidNode

# Register InvalidNode in _pyAgrum:
_pyAgrum.InvalidNode_swigregister(InvalidNode)

class DefaultInLabel(GraphError):
    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):
        _pyAgrum.DefaultInLabel_swiginit(self, _pyAgrum.new_DefaultInLabel(*args))
    __swig_destroy__ = _pyAgrum.delete_DefaultInLabel

# Register DefaultInLabel in _pyAgrum:
_pyAgrum.DefaultInLabel_swigregister(DefaultInLabel)

class InvalidDirectedCycle(GraphError):
    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):
        _pyAgrum.InvalidDirectedCycle_swiginit(self, _pyAgrum.new_InvalidDirectedCycle(*args))
    __swig_destroy__ = _pyAgrum.delete_InvalidDirectedCycle

# Register InvalidDirectedCycle in _pyAgrum:
_pyAgrum.InvalidDirectedCycle_swigregister(InvalidDirectedCycle)

class CPTError(GumException):
    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):
        _pyAgrum.CPTError_swiginit(self, _pyAgrum.new_CPTError(*args))
    __swig_destroy__ = _pyAgrum.delete_CPTError

# Register CPTError in _pyAgrum:
_pyAgrum.CPTError_swigregister(CPTError)

class IncompatibleEvidence(GumException):
    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):
        _pyAgrum.IncompatibleEvidence_swiginit(self, _pyAgrum.new_IncompatibleEvidence(*args))
    __swig_destroy__ = _pyAgrum.delete_IncompatibleEvidence

# Register IncompatibleEvidence in _pyAgrum:
_pyAgrum.IncompatibleEvidence_swigregister(IncompatibleEvidence)

class FactoryError(GumException):
    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):
        _pyAgrum.FactoryError_swiginit(self, _pyAgrum.new_FactoryError(*args))
    __swig_destroy__ = _pyAgrum.delete_FactoryError

# Register FactoryError in _pyAgrum:
_pyAgrum.FactoryError_swigregister(FactoryError)

class FactoryInvalidState(FactoryError):
    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):
        _pyAgrum.FactoryInvalidState_swiginit(self, _pyAgrum.new_FactoryInvalidState(*args))
    __swig_destroy__ = _pyAgrum.delete_FactoryInvalidState

# Register FactoryInvalidState in _pyAgrum:
_pyAgrum.FactoryInvalidState_swigregister(FactoryInvalidState)

class TypeError(FactoryError):
    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):
        _pyAgrum.TypeError_swiginit(self, _pyAgrum.new_TypeError(*args))
    __swig_destroy__ = _pyAgrum.delete_TypeError

# Register TypeError in _pyAgrum:
_pyAgrum.TypeError_swigregister(TypeError)

class WrongClassElement(FactoryError):
    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):
        _pyAgrum.WrongClassElement_swiginit(self, _pyAgrum.new_WrongClassElement(*args))
    __swig_destroy__ = _pyAgrum.delete_WrongClassElement

# Register WrongClassElement in _pyAgrum:
_pyAgrum.WrongClassElement_swigregister(WrongClassElement)

class PRMTypeError(FactoryError):
    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):
        _pyAgrum.PRMTypeError_swiginit(self, _pyAgrum.new_PRMTypeError(*args))
    __swig_destroy__ = _pyAgrum.delete_PRMTypeError

# Register PRMTypeError in _pyAgrum:
_pyAgrum.PRMTypeError_swigregister(PRMTypeError)

class LearningError(GumException):
    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):
        _pyAgrum.LearningError_swiginit(self, _pyAgrum.new_LearningError(*args))
    __swig_destroy__ = _pyAgrum.delete_LearningError

# Register LearningError in _pyAgrum:
_pyAgrum.LearningError_swigregister(LearningError)

class IncompatibleScoreApriori(LearningError):
    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):
        _pyAgrum.IncompatibleScoreApriori_swiginit(self, _pyAgrum.new_IncompatibleScoreApriori(*args))
    __swig_destroy__ = _pyAgrum.delete_IncompatibleScoreApriori

# Register IncompatibleScoreApriori in _pyAgrum:
_pyAgrum.IncompatibleScoreApriori_swigregister(IncompatibleScoreApriori)

class PossiblyIncompatibleScoreApriori(LearningError):
    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):
        _pyAgrum.PossiblyIncompatibleScoreApriori_swiginit(self, _pyAgrum.new_PossiblyIncompatibleScoreApriori(*args))
    __swig_destroy__ = _pyAgrum.delete_PossiblyIncompatibleScoreApriori

# Register PossiblyIncompatibleScoreApriori in _pyAgrum:
_pyAgrum.PossiblyIncompatibleScoreApriori_swigregister(PossiblyIncompatibleScoreApriori)

class DatabaseError(LearningError):
    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):
        _pyAgrum.DatabaseError_swiginit(self, _pyAgrum.new_DatabaseError(*args))
    __swig_destroy__ = _pyAgrum.delete_DatabaseError

# Register DatabaseError in _pyAgrum:
_pyAgrum.DatabaseError_swigregister(DatabaseError)

class MissingVariableInDatabase(LearningError):
    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):
        _pyAgrum.MissingVariableInDatabase_swiginit(self, _pyAgrum.new_MissingVariableInDatabase(*args))
    __swig_destroy__ = _pyAgrum.delete_MissingVariableInDatabase

# Register MissingVariableInDatabase in _pyAgrum:
_pyAgrum.MissingVariableInDatabase_swigregister(MissingVariableInDatabase)

class MissingValueInDatabase(LearningError):
    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):
        _pyAgrum.MissingValueInDatabase_swiginit(self, _pyAgrum.new_MissingValueInDatabase(*args))
    __swig_destroy__ = _pyAgrum.delete_MissingValueInDatabase

# Register MissingValueInDatabase in _pyAgrum:
_pyAgrum.MissingValueInDatabase_swigregister(MissingValueInDatabase)

class UnknownLabelInDatabase(LearningError):
    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):
        _pyAgrum.UnknownLabelInDatabase_swiginit(self, _pyAgrum.new_UnknownLabelInDatabase(*args))
    __swig_destroy__ = _pyAgrum.delete_UnknownLabelInDatabase

# Register UnknownLabelInDatabase in _pyAgrum:
_pyAgrum.UnknownLabelInDatabase_swigregister(UnknownLabelInDatabase)

class SyntaxError(IOError):
    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):
        _pyAgrum.SyntaxError_swiginit(self, _pyAgrum.new_SyntaxError(*args))

    def col(self) -> int:
        r"""

        Returns
        -------
        int
        	the indice of the colonne of the error

        """
        return _pyAgrum.SyntaxError_col(self)

    def line(self) -> int:
        r"""

        Returns
        -------
        int
        	the indice of the line of the error

        """
        return _pyAgrum.SyntaxError_line(self)

    def filename(self) -> str:
        return _pyAgrum.SyntaxError_filename(self)

    def what(self) -> str:
        return _pyAgrum.SyntaxError_what(self)
    __swig_destroy__ = _pyAgrum.delete_SyntaxError

# Register SyntaxError in _pyAgrum:
_pyAgrum.SyntaxError_swigregister(SyntaxError)


def randomValue(max: int=2) -> int:
    r"""

    Returns
    -------
    int
      a value randomly drawn (0 or 1)

    """
    return _pyAgrum.randomValue(max)

def randomProba() -> float:
    r"""

    Returns
    -------
    float
        a random number between 0 and 1 included (i.e. a proba). 

    """
    return _pyAgrum.randomProba()

def randomGeneratorSeed() -> int:
    r"""

    Returns
    -------
    int
      a randomly generated seed

    """
    return _pyAgrum.randomGeneratorSeed()

def initRandom(seed: int=0) -> None:
    r"""

    Initialize random generator seed.

    Parameters
    ----------
    seed : int
      the seed used to initialize the random generator

    """
    return _pyAgrum.initRandom(seed)

def getRandomGenerator(seed: int=0) -> "std::default_random_engine":
    r"""

    Returns
    -------
    tbw
      the random generator

    """
    return _pyAgrum.getRandomGenerator(seed)

def isOMP() -> bool:
    r"""

    Returns
    -------
    bool
      True if OMP has been set at compilation, False otherwise

    """
    return _pyAgrum.isOMP()

def setNumberOfThreads(number: int) -> None:
    r"""

    To aNone spare cycles (less then 100% CPU occupied), use more threads than logical processors (x2 is a good all-around value). 

    Returns
    -------
    number : int
      the number of threads to be used

    """
    return _pyAgrum.setNumberOfThreads(number)

def getMaxNumberOfThreads() -> int:
    r"""

    Returns
    -------
    int
      the max number of threads

    """
    return _pyAgrum.getMaxNumberOfThreads()

def getThreadNumber() -> int:
    r"""

    Returns
    -------
    int
      the number of thread

    """
    return _pyAgrum.getThreadNumber()

def getNumberOfRunningThreads() -> int:
    r"""

    Returns
    -------
    int
      the number of running threads

    """
    return _pyAgrum.getNumberOfRunningThreads()

def getNumberOfLogicalProcessors() -> int:
    r"""

    Returns
    -------
    int
      the number of logical processors

    """
    return _pyAgrum.getNumberOfLogicalProcessors()

def setNestedParallelism(value: bool) -> None:
    r"""

    Parameters
    ----------
    value : bool
      True if nested parallelism should be activated

    """
    return _pyAgrum.setNestedParallelism(value)

def getNestedParallelism() -> bool:
    r"""

    Returns
    -------
    bool
      True if nested parallelism is enabled

    """
    return _pyAgrum.getNestedParallelism()

def setDynamicThreadsNumber(value: bool) -> None:
    r"""

    Parameters
    ----------
    value : bool
      True if the number of threads should be dynamic

    """
    return _pyAgrum.setDynamicThreadsNumber(value)

def getDynamicThreadsNumber() -> bool:
    r"""

    Returns
    -------
    bool
      True if dynamic threads number is enabled

    """
    return _pyAgrum.getDynamicThreadsNumber()
VarType_Discretized = _pyAgrum.VarType_Discretized
VarType_Labelized = _pyAgrum.VarType_Labelized
VarType_Integer = _pyAgrum.VarType_Integer
VarType_Range = _pyAgrum.VarType_Range
VarType_Continuous = _pyAgrum.VarType_Continuous
class Variable(object):
    r"""

    Abstract class used by DiscreteVariable.

    """

    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_Variable

    def clone(self) -> "pyAgrum.Variable":
        r"""

        Copy factory

        Returns
        -------
        pyAgrum.DiscreteVariable
        	a pointer on a new copy of this

        """
        return _pyAgrum.Variable_clone(self)

    def __eq__(self, aRV: "pyAgrum.Variable") -> bool:
        return _pyAgrum.Variable___eq__(self, aRV)

    def __ne__(self, aRV: "pyAgrum.Variable") -> bool:
        return _pyAgrum.Variable___ne__(self, aRV)

    def setName(self, theValue: str) -> None:
        r"""

        sets the name of the variable.

        Parameters
        ----------
        theValue : str
        	the new description of the variable

        """
        return _pyAgrum.Variable_setName(self, theValue)

    def name(self) -> str:
        r"""

        Returns
        -------
        str
        	the name of the variable

        """
        return _pyAgrum.Variable_name(self)

    def setDescription(self, theValue: str) -> None:
        r"""

        set the description of the variable.

        Parameters
        ----------
        theValue : str
        	the new description of the variable

        """
        return _pyAgrum.Variable_setDescription(self, theValue)

    def description(self) -> str:
        r"""

        Returns
        -------
        str
        	the description of the variable

        """
        return _pyAgrum.Variable_description(self)

    def varType(self) -> int:
        return _pyAgrum.Variable_varType(self)

    def domain(self) -> str:
        return _pyAgrum.Variable_domain(self)

# Register Variable in _pyAgrum:
_pyAgrum.Variable_swigregister(Variable)

class DiscreteVariable(Variable):
    r"""

    DiscreteVariable is the (abstract) base class for discrete random variables.

    """

    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 - class is abstract")
    __swig_destroy__ = _pyAgrum.delete_DiscreteVariable

    def clone(self) -> "pyAgrum.DiscreteVariable":
        r"""

        Returns
        -------
        pyAgrum.DiscreteVariable
        	a copy of the DiscreteVariable

        """
        return _pyAgrum.DiscreteVariable_clone(self)

    def empty(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the domain size < 2

        """
        return _pyAgrum.DiscreteVariable_empty(self)

    def domainSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of modalities in the variable domain

        """
        return _pyAgrum.DiscreteVariable_domainSize(self)

    def labels(self) -> List[str]:
        r"""

        Returns
        -------
        tuple
        	a tuple containing the labels

        """
        return _pyAgrum.DiscreteVariable_labels(self)

    def numerical(self, indice: int) -> float:
        r"""

        Parameters
        ----------
        indice : int
        	an index

        Returns
        -------
        float
        	the numerical representation of the indice-th value

        """
        return _pyAgrum.DiscreteVariable_numerical(self, indice)

    def varType(self) -> int:
        r"""

        returns the type of variable

        Returns
        -------
        int :
        	the type of the variable, 0: DiscretizedVariable, 1: LabelizedVariable, 2: RangeVariable

        """
        return _pyAgrum.DiscreteVariable_varType(self)

    def __eq__(self, aRV: "pyAgrum.DiscreteVariable") -> bool:
        return _pyAgrum.DiscreteVariable___eq__(self, aRV)

    def __ne__(self, aRV: "pyAgrum.DiscreteVariable") -> bool:
        return _pyAgrum.DiscreteVariable___ne__(self, aRV)

    def index(self, label: str) -> int:
        r"""

        Parameters
        ----------
        label : str
        	a label

        Returns
        -------
        int
        	the indice of the label

        """
        return _pyAgrum.DiscreteVariable_index(self, label)

    def label(self, i: int) -> str:
        r"""

        Parameters
        ----------
        i : int
        	the index of the label we wish to return

        Returns
        -------
        str
        	the indice-th label

        Raises
        ------
        pyAgrum.OutOfBound
        	If the variable does not contain the label

        """
        return _pyAgrum.DiscreteVariable_label(self, i)

    def toStringWithDescription(self) -> str:
        r"""

        Returns
        -------
        str
        	a description of the variable

        """
        return _pyAgrum.DiscreteVariable_toStringWithDescription(self)

    def domain(self) -> str:
        r"""

        Returns
        -------
        str
        	the domain of the variable

        """
        return _pyAgrum.DiscreteVariable_domain(self)

    def stype(self) -> str:
        return _pyAgrum.DiscreteVariable_stype(self)

    def __repr__(self) -> str:
        return _pyAgrum.DiscreteVariable___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.DiscreteVariable___str__(self)

    def __hash__(self):
        return hash(self.name())

    def __getitem__(self,label):   # adding the y() function here
        return self.index(label)


    def toLabelizedVar(self) -> "pyAgrum.LabelizedVariable":
        r"""

        Returns
        -------
        pyAgrum.LabelizedVariable
        	the labelized variable

        Raises
        ------
        pyAgrum.RuntimeError
        	If the variable is not a LabelizedVariable

        """
        return _pyAgrum.DiscreteVariable_toLabelizedVar(self)

    def toRangeVar(self) -> "pyAgrum.RangeVariable":
        r"""

        Returns
        -------
        pyAgrum.RangeVariable
        	the range variable

        Raises
        ------
        pyAgrum.RuntimeError
        	If the variable is not a RangeVariable

        """
        return _pyAgrum.DiscreteVariable_toRangeVar(self)

    def toIntegerVar(self) -> "pyAgrum.IntegerVariable":
        return _pyAgrum.DiscreteVariable_toIntegerVar(self)

    def toDiscretizedVar(self) -> "pyAgrum.DiscretizedVariable":
        r"""

        Returns
        -------
        pyAgrum.DiscretizedVariable
        	the discretized variable

        Raises
        ------
        pyAgrum.RuntimeError
        	If the variable is not a DiscretizedVariable

        """
        return _pyAgrum.DiscreteVariable_toDiscretizedVar(self)

# Register DiscreteVariable in _pyAgrum:
_pyAgrum.DiscreteVariable_swigregister(DiscreteVariable)

class LabelizedVariable(DiscreteVariable):
    r"""

    LabelizedVariable is a discrete random variable with a customizable sequence of labels.

    LabelizedVariable(aName, aDesc='', nbrLabel=2) -> LabelizedVariable
        Parameters:
            * **aName** (*str*) -- the name of the variable
            * **aDesc** (*str*) -- the (optional) description of the variable
            * **nbrLabel** (*int) -- the number of labels to create (2 by default)

    LabelizedVariable(aLDRV) -> LabelizedVariable
        Parameters:
            * **aLDRV** (*pyAgrum.LabelizedVariable*) -- The pyAgrum.LabelizedVariable that will be copied

    Examples
    --------
    >>> import pyAgrum as gum
    >>> # creating a variable with 3 labels : '0', '1' and '2'
    >>> va=gum.LabelizedVariable('a','a labelized variable',3)
    >>> print(va)
    a:Labelized(<0,1,2>)
    >>> va.addLabel('foo')
    ("pyAgrum.LabelizedVariable"@0x7fc4c840dd90) a:Labelized(<0,1,2,foo>)
    >>> va.changeLabel(1,'bar')
    >>> print(va)
    a:Labelized(<0,bar,2,foo>)
    >>> vb=gum.LabelizedVariable('b','b',0).addLabel('A').addLabel('B').addLabel('C')
    >>> print(vb)
    b:Labelized(<A,B,C>)
    >>> vb.labels()
    ('A', 'B', 'C')
    >>> vb.isLabel('E')
    False
    >>> vb.label(2)
    'C'
    >>> vc=gum.LabelizedVariable('b','b',['one','two','three'])
    >>> vc
    ("pyAgrum.LabelizedVariable"@0x7fc4c840c130) b:Labelized(<one,two,three>)

    """

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

    def __init__(self, *args):
        _pyAgrum.LabelizedVariable_swiginit(self, _pyAgrum.new_LabelizedVariable(*args))
    __swig_destroy__ = _pyAgrum.delete_LabelizedVariable

    def clone(self) -> "pyAgrum.LabelizedVariable":
        r"""

        Returns
        -------
        pyAgrum.LabelizedVariable
        	a copy of the LabelizedVariable

        """
        return _pyAgrum.LabelizedVariable_clone(self)

    def index(self, label: str) -> int:
        r"""

        Parameters
        ----------
        label : str
        	a label

        Returns
        -------
        int
        	the indice of the label

        """
        return _pyAgrum.LabelizedVariable_index(self, label)

    def isLabel(self, aLabel: str) -> bool:
        r"""

        Indicates whether the variable already has the label passed in argument

        Parameters
        ----------
        aLabel : str
        	the label to be tested

        Returns
        -------
        bool
        	True if the label already exists

        """
        return _pyAgrum.LabelizedVariable_isLabel(self, aLabel)

    def addLabel(self,*args):
        """
        Add a label with a new index (we assume that we will NEVER remove a label).

        Parameters
        ----------
        aLabel : str
            the label to be added to the labelized variable

        Returns
        -------
        pyAgrum.LabelizedVariable
            the labelized variable

        Raises
        ------
        gum.DuplicateElement
            If the variable already contains the label
        """
        _pyAgrum.LabelizedVariable_addLabel(self,*args)
        return self



    def changeLabel(self, pos: int, aLabel: str) -> None:
        r"""

        Change the label at the specified index

        Parameters
        ----------
        pos : int
        	the index of the label to be changed
        aLabel : str
        	the label to be added to the labelized variable

        Raises
        ------
        pyAgrum.DuplicatedElement
          If the variable already contains the new label
        pyAgrum.OutOfBounds
          If the index is greater than the size of the variable

        """
        return _pyAgrum.LabelizedVariable_changeLabel(self, pos, aLabel)

    def eraseLabels(self) -> None:
        r"""

        Erase all the labels from the variable.

        """
        return _pyAgrum.LabelizedVariable_eraseLabels(self)

    def label(self, i: int) -> str:
        r"""

        Parameters
        ----------
        i : int
        	the index of the label we wish to return

        Returns
        -------
        str
        	the indice-th label

        Raises
        ------
        pyAgrum.OutOfBound
        	If the variable does not contain the label

        """
        return _pyAgrum.LabelizedVariable_label(self, i)

    def posLabel(self, label: str) -> int:
        return _pyAgrum.LabelizedVariable_posLabel(self, label)

    def numerical(self, index: int) -> float:
        r"""

        Parameters
        ----------
        indice : int
        	an index

        Returns
        -------
        float
        	the numerical representation of the indice-th value

        """
        return _pyAgrum.LabelizedVariable_numerical(self, index)

    def domainSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of modalities in the variable domain

        """
        return _pyAgrum.LabelizedVariable_domainSize(self)

    def varType(self) -> int:
        r"""

        returns the type of variable

        Returns
        -------
        int :
        	the type of the variable, 0: DiscretizedVariable, 1: LabelizedVariable, 2: RangeVariable

        """
        return _pyAgrum.LabelizedVariable_varType(self)

    def domain(self) -> str:
        r"""

        Returns
        -------
        str
            the domain of the variable as a string

        """
        return _pyAgrum.LabelizedVariable_domain(self)

    def stype(self) -> str:
        return _pyAgrum.LabelizedVariable_stype(self)

    def __repr__(self) -> str:
        return _pyAgrum.LabelizedVariable___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.LabelizedVariable___str__(self)

# Register LabelizedVariable in _pyAgrum:
_pyAgrum.LabelizedVariable_swigregister(LabelizedVariable)

class RangeVariable(DiscreteVariable):
    r"""

    RangeVariable represents a variable with a range of integers as domain.

    RangeVariable(aName, aDesc,minVal, maxVal) -> RangeVariable
        Parameters:
            * **aName** (*str*) -- the name of the variable
            * **aDesc** (*str*) -- the description of the variable
            * **minVal** (*int) -- the minimal integer of the interval
            * **maxVal** (*int) -- the maximal integer of the interval

    RangeVariable(aName, aDesc='') -> RangeVariable
        Parameters:
            * **aName** (*str*) -- the name of the variable
            * **aDesc** (*str*) -- the description of the variable

        By default ``minVal=0`` and ``maxVal=1``

    RangeVariable(aRV) -> RangeVariable
        Parameters:
            * **aDV** (*RangeVariable*) -- the pyAgrum.RangeVariable that will be copied

    Examples
    --------
    >>> import pyAgrum as gum
    >>> vI=gum.RangeVariable('I','I in [4,10]',4,10)
    >>> print(vI)
    I:Range([4,10])
    >>> vI.maxVal()
    10
    >>> vI.belongs(1)
    False
    >>> # where is the value 5 ?
    >>> vI.index('5')
    1
    >>> vI.labels()
    ('4', '5', '6', '7', '8', '9', '10')

    """

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

    def __init__(self, *args):
        _pyAgrum.RangeVariable_swiginit(self, _pyAgrum.new_RangeVariable(*args))
    __swig_destroy__ = _pyAgrum.delete_RangeVariable

    def clone(self) -> "pyAgrum.RangeVariable":
        r"""

        Returns
        -------
        pyAgrum.RangeVariable
        	a copy of the RangeVariable

        """
        return _pyAgrum.RangeVariable_clone(self)

    def domainSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of modalities in the variable domain

        """
        return _pyAgrum.RangeVariable_domainSize(self)

    def varType(self) -> int:
        r"""

        returns the type of variable

        Returns
        -------
        int :
        	the type of the variable, 0: DiscretizedVariable, 1: LabelizedVariable, 2: RangeVariable

        """
        return _pyAgrum.RangeVariable_varType(self)

    def label(self, index: int) -> str:
        r"""

        Parameters
        ----------
        indice : int
          the index of the label we wish to return

        Returns
        -------
        str
          the indice-th label

        Raises
        ------
        pyAgrum.OutOfBound
          If the variable does not contain the label

        """
        return _pyAgrum.RangeVariable_label(self, index)

    def numerical(self, index: int) -> float:
        r"""

        Parameters
        ----------
        indice : int
        	an index

        Returns
        -------
        float
        	the numerical representation of the indice-th value

        """
        return _pyAgrum.RangeVariable_numerical(self, index)

    def minVal(self) -> int:
        r"""

        Returns
        -------
        int :
          the lower bound of the variable

        """
        return _pyAgrum.RangeVariable_minVal(self)

    def setMinVal(self, minVal: int) -> None:
        r"""

        Set a new value of the lower bound

        Parameters
        ----------
        minVal : int
          The new value of the lower bound

        Warnings
        --------
        An error should be raised if the value is higher than the upper bound.

        """
        return _pyAgrum.RangeVariable_setMinVal(self, minVal)

    def maxVal(self) -> int:
        r"""

        Returns
        -------
        int :
          the upper bound of the variable.

        """
        return _pyAgrum.RangeVariable_maxVal(self)

    def setMaxVal(self, maxVal: int) -> None:
        r"""

        Set a new value of the upper bound

        Parameters
        ----------
        maxVal : int
          The new value of the upper bound

        Warnings
        --------
        An error should be raised if the value is lower than the lower bound.

        """
        return _pyAgrum.RangeVariable_setMaxVal(self, maxVal)

    def belongs(self, val: int) -> bool:
        r"""

        Parameters
        ----------
        val : int
          the value to be tested

        Returns
        -------
        bool:
          True if the value in parameters belongs to the variable's interval.

        """
        return _pyAgrum.RangeVariable_belongs(self, val)

    def index(self, arg2: str) -> int:
        r"""

        Parameters
        ----------
        arg2 : str
          a label

        Returns
        -------
        int
          the indice of the label

        """
        return _pyAgrum.RangeVariable_index(self, arg2)

    def domain(self) -> str:
        r"""

        Returns
        -------
        str
        	the domain of the variable

        """
        return _pyAgrum.RangeVariable_domain(self)

    def stype(self) -> str:
        return _pyAgrum.RangeVariable_stype(self)

    def __repr__(self) -> str:
        return _pyAgrum.RangeVariable___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.RangeVariable___str__(self)

# Register RangeVariable in _pyAgrum:
_pyAgrum.RangeVariable_swigregister(RangeVariable)

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

    def __init__(self, *args):
        _pyAgrum.IntegerVariable_swiginit(self, _pyAgrum.new_IntegerVariable(*args))

    def clone(self) -> "pyAgrum.IntegerVariable":
        r"""

        Returns
        -------
        pyAgrum.DiscreteVariable
        	a copy of the DiscreteVariable

        """
        return _pyAgrum.IntegerVariable_clone(self)
    __swig_destroy__ = _pyAgrum.delete_IntegerVariable

    def __eq__(self, var: "pyAgrum.Variable") -> bool:
        return _pyAgrum.IntegerVariable___eq__(self, var)

    def __ne__(self, var: "pyAgrum.Variable") -> bool:
        return _pyAgrum.IntegerVariable___ne__(self, var)

    def domainSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of modalities in the variable domain

        """
        return _pyAgrum.IntegerVariable_domainSize(self)

    def varType(self) -> int:
        r"""

        returns the type of variable

        Returns
        -------
        int :
        	the type of the variable, 0: DiscretizedVariable, 1: LabelizedVariable, 2: RangeVariable

        """
        return _pyAgrum.IntegerVariable_varType(self)

    def index(self, label: str) -> int:
        r"""

        Parameters
        ----------
        label : str
        	a label

        Returns
        -------
        int
        	the indice of the label

        """
        return _pyAgrum.IntegerVariable_index(self, label)

    def label(self, index: int) -> str:
        r"""

        Parameters
        ----------
        i : int
        	the index of the label we wish to return

        Returns
        -------
        str
        	the indice-th label

        Raises
        ------
        pyAgrum.OutOfBound
        	If the variable does not contain the label

        """
        return _pyAgrum.IntegerVariable_label(self, index)

    def numerical(self, index: int) -> float:
        r"""

        Parameters
        ----------
        indice : int
        	an index

        Returns
        -------
        float
        	the numerical representation of the indice-th value

        """
        return _pyAgrum.IntegerVariable_numerical(self, index)

    def domain(self) -> str:
        r"""

        Returns
        -------
        str
        	the domain of the variable

        """
        return _pyAgrum.IntegerVariable_domain(self)

    def stype(self) -> str:
        return _pyAgrum.IntegerVariable_stype(self)

    def integerDomain(self) -> List[int]:
        return _pyAgrum.IntegerVariable_integerDomain(self)

    def addValue(self, value: int) -> "pyAgrum.IntegerVariable":
        return _pyAgrum.IntegerVariable_addValue(self, value)

    def changeValue(self, old_value: int, new_value: int) -> None:
        return _pyAgrum.IntegerVariable_changeValue(self, old_value, new_value)

    def eraseValue(self, value: int) -> None:
        return _pyAgrum.IntegerVariable_eraseValue(self, value)

    def eraseValues(self) -> None:
        return _pyAgrum.IntegerVariable_eraseValues(self)

    def __repr__(self) -> str:
        return _pyAgrum.IntegerVariable___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.IntegerVariable___str__(self)

# Register IntegerVariable in _pyAgrum:
_pyAgrum.IntegerVariable_swigregister(IntegerVariable)

class IDiscretizedVariable(DiscreteVariable):
    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_IDiscretizedVariable

    def clone(self) -> "pyAgrum.DiscretizedVariable":
        r"""

        Returns
        -------
        pyAgrum.DiscreteVariable
        	a copy of the DiscreteVariable

        """
        return _pyAgrum.IDiscretizedVariable_clone(self)

# Register IDiscretizedVariable in _pyAgrum:
_pyAgrum.IDiscretizedVariable_swigregister(IDiscretizedVariable)

class Edge(object):
    r"""

    pyAgrum.Edge is the representation of an arc between two nodes represented by int : the first and the second.

    Edge(aN1,aN2) -> Edge
        Parameters:
            * **aN1** (*int) -- the nodeId of the first node
            * **aN2** (*int) -- the nodeId of the secondnode

    Edge(src) -> Edge
        Parameters:
            * **src** (*yAgrum.Edge*) -- the Edge to copy

    """

    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):
        _pyAgrum.Edge_swiginit(self, _pyAgrum.new_Edge(*args))
    __swig_destroy__ = _pyAgrum.delete_Edge

    def other(self, id: int) -> int:
        r"""

        Parameters
        ----------
        id : int
          the nodeId of one of the nodes of the Edge


        Returns
        ------
        int
          the nodeId of the other node

        """
        return _pyAgrum.Edge_other(self, id)

    def first(self) -> int:
        r"""

        Returns
        ------
        int
          the nodeId of the first node of the arc (the tail)

        """
        return _pyAgrum.Edge_first(self)

    def second(self) -> int:
        r"""

        Returns
        ------
        int
          the nodeId of the second node of the arc (the head)

        """
        return _pyAgrum.Edge_second(self)

    def __eq__(self, src: "pyAgrum.Edge") -> bool:
        return _pyAgrum.Edge___eq__(self, src)

    def __ne__(self, src: "pyAgrum.Edge") -> bool:
        return _pyAgrum.Edge___ne__(self, src)

# Register Edge in _pyAgrum:
_pyAgrum.Edge_swigregister(Edge)

class Arc(object):
    r"""

    pyAgrum.Arc is the representation of an arc between two nodes represented by int : the head and the tail.

    Arc(tail, head) -> Arc
        Parameters:
            * **tail** (*int) -- the tail
            * **head** (*int) -- the head

    Arc(src) -> Arc
        Parameters:
            * **src** (*Arc*) -- the pyAgrum.Arc to copy

    """

    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):
        _pyAgrum.Arc_swiginit(self, _pyAgrum.new_Arc(*args))
    __swig_destroy__ = _pyAgrum.delete_Arc

    def tail(self) -> int:
        r"""

        Returns
        -------
        int
          the id of the tail node

        """
        return _pyAgrum.Arc_tail(self)

    def head(self) -> int:
        r"""

        Returns
        ------
        int
          the id of the head node

        """
        return _pyAgrum.Arc_head(self)

    def other(self, id: int) -> int:
        r"""

        Parameters
        ----------
        id : int
          the nodeId of the head or the tail


        Returns
        -------
        int
          the nodeId of the other node

        """
        return _pyAgrum.Arc_other(self, id)

    def first(self) -> int:
        r"""

        Returns
        -------
        int
          the nodeId of the first node of the arc (the tail)

        """
        return _pyAgrum.Arc_first(self)

    def second(self) -> int:
        r"""

        Returns
        -------
        int
          the nodeId of the second node of the arc (the head)

        """
        return _pyAgrum.Arc_second(self)

    def __eq__(self, src: "pyAgrum.Arc") -> bool:
        return _pyAgrum.Arc___eq__(self, src)

    def __ne__(self, src: "pyAgrum.Arc") -> bool:
        return _pyAgrum.Arc___ne__(self, src)

# Register Arc in _pyAgrum:
_pyAgrum.Arc_swigregister(Arc)

class UndiGraph(object):
    r"""

    UndiGraph represents an Undirected Graph.

    UndiGraph() -> UndiGraph
        default constructor

    UndiGraph(src) -> UndiGraph
        Parameters!
            * **src** (*UndiGraph*) -- the pyAgrum.UndiGraph to copy


    """

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

    def __init__(self, *args):
        _pyAgrum.UndiGraph_swiginit(self, _pyAgrum.new_UndiGraph(*args))
    __swig_destroy__ = _pyAgrum.delete_UndiGraph

    def __eq__(self, g: "pyAgrum.UndiGraph") -> bool:
        return _pyAgrum.UndiGraph___eq__(self, g)

    def __ne__(self, g: "pyAgrum.UndiGraph") -> bool:
        return _pyAgrum.UndiGraph___ne__(self, g)

    def eraseNode(self, id: int) -> None:
        r"""

        Erase the node and all the adjacent edges.

        Parameters
        ----------
        id : int
          the id of the node

        """
        return _pyAgrum.UndiGraph_eraseNode(self, id)

    def clear(self) -> None:
        r"""

        Remove all the nodes and edges from the graph.

        """
        return _pyAgrum.UndiGraph_clear(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format

        """
        return _pyAgrum.UndiGraph_toDot(self)

    def hasUndirectedCycle(self) -> bool:
        r"""

        Checks whether the graph contains cycles.

        Returns
        -------
        bool
            True if the graph contains a cycle

        """
        return _pyAgrum.UndiGraph_hasUndirectedCycle(self)

    def partialUndiGraph(self, nodes: List[int]) -> "pyAgrum.UndiGraph":
        r"""

        Parameters
        ----------
        nodesSet : Set
            The set of nodes composing the partial graph

        Returns
        -------
        pyAgrum.UndiGraph
            The partial graph formed by the nodes given in parameter

        """
        return _pyAgrum.UndiGraph_partialUndiGraph(self, nodes)

    def nodes2ConnectedComponent(self) -> Dict[int,int]:
        return _pyAgrum.UndiGraph_nodes2ConnectedComponent(self)

    def __repr__(self) -> str:
        return _pyAgrum.UndiGraph___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.UndiGraph___str__(self)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.UndiGraph_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def addNodes(self, n: int) -> object:
        r"""

        Add n nodes.

        Parameters
        ----------
        n : int
          the number of nodes to add.

        Returns
        -------
        Set of int
          the new ids

        """
        return _pyAgrum.UndiGraph_addNodes(self, n)

    def edges(self) -> object:
        r"""

        Returns
        -------
        List
          the list of the edges

        """
        return _pyAgrum.UndiGraph_edges(self)

    def neighbours(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id : int
            the id of the checked node

        Returns
        -------
        Set
            The set of edges adjacent to the given node

        """
        return _pyAgrum.UndiGraph_neighbours(self, id)

    def addNode(self) -> int:
        r"""

        Returns
        -------
        int
          the new NodeId

        """
        return _pyAgrum.UndiGraph_addNode(self)

    def addNodeWithId(self, id: int) -> None:
        r"""

        Add a node by choosing a new NodeId.

        Parameters
        ----------
        id : int
          The id of the new node

        Raises
        ------
        pyAgrum.DuplicateElement
          If the given id is already used

        """
        return _pyAgrum.UndiGraph_addNodeWithId(self, id)

    def existsNode(self, id: int) -> bool:
        r"""

        Check if a node with a certain id exists in the graph.

        Parameters
        ----------
        id : int
            the checked id

        Returns
        -------
        bool
            True if the node exists

        """
        return _pyAgrum.UndiGraph_existsNode(self, id)

    def size(self) -> int:
        r"""

        Returns
        -------
        int
            the number of nodes in the graph

        """
        return _pyAgrum.UndiGraph_size(self)

    def empty(self) -> bool:
        r"""

        Check if the graph is empty.

        Returns
        -------
        bool
            True if the graph is empty

        """
        return _pyAgrum.UndiGraph_empty(self)

    def addEdge(self, *args) -> None:
        r"""

        Insert a new edge into the graph.

        Parameters
        ----------
        n1 : int
          the id of one node of the new inserted edge
        n2 : int
          the id of the other node of the new inserted edge

        Raises
        ------
        pyAgrum.InvalidNode
          If n1 or n2 does not belong to the graph nodes.

        """
        return _pyAgrum.UndiGraph_addEdge(self, *args)

    def eraseEdge(self, n1: int, n2: int) -> None:
        r"""

        Erase the edge between n1 and n2.

        Parameters
        ----------
        n1 : int
          the id of the tail node
        n2 : int
          the id of the head node

        """
        return _pyAgrum.UndiGraph_eraseEdge(self, n1, n2)

    def existsEdge(self, n1: int, n2: int) -> bool:
        r"""

        Check if an edge exists bewteen n1 and n2.

        Parameters
        ----------
        n1 : int
          the id of one extremity of the edge
        n2 : int
          the id of the other extremity if tge edge

        Returns
        -------
        bool
            True if the arc exists

        """
        return _pyAgrum.UndiGraph_existsEdge(self, n1, n2)

    def sizeEdges(self) -> int:
        r"""

        Returns
        -------
        int
            the number of edges in the graph

        """
        return _pyAgrum.UndiGraph_sizeEdges(self)

    def emptyEdges(self) -> bool:
        r"""

        Check if the graph doesn't contains edges.

        Returns
        -------
        bool
            True if the graph doesn't contains edges

        """
        return _pyAgrum.UndiGraph_emptyEdges(self)

    def eraseNeighbours(self, n: int) -> None:
        r"""

        Erase all the edges adjacent to a given node.

        Parameters
        ----------
        n : int
          the id of the node

        """
        return _pyAgrum.UndiGraph_eraseNeighbours(self, n)

# Register UndiGraph in _pyAgrum:
_pyAgrum.UndiGraph_swigregister(UndiGraph)

class DiGraph(object):
    r"""

    DiGraph represents a Directed Graph.

    DiGraph() -> DiGraph
        default constructor

    DiGraph(src) -> DiGraph
        Parameters:
            * **src** (*pyAgrum.DiGraph*) -- the digraph to copy

    """

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

    def __init__(self, *args):
        _pyAgrum.DiGraph_swiginit(self, _pyAgrum.new_DiGraph(*args))
    __swig_destroy__ = _pyAgrum.delete_DiGraph

    def __eq__(self, g: "DiGraph") -> bool:
        return _pyAgrum.DiGraph___eq__(self, g)

    def __ne__(self, g: "DiGraph") -> bool:
        return _pyAgrum.DiGraph___ne__(self, g)

    def eraseNode(self, id: int) -> None:
        r"""

        Erase the node and all the related arcs.

        Parameters
        ----------
        id : int
        	the id of the node

        """
        return _pyAgrum.DiGraph_eraseNode(self, id)

    def clear(self) -> None:
        r"""

        Remove all the nodes and arcs from the graph.

        """
        return _pyAgrum.DiGraph_clear(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format 

        """
        return _pyAgrum.DiGraph_toDot(self)

    def topologicalOrder(self, clear: bool=True) -> List[int]:
        r"""

        Returns
        -------
        List
            the list of the nodes Ids in a topological order

        Raises
        ------
        pyAgrum.InvalidDirectedCycle
          If this graph contains cycles

        """
        return _pyAgrum.DiGraph_topologicalOrder(self, clear)

    def hasDirectedPath(self, _from: int, to: int) -> bool:
        r"""

        Check if a directedpath exists bewteen from and to.

        Parameters
        ----------
        from : int
        	the id of the first node of the (possible) path
        to : int
        	the id of the last node of the (possible) path

        Returns
        -------
        bool
            True if the directed path exists

        """
        return _pyAgrum.DiGraph_hasDirectedPath(self, _from, to)

    def __repr__(self) -> str:
        return _pyAgrum.DiGraph___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.DiGraph___str__(self)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.DiGraph_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def addNodes(self, n: int) -> object:
        r"""

        Add n nodes.

        Parameters
        ----------
        n : int
          the number of nodes to add.

        Returns
        -------
        Set of int
          the new ids

        """
        return _pyAgrum.DiGraph_addNodes(self, n)

    def arcs(self) -> object:
        r"""

        Returns
        -------
        List
        	the list of the arcs

        """
        return _pyAgrum.DiGraph_arcs(self)

    def parents(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        Set
            the set of the parents ids.

        """
        return _pyAgrum.DiGraph_parents(self, id)

    def children(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.DiGraph_children(self, id)

    def addNode(self) -> int:
        r"""

        Returns
        -------
        int
          the new NodeId

        """
        return _pyAgrum.DiGraph_addNode(self)

    def addNodeWithId(self, id: int) -> None:
        r"""

        Add a node by choosing a new NodeId.

        Parameters
        ----------
        id : int
          The id of the new node

        Raises
        ------
        pyAgrum.DuplicateElement
          If the given id is already used

        """
        return _pyAgrum.DiGraph_addNodeWithId(self, id)

    def existsNode(self, id: int) -> bool:
        r"""

        Check if a node with a certain id exists in the graph.

        Parameters
        ----------
        id : int
            the checked id

        Returns
        -------
        bool
            True if the node exists

        """
        return _pyAgrum.DiGraph_existsNode(self, id)

    def size(self) -> int:
        r"""

        Returns
        -------
        int
            the number of nodes in the graph

        """
        return _pyAgrum.DiGraph_size(self)

    def empty(self) -> bool:
        r"""

        Check if the graph is empty.

        Returns
        -------
        bool
            True if the graph is empty

        """
        return _pyAgrum.DiGraph_empty(self)

    def addArc(self, *args) -> None:
        r"""

        Add an arc from tail to head.

        Parameters
        ----------
        tail : int
          the id of the tail node
        head : int
          the id of the head node

        Raises
        ------
        pyAgrum.InvalidNode
          If head or tail does not belong to the graph nodes.

        """
        return _pyAgrum.DiGraph_addArc(self, *args)

    def eraseArc(self, n1: int, n2: int) -> None:
        r"""

        Erase the arc between n1 and n2.

        Parameters
        ----------
        n1 : int
        	the id of the tail node
        n2 : int
        	the id of the head node

        """
        return _pyAgrum.DiGraph_eraseArc(self, n1, n2)

    def existsArc(self, n1: int, n2: int) -> bool:
        r"""

        Check if an arc exists bewteen n1 and n2.

        Parameters
        ----------
        n1 : int
        	the id of the tail node
        n2 : int
        	the id of the head node

        Returns
        -------
        bool
            True if the arc exists

        """
        return _pyAgrum.DiGraph_existsArc(self, n1, n2)

    def eraseParents(self, n: int) -> None:
        r"""

        Erase the arcs coming to the node.

        Parameters
        ----------
        n : int
        	the id of the child node

        """
        return _pyAgrum.DiGraph_eraseParents(self, n)

    def eraseChildren(self, n: int) -> None:
        r"""

        Erase the arcs heading through the node's children.

        Parameters
        ----------
        n : int
        	the id of the parent node

        """
        return _pyAgrum.DiGraph_eraseChildren(self, n)

    def sizeArcs(self) -> int:
        r"""

        Returns
        -------
        int
            the number of arcs in the graph

        """
        return _pyAgrum.DiGraph_sizeArcs(self)

    def emptyArcs(self) -> bool:
        r"""

        Check if the graph doesn't contains arcs.

        Returns
        -------
        bool
            True if the graph doesn't contains arcs

        """
        return _pyAgrum.DiGraph_emptyArcs(self)

# Register DiGraph in _pyAgrum:
_pyAgrum.DiGraph_swigregister(DiGraph)

class DAG(DiGraph):
    r"""

    DAG represents a Directed Acyclic Graph.

    DAG() -> DAG
        default constructor

    DAG(src) -> DAG
        Parameters:
            * **src** (*DAG*) -- the DAG to copy

    """

    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):
        _pyAgrum.DAG_swiginit(self, _pyAgrum.new_DAG(*args))
    __swig_destroy__ = _pyAgrum.delete_DAG

    def moralGraph(self) -> "pyAgrum.UndiGraph":
        return _pyAgrum.DAG_moralGraph(self)

    def moralizedAncestralGraph(self, nodes: List[int]) -> "pyAgrum.UndiGraph":
        return _pyAgrum.DAG_moralizedAncestralGraph(self, nodes)

    def dSeparation(self, *args) -> bool:
        return _pyAgrum.DAG_dSeparation(self, *args)

    def addArc(self, *args) -> None:
        r"""

        Add an arc from tail to head.

        Parameters
        ----------
        tail : int
          the id of the tail node
        head : int
          the id of the head node

        Raises
        ------
        pyAgrum.InvalidDirectedCircle
        	If any (directed) cycle is created by this arc
        pyAgrum.InvalidNode
        	If head or tail does not belong to the graph nodes

        """
        return _pyAgrum.DAG_addArc(self, *args)

    def eraseArc(self, n1: int, n2: int) -> None:
        return _pyAgrum.DAG_eraseArc(self, n1, n2)

    def existsArc(self, n1: int, n2: int) -> bool:
        return _pyAgrum.DAG_existsArc(self, n1, n2)

    def eraseParents(self, n: int) -> None:
        return _pyAgrum.DAG_eraseParents(self, n)

    def eraseChildren(self, n: int) -> None:
        return _pyAgrum.DAG_eraseChildren(self, n)

    def sizeArcs(self) -> int:
        return _pyAgrum.DAG_sizeArcs(self)

    def emptyArcs(self) -> bool:
        return _pyAgrum.DAG_emptyArcs(self)

# Register DAG in _pyAgrum:
_pyAgrum.DAG_swigregister(DAG)

class MixedGraph(UndiGraph, DiGraph):
    r"""

    MixedGraph represents a graph with both arcs and edges.

    MixedGraph() -> MixedGraph
        default constructor

    MixedGraph(src) -> MixedGraph
        Parameters:
            * **src** (*pyAgrum.MixedGraph*) --the MixedGraph to copy

    """

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

    def __init__(self, *args):
        _pyAgrum.MixedGraph_swiginit(self, _pyAgrum.new_MixedGraph(*args))
    __swig_destroy__ = _pyAgrum.delete_MixedGraph

    def __eq__(self, g: "MixedGraph") -> bool:
        return _pyAgrum.MixedGraph___eq__(self, g)

    def __ne__(self, g: "MixedGraph") -> bool:
        return _pyAgrum.MixedGraph___ne__(self, g)

    def eraseNode(self, id: int) -> None:
        r"""

        Erase the node and all the related arcs and edges.

        Parameters
        ----------
        id : int
        	the id of the node

        """
        return _pyAgrum.MixedGraph_eraseNode(self, id)

    def clear(self) -> None:
        r"""

        Remove all the nodes and edges from the graph.

        """
        return _pyAgrum.MixedGraph_clear(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format

        """
        return _pyAgrum.MixedGraph_toDot(self)

    def __repr__(self) -> str:
        return _pyAgrum.MixedGraph___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.MixedGraph___str__(self)

    def addNodes(self, n: int) -> object:
        r"""

        Add n nodes.

        Parameters
        ----------
        n : int
          the number of nodes to add.

        Returns
        -------
        Set of int
          the new ids

        """
        return _pyAgrum.MixedGraph_addNodes(self, n)

    def addNode(self) -> int:
        r"""

        Returns
        -------
        int
          the new NodeId

        """
        return _pyAgrum.MixedGraph_addNode(self)

    def addNodeWithId(self, id: int) -> None:
        r"""

        Add a node by choosing a new NodeId.

        Parameters
        ----------
        id : int
          The id of the new node

        Raises
        ------
        pyAgrum.DuplicateElement
          If the given id is already used

        """
        return _pyAgrum.MixedGraph_addNodeWithId(self, id)

    def existsNode(self, id: int) -> bool:
        r"""

        Check if a node with a certain id exists in the graph.

        Parameters
        ----------
        id : int
            the checked id

        Returns
        -------
        bool
            True if the node exists

        """
        return _pyAgrum.MixedGraph_existsNode(self, id)

    def size(self) -> int:
        r"""

        Returns
        -------
        int
            the number of nodes in the graph

        """
        return _pyAgrum.MixedGraph_size(self)

    def empty(self) -> bool:
        r"""

        Check if the graph is empty.

        Returns
        -------
        bool
            True if the graph is empty

        """
        return _pyAgrum.MixedGraph_empty(self)

    def addEdge(self, n1: int, n2: int) -> None:
        r"""

        Insert a new edge into the graph.

        Parameters
        ----------
        n1 : int
          the id of one node of the new inserted edge
        n2 : int
          the id of the other node of the new inserted edge

        Raises
        ------
        pyAgrum.InvalidNode
          If n1 or n2 does not belong to the graph nodes.

        """
        return _pyAgrum.MixedGraph_addEdge(self, n1, n2)

    def eraseEdge(self, n1: int, n2: int) -> None:
        r"""

        Erase the edge between n1 and n2.

        Parameters
        ----------
        n1 : int
          the id of the tail node
        n2 : int
          the id of the head node

        """
        return _pyAgrum.MixedGraph_eraseEdge(self, n1, n2)

    def existsEdge(self, n1: int, n2: int) -> bool:
        r"""

        Check if an edge exists bewteen n1 and n2.

        Parameters
        ----------
        n1 : int
          the id of one extremity of the edge
        n2 : int
          the id of the other extremity if tge edge

        Returns
        -------
        bool
            True if the arc exists

        """
        return _pyAgrum.MixedGraph_existsEdge(self, n1, n2)

    def sizeEdges(self) -> int:
        r"""

        Returns
        -------
        int
            the number of edges in the graph

        """
        return _pyAgrum.MixedGraph_sizeEdges(self)

    def emptyEdges(self) -> bool:
        r"""

        Check if the graph doesn't contains edges.

        Returns
        -------
        bool
            True if the graph doesn't contains edges

        """
        return _pyAgrum.MixedGraph_emptyEdges(self)

    def eraseNeighbours(self, n: int) -> None:
        r"""

        Erase all the edges adjacent to a given node.

        Parameters
        ----------
        n : int
          the id of the node

        """
        return _pyAgrum.MixedGraph_eraseNeighbours(self, n)

    def addArc(self, n1: int, n2: int) -> None:
        r"""

        Add an arc from tail to head.

        Parameters
        ----------
        tail : int
          the id of the tail node
        head : int
          the id of the head node

        Raises
        ------
        pyAgrum.InvalidNode
          If head or tail does not belong to the graph nodes.

        """
        return _pyAgrum.MixedGraph_addArc(self, n1, n2)

    def eraseArc(self, n1: int, n2: int) -> None:
        r"""

        Erase the arc between n1 and n2.

        Parameters
        ----------
        n1 : int
        	the id of the tail node
        n2 : int
        	the id of the head node

        """
        return _pyAgrum.MixedGraph_eraseArc(self, n1, n2)

    def existsArc(self, n1: int, n2: int) -> bool:
        r"""

        Check if an arc exists bewteen n1 and n2.

        Parameters
        ----------
        n1 : int
        	the id of the tail node
        n2 : int
        	the id of the head node

        Returns
        -------
        bool
            True if the arc exists

        """
        return _pyAgrum.MixedGraph_existsArc(self, n1, n2)

    def eraseParents(self, n: int) -> None:
        r"""

        Erase the arcs coming to the node.

        Parameters
        ----------
        n : int
        	the id of the child node

        """
        return _pyAgrum.MixedGraph_eraseParents(self, n)

    def eraseChildren(self, n: int) -> None:
        r"""

        Erase the arcs heading through the node's children.

        Parameters
        ----------
        n : int
        	the id of the parent node

        """
        return _pyAgrum.MixedGraph_eraseChildren(self, n)

    def sizeArcs(self) -> int:
        r"""

        Returns
        -------
        int
            the number of arcs in the graph

        """
        return _pyAgrum.MixedGraph_sizeArcs(self)

    def emptyArcs(self) -> bool:
        r"""

        Check if the graph doesn't contains arcs.

        Returns
        -------
        bool
            True if the graph doesn't contains arcs

        """
        return _pyAgrum.MixedGraph_emptyArcs(self)

    def adjacents(self, *args) -> List[int]:
        r"""

        adjacents nodes are neighbours (not oriented), children and parents

        Parameters
        ----------
        id : int
        	the id of the node

        Returns
        -------
        set
            the set of node ids.

        """
        return _pyAgrum.MixedGraph_adjacents(self, *args)

    def mixedOrientedPath(self, *args) -> "pyAgrum.YetUnWrapped":
        r"""

        Parameters
        ----------
        node1 : int
        	the id form which the path begins
        node2 : int
        	the id to witch the path ends

        Returns
        -------
        List
        	 a path from node1 to node2, using edges and/or arcs (following the direction of the arcs). If no path is found, the returned list is empty.

        """
        return _pyAgrum.MixedGraph_mixedOrientedPath(self, *args)

    def mixedUnorientedPath(self, *args) -> "pyAgrum.YetUnWrapped":
        r"""

        Parameters
        ----------
        node1 : int
        	the id from which the path begins
        node2 : int
        	the id to which the path ends

        Returns
        -------
        List
        	 a path from node1 to node2, using edges and/or arcs (not necessarily following the direction of the arcs). If no path is found, the list is empty.


        """
        return _pyAgrum.MixedGraph_mixedUnorientedPath(self, *args)

# Register MixedGraph in _pyAgrum:
_pyAgrum.MixedGraph_swigregister(MixedGraph)

class CliqueGraph(UndiGraph):
    r"""

    CliqueGraph represents a Clique Graph.

    CliqueGraph() -> CliqueGraph
        default constructor

    CliqueGraph(src) -> CliqueGraph
        Parameter
            * **src** (*pyAgrum.CliqueGraph*) -- the CliqueGraph to copy

    """

    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):
        _pyAgrum.CliqueGraph_swiginit(self, _pyAgrum.new_CliqueGraph(*args))
    __swig_destroy__ = _pyAgrum.delete_CliqueGraph

    def addEdge(self, first: int, second: int) -> None:
        r"""

        Insert a new edge into the graph.

        Parameters
        ----------
        n1 : int
          the id of one node of the new inserted edge
        n2 : int
          the id of the other node of the new inserted edge

        Raises
        ------
        pyAgrum.InvalidNode
          If n1 or n2 does not belong to the graph nodes.

        """
        return _pyAgrum.CliqueGraph_addEdge(self, first, second)

    def eraseEdge(self, edge: "pyAgrum.Edge") -> None:
        r"""

        Erase the edge between n1 and n2.

        Parameters
        ----------
        n1 : int
          the id of the tail node
        n2 : int
          the id of the head node

        """
        return _pyAgrum.CliqueGraph_eraseEdge(self, edge)

    def clearEdges(self) -> None:
        r"""

        Remove all edges and their separators 

        """
        return _pyAgrum.CliqueGraph_clearEdges(self)

    def addNode(self, *args) -> None:
        r"""

        Returns
        -------
        int
          the new NodeId

        """
        return _pyAgrum.CliqueGraph_addNode(self, *args)

    def eraseNode(self, node: int) -> None:
        r"""

        Erase the node and all the adjacent edges.

        Parameters
        ----------
        id : int
          the id of the node

        """
        return _pyAgrum.CliqueGraph_eraseNode(self, node)

    def clear(self) -> None:
        r"""

        Remove all the nodes and edges from the graph.

        """
        return _pyAgrum.CliqueGraph_clear(self)

    def container(self, idNode: int) -> int:
        r"""

        Parameters
        ----------
        idNode : int
          the id of the node

        Returns
        -------
        int
          the id of a clique containing the node

        Raises
        ------
        pyAgrum.NotFound
          If no clique contains idNode  

        """
        return _pyAgrum.CliqueGraph_container(self, idNode)

    def setClique(self, idClique: int, new_clique: List[int]) -> None:
        r"""

        changes the set of nodes included into a given clique

        Parameters
        ----------
        idClique : int
          the id of the clique
        new_clique : Set
          the new set of nodes to be included in the clique

        Raises
        ------
        pyAgrum.NotFound
          If idClique is not a clique of the graph

        """
        return _pyAgrum.CliqueGraph_setClique(self, idClique, new_clique)

    def addToClique(self, clique_id: int, node_id: int) -> None:
        r"""

        Change the set of nodes included into a given clique and returns the new set 

        Parameters
        ----------
        clique_id : int
          the id of the clique
        node_id : int
          the id of the node

        Raises
        ------
        pyAgrum.NotFound
          If clique_id does not exist
        pyAgrum.DuplicateElement
          If clique_id set already contains the ndoe

        """
        return _pyAgrum.CliqueGraph_addToClique(self, clique_id, node_id)

    def eraseFromClique(self, clique_id: int, node_id: int) -> None:
        r"""

        Remove a node from a clique

        Parameters
        ----------
        clique_id : int
          the id of the clique
        node_id : int
          the id of the node

        Raises
        ------
        pyAgrum.NotFound
          If clique_id does not exist

        """
        return _pyAgrum.CliqueGraph_eraseFromClique(self, clique_id, node_id)

    def containerPath(self, node1: int, node2: int) -> "pyAgrum.YetUnWrapped":
        r"""

        Parameters
        ----------
        node1 : int
          the id of one node
        node2 : int
          the id of the other node

        Returns
        -------
        List
          a path from a clique containing node1 to a clique containing node2

        Raises
        ------
        pyAgrum.NotFound
          If such path cannot be found

        """
        return _pyAgrum.CliqueGraph_containerPath(self, node1, node2)

    def hasRunningIntersection(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if the running intersection property holds 

        """
        return _pyAgrum.CliqueGraph_hasRunningIntersection(self)

    def isJoinTree(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if the graph is a join tree 

        """
        return _pyAgrum.CliqueGraph_isJoinTree(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format

        """
        return _pyAgrum.CliqueGraph_toDot(self)

    def __ne__(self, _from: "CliqueGraph") -> bool:
        return _pyAgrum.CliqueGraph___ne__(self, _from)

    def __eq__(self, _from: "CliqueGraph") -> bool:
        return _pyAgrum.CliqueGraph___eq__(self, _from)

    def clique(self, clique: int) -> object:
        r"""

        Parameters
        ----------
        idClique : int
          the id of the clique

        Returns
        -------
        Set
          The set of nodes included in the clique

        Raises
        ------
        pyAgrum.NotFound
          If the clique does not belong to the clique graph

        """
        return _pyAgrum.CliqueGraph_clique(self, clique)

    def separator(self, cliq1: int, cliq2: int) -> object:
        r"""

        Parameters
        ----------
        edge : pyAgrum.Edge
          the edge to be checked
        clique1 : int 
          one extremity of the edge
        clique : int 
          the other extremity of the edge

        Returns
        -------
        Set
          the separator included in a given edge

        Raises
        ------
        pyAgrum.NotFound
          If the edge does not belong to the clique graph

        """
        return _pyAgrum.CliqueGraph_separator(self, cliq1, cliq2)

    def toDotWithNames(self,bn):
        """
        Parameters
        ----------
        bn : pyAgrum.BayesNet
        a Bayesian network

        Returns
        -------
        str
          a friendly display of the graph in DOT format where ids have been changed according to their correspondance in the BN
        """
        def nameFromId(m):
          return " ".join([bn.variable(int(n)).name()
                           for n in m.group().split("-")])
        import re
        m = re.compile('(?<=label=\")\d+[\-\d+]*')
        return m.sub(nameFromId,self.toDot())


# Register CliqueGraph in _pyAgrum:
_pyAgrum.CliqueGraph_swigregister(CliqueGraph)

class Instantiation(object):
    r"""

    Class for assigning/browsing values to tuples of discrete variables.

    Instantiation is designed to assign values to tuples of variables and to efficiently loop over values of subsets of variables.

    Instantiation() -> Instantiation
        default constructor

    Instantiation(aI) -> Instantiation
        Parameters:
          * **aI** (*pyAgrum.Instantiation*) -- the Instantiation we copy

    Returns
    -------
    pyAgrum.Instantiation
    	An empty tuple or a copy of the one in parameters

    Instantiation is subscriptable therefore values can be easily accessed/modified.

    Examples
    --------
    >>> ## Access the value of A in an instantiation aI
    >>> valueOfA = aI['A']
    >>> ## Modify the value
    >>> aI['A'] = newValueOfA

    """

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

    def __init__(self, *args):
        _pyAgrum.Instantiation_swiginit(self, _pyAgrum.new_Instantiation(*args))
    __swig_destroy__ = _pyAgrum.delete_Instantiation

    def nbrDim(self) -> int:
        r"""

        Returns
        -------
        int
            The number of variables in the Instantiation.

        """
        return _pyAgrum.Instantiation_nbrDim(self)

    def add(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Adds a new variable in the Instantiation.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
          The new variable added to the Instantiation

        Raises
        ------
        DuplicateElement
          If the variable is already in this Instantiation


        """
        val = _pyAgrum.Instantiation_add(self, v)

        return self


        return val


    def erase(self, *args) -> None:
        r"""

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
          The variable to be removed from this Instantiation.

        Raises
        ------
        NotFound
          If v does not belong to this Instantiation.

        """
        return _pyAgrum.Instantiation_erase(self, *args)

    def clear(self) -> None:
        r"""

        Erase all variables from an Instantiation.

        """
        return _pyAgrum.Instantiation_clear(self)

    def domainSize(self) -> int:
        r"""

        Returns
        -------
        int
            The product of the variable's domain size in the Instantiation.

        """
        return _pyAgrum.Instantiation_domainSize(self)

    def pos(self, v: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Returns
        -------
        int
           the position of the variable v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            the variable for which its position is return.

        Raises
        ------
        NotFound
          If v does not belong to the instantiation.

        """
        return _pyAgrum.Instantiation_pos(self, v)

    def val(self, *args) -> int:
        r"""

        Parameters
        ----------
        i : int
        	The index of the variable.
        var : pyAgrum.DiscreteVariable
        	The variable the value of which we wish to know

        Returns
        -------
        int
        	the current value of the variable.

        Raises
        ------
        NotFound
          If the element cannot be found.

        """
        return _pyAgrum.Instantiation_val(self, *args)

    def variable(self, *args) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        i : int
          The index of the variable

        Returns
        -------
        pyAgrum.DiscreteVariable
          the variable at position i in the tuple.

        Raises
        ------
        NotFound
          If the element cannot be found.

        """
        return _pyAgrum.Instantiation_variable(self, *args)

    def chgVal(self, *args) -> "pyAgrum.Instantiation":
        r"""

        Assign newval to v (or to the variable at position varPos) in the Instantiation.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable or string
          The variable whose value is assigned (or its name)
        varPos : int
          The index of the variable whose value is assigned in the tuple of variables of the Instantiation
        newval : int or string
          The index of the value assigned (or its name)

        Returns
        -------
        pyAgrum.Instantiation
            The modified instantiation

        Raises
        ------
        NotFound
          If variable v does not belong to the instantiation.
        OutOfBound
          If newval is not a possible value for the variable.

        """
        return _pyAgrum.Instantiation_chgVal(self, *args)

    def setVals(self, i: "Instantiation") -> "pyAgrum.Instantiation":
        r"""

        Assign the values from i in the Instantiation.

        Parameters
        ----------
        i : pyAgrum.Instantiation
          An Instantiation in which the new values are searched

        Returns
        -------
        pyAgrum.Instantiation
          a reference to the instantiation

        """
        return _pyAgrum.Instantiation_setVals(self, i)

    def contains(self, *args) -> bool:
        r"""

        Indicates whether a given variable belongs to the Instantiation.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable for which the test is made.

        Returns
        -------
        bool :
            True if the variable is in the Instantiation.

        """
        return _pyAgrum.Instantiation_contains(self, *args)

    def variablesSequence(self) -> List[object]:
        r"""

        Returns
        -------
        List
            the sequence of DiscreteVariable of this instantiation.

        """
        return _pyAgrum.Instantiation_variablesSequence(self)

    def empty(self) -> bool:
        r"""

        Returns
        -------
        bool
            True if the instantiation is empty.

        """
        return _pyAgrum.Instantiation_empty(self)

    def inOverflow(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if the current value of the tuple is correct

        """
        return _pyAgrum.Instantiation_inOverflow(self)

    def unsetOverflow(self) -> None:
        r"""

        Removes the flag overflow.

        """
        return _pyAgrum.Instantiation_unsetOverflow(self)

    def unsetEnd(self) -> None:
        r"""

        Alias for unsetOverflow().

        """
        return _pyAgrum.Instantiation_unsetEnd(self)

    def end(self) -> bool:
        r"""

        Returns
        -------
        bool
            True if the Instantiation reached the end.

        """
        return _pyAgrum.Instantiation_end(self)

    def rend(self) -> bool:
        r"""

        Returns
        -------
        bool:
          True if the Instantiation reached the rend.

        """
        return _pyAgrum.Instantiation_rend(self)

    def inc(self) -> None:
        r"""

        Operator ++.

        """
        return _pyAgrum.Instantiation_inc(self)

    def dec(self) -> None:
        r"""

        Operator --.

        """
        return _pyAgrum.Instantiation_dec(self)

    def incIn(self, i: "Instantiation") -> None:
        r"""

        Operator ++ for the variables in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
            The set of variables to increment in this Instantiation.

        """
        return _pyAgrum.Instantiation_incIn(self, i)

    def decIn(self, i: "Instantiation") -> None:
        r"""

        Operator -- for the variables in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
          The set of variables to decrement in this Instantiation

        """
        return _pyAgrum.Instantiation_decIn(self, i)

    def incOut(self, i: "Instantiation") -> None:
        r"""

        Operator ++ for the variables not in i.

        Parameters
        ----------
        i : Instantiation
            The set of variable to not increment in this Instantiation.

        """
        return _pyAgrum.Instantiation_incOut(self, i)

    def decOut(self, i: "Instantiation") -> None:
        r"""

        Operator -- for the variables not in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
          The set of variables to not decrement in this Instantiation.

        """
        return _pyAgrum.Instantiation_decOut(self, i)

    def incNotVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Operator ++ for vars which are not v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable not to increment in this Instantiation.

        """
        return _pyAgrum.Instantiation_incNotVar(self, v)

    def decNotVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Operator -- for vars which are not v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
          The variable not to decrement in this Instantiation.

        """
        return _pyAgrum.Instantiation_decNotVar(self, v)

    def incVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Operator ++ for variable v only.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable to increment in this Instantiation.

        Raises
        ------
        NotFound
          If variable v does not belong to the Instantiation.

        """
        return _pyAgrum.Instantiation_incVar(self, v)

    def decVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Operator -- for variable v only.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
         The variable to decrement in this Instantiation.

        Raises
        ------
        NotFound
          If variable v does not belong to the Instantiation.

        """
        return _pyAgrum.Instantiation_decVar(self, v)

    def setFirst(self) -> None:
        r"""

        Assign the first values to the tuple of the Instantiation.

        """
        return _pyAgrum.Instantiation_setFirst(self)

    def setLast(self) -> None:
        r"""

        Assign the last values in the Instantiation.

        """
        return _pyAgrum.Instantiation_setLast(self)

    def setFirstIn(self, i: "Instantiation") -> None:
        r"""

        Assign the first values in the Instantiation for the variables in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
          The variables to which their first value is assigned in this Instantiation.

        """
        return _pyAgrum.Instantiation_setFirstIn(self, i)

    def setLastIn(self, i: "Instantiation") -> None:
        r"""

        Assign the last values in the Instantiation for the variables in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
            The variables to which their last value is assigned in this Instantiation.

        """
        return _pyAgrum.Instantiation_setLastIn(self, i)

    def setFirstOut(self, i: "Instantiation") -> None:
        r"""

        Assign the first values in the Instantiation for the variables not in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
            The variable that will not be set to their first value in this Instantiation.

        """
        return _pyAgrum.Instantiation_setFirstOut(self, i)

    def setLastOut(self, i: "Instantiation") -> None:
        r"""

        Assign the last values in the Instantiation for the variables not in i.

        Parameters
        ----------
        i : pyAgrum.Instantiation
            The variables that will not be set to their last value in this Instantiation.

        """
        return _pyAgrum.Instantiation_setLastOut(self, i)

    def setFirstNotVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Assign the first values to variables different of v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
          The variable that will not be set to its first value in this Instantiation.

        """
        return _pyAgrum.Instantiation_setFirstNotVar(self, v)

    def setLastNotVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Assign the last values to variables different of v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable that will not be set to its last value in this Instantiation.

        """
        return _pyAgrum.Instantiation_setLastNotVar(self, v)

    def setFirstVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Assign the first value in the Instantiation for var v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable that will be set to its first value in this Instantiation.

        """
        return _pyAgrum.Instantiation_setFirstVar(self, v)

    def setLastVar(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Assign the last value in the Instantiation for var v.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
          The variable that will be set to its last value in this Instantiation.

        """
        return _pyAgrum.Instantiation_setLastVar(self, v)

    def __eq__(self, other: "Instantiation") -> bool:
        return _pyAgrum.Instantiation___eq__(self, other)

    def __iadd__(self, depl: int) -> "pyAgrum.Instantiation":
        return _pyAgrum.Instantiation___iadd__(self, depl)

    def __isub__(self, depl: int) -> "pyAgrum.Instantiation":
        return _pyAgrum.Instantiation___isub__(self, depl)

    def hamming(self) -> int:
        r"""

        Returns
        -------
        int
          the hamming distance of this instantiation.

        """
        return _pyAgrum.Instantiation_hamming(self)

    def reorder(self, *args) -> None:
        r"""

        Reorder vars of this instantiation giving the order in v (or i).

        Parameters
        ----------
        i : pyAgrum.Instantiation
          The sequence of variables with which to reorder this Instantiation.
        v : list
            The new order of variables for this Instantiation.

        """
        return _pyAgrum.Instantiation_reorder(self, *args)

    def __repr__(self) -> str:
        return _pyAgrum.Instantiation___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.Instantiation___str__(self)

    def setMutable(self) -> None:
        return _pyAgrum.Instantiation_setMutable(self)

    def isMutable(self) -> bool:
        return _pyAgrum.Instantiation_isMutable(self)

    def todict(self, withLabels: bool=False) -> object:
        r"""

        Create a dictionary `{variable_name:value}` from an instantiation

        Parameters
        ----------
        withLabels : boolean
        	The value will be a label (string) if True. It will be a position (int) if False.

        Returns
        -------
        Dict[str,int]
            The dictionary

        """
        return _pyAgrum.Instantiation_todict(self, withLabels)

    def fromdict(self, dict: object) -> None:
        r"""

        Change the values in an instantiation from a dictionary `{variable_name:value}` where value can be a position (int) or a label (string).

        If a variable_name does not occur in the instantiation, nothing is done.

        Warnings
        --------
            OutOfBounds raised if a value cannot be found.

        """
        return _pyAgrum.Instantiation_fromdict(self, dict)

    def __setitem__(self,key,item):
      self.chgVal(key,item)

    def __getitem__(self,key):
      return self.val(self.variable(key))

    def variablesSequence(self):
      """
      Returns
      -------
      list
          a list containing the sequence of variables
      """
      varlist = []
      for i in range(0, self.nbrDim()):
          varlist.append(self.variable(i))
      return varlist

    def addVarsFromModel(self,model,names):
      r"""
      From a graphical model, add all the variable whose names are in the iterable

      Parameters
      ----------
      model : pyAgrum.GraphicalModel
      a (discrete) graphical model such as Bayesian network, Markov network, Influence Diagram, etc.

      names : iterable of strings
      a list/set/etc of names of variables (as string)

      Returns
      -------
      pyAgrum.Instantiation
      the current instantiation (self) in order to chain methods.
      """
      for name in names:
        self.add(model.variable(name))
      return self



# Register Instantiation in _pyAgrum:
_pyAgrum.Instantiation_swigregister(Instantiation)

GUM_DEFAULT_ITERATOR_NUMBER = _pyAgrum.GUM_DEFAULT_ITERATOR_NUMBER
class GraphicalModel(object):
    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_GraphicalModel

    def property(self, name: str) -> str:
        return _pyAgrum.GraphicalModel_property(self, name)

    def propertyWithDefault(self, name: str, byDefault: str) -> str:
        return _pyAgrum.GraphicalModel_propertyWithDefault(self, name, byDefault)

    def setProperty(self, name: str, value: str) -> None:
        return _pyAgrum.GraphicalModel_setProperty(self, name, value)

    def variableNodeMap(self) -> "pyAgrum.VariableNodeMap":
        return _pyAgrum.GraphicalModel_variableNodeMap(self)

    def size(self) -> int:
        return _pyAgrum.GraphicalModel_size(self)

    def empty(self) -> bool:
        return _pyAgrum.GraphicalModel_empty(self)

    def exists(self, *args) -> bool:
        return _pyAgrum.GraphicalModel_exists(self, *args)

    def names(self, *args) -> List[str]:
        return _pyAgrum.GraphicalModel_names(self, *args)

    def ids(self, names: "Vector_string") -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.GraphicalModel_ids(self, names)

    def nodeset(self, names: "Vector_string") -> List[int]:
        return _pyAgrum.GraphicalModel_nodeset(self, names)

    def nodes(self) -> Set[int]:
        return _pyAgrum.GraphicalModel_nodes(self)

    def completeInstantiation(self) -> "pyAgrum.Instantiation":
        return _pyAgrum.GraphicalModel_completeInstantiation(self)

    def variable(self, id: int) -> "pyAgrum.DiscreteVariable":
        return _pyAgrum.GraphicalModel_variable(self, id)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        return _pyAgrum.GraphicalModel_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        return _pyAgrum.GraphicalModel_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        return _pyAgrum.GraphicalModel_variableFromName(self, name)

    def log10DomainSize(self) -> float:
        return _pyAgrum.GraphicalModel_log10DomainSize(self)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.GraphicalModel_isIndependent(self, *args)

# Register GraphicalModel in _pyAgrum:
_pyAgrum.GraphicalModel_swigregister(GraphicalModel)
cvar = _pyAgrum.cvar
_list_end_safe_ = cvar._list_end_safe_
_list_end_ = cvar._list_end_

class DAGmodel(GraphicalModel):
    r"""

    Abstract class used by IBayesNet and InfluenceDiagram.

    """

    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_DAGmodel

    def dag(self) -> "pyAgrum.DAG":
        r"""

        Returns
        -------
        pyAgrum.DAG
        	a constant reference to the dag of this BayesNet.

        """
        val = _pyAgrum.DAGmodel_dag(self)

        val = DAG(val) # copying the DAG


        return val


    def size(self) -> int:
        r"""

        Returns
        -------
        int
            the number of nodes in the graph

        """
        return _pyAgrum.DAGmodel_size(self)

    def sizeArcs(self) -> int:
        r"""

        Returns
        -------
        int
            the number of arcs in the graph

        """
        return _pyAgrum.DAGmodel_sizeArcs(self)

    def nodes(self) -> Set[int]:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.DAGmodel_nodes(self)

    def exists(self, node: int) -> bool:
        return _pyAgrum.DAGmodel_exists(self, node)

    def arcs(self) -> Set[Tuple[int,int]]:
        r"""

        Returns
        -------
        list
        	The lisf of arcs in the graph

        """
        return _pyAgrum.DAGmodel_arcs(self)

    def existsArc(self, *args) -> bool:
        return _pyAgrum.DAGmodel_existsArc(self, *args)

    def parents(self, *args) -> List[int]:
        return _pyAgrum.DAGmodel_parents(self, *args)

    def family(self, *args) -> List[int]:
        return _pyAgrum.DAGmodel_family(self, *args)

    def children(self, *args) -> List[int]:
        return _pyAgrum.DAGmodel_children(self, *args)

    def descendants(self, *args) -> List[int]:
        return _pyAgrum.DAGmodel_descendants(self, *args)

    def ancestors(self, *args) -> List[int]:
        return _pyAgrum.DAGmodel_ancestors(self, *args)

    def moralizedAncestralGraph(self, *args) -> "pyAgrum.UndiGraph":
        return _pyAgrum.DAGmodel_moralizedAncestralGraph(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.DAGmodel_isIndependent(self, *args)

    def moralGraph(self, clear: bool=True) -> "pyAgrum.UndiGraph":
        r"""

        Returns the moral graph of the BayesNet, formed by adding edges between all pairs of nodes that have a common child, and then making all edges in the graph undirected.

        Returns
        -------
        pyAgrum.UndiGraph
        	The moral graph

        """
        return _pyAgrum.DAGmodel_moralGraph(self, clear)

    def topologicalOrder(self, clear: bool=True) -> List[int]:
        r"""

        Returns
        -------
        List
            the list of the nodes Ids in a topological order

        Raises
        ------
        pyAgrum.InvalidDirectedCycle
        	If this graph contains cycles

        """
        return _pyAgrum.DAGmodel_topologicalOrder(self, clear)

    def hasSameStructure(self, other: "pyAgrum.DAGmodel") -> bool:
        r"""

        Parameters
        ----------
        pyAgrum.DAGmodel
        	a direct acyclic model

        Returns
        -------
        bool
            True if all the named node are the same and all the named arcs are the same

        """
        return _pyAgrum.DAGmodel_hasSameStructure(self, other)

# Register DAGmodel in _pyAgrum:
_pyAgrum.DAGmodel_swigregister(DAGmodel)

class UGmodel(GraphicalModel):
    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_UGmodel

    def graph(self) -> "pyAgrum.UndiGraph":
        return _pyAgrum.UGmodel_graph(self)

    def size(self) -> int:
        return _pyAgrum.UGmodel_size(self)

    def sizeEdges(self) -> int:
        return _pyAgrum.UGmodel_sizeEdges(self)

    def nodes(self) -> Set[int]:
        return _pyAgrum.UGmodel_nodes(self)

    def exists(self, node: int) -> bool:
        return _pyAgrum.UGmodel_exists(self, node)

    def edges(self) -> Set[Tuple[int,int]]:
        return _pyAgrum.UGmodel_edges(self)

    def existsEdge(self, *args) -> bool:
        return _pyAgrum.UGmodel_existsEdge(self, *args)

    def neighbours(self, *args) -> List[int]:
        return _pyAgrum.UGmodel_neighbours(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.UGmodel_isIndependent(self, *args)

    def hasSameStructure(self, other: "pyAgrum.UGmodel") -> bool:
        return _pyAgrum.UGmodel_hasSameStructure(self, other)

# Register UGmodel in _pyAgrum:
_pyAgrum.UGmodel_swigregister(UGmodel)

class EssentialGraph(object):
    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):
        _pyAgrum.EssentialGraph_swiginit(self, _pyAgrum.new_EssentialGraph(*args))
    __swig_destroy__ = _pyAgrum.delete_EssentialGraph

    def mixedGraph(self) -> "pyAgrum.MixedGraph":
        r"""

        Returns
        -------
        pyAgrum.MixedGraph
        	the mixed graph

        """
        return _pyAgrum.EssentialGraph_mixedGraph(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format 

        """
        return _pyAgrum.EssentialGraph_toDot(self)

    def sizeArcs(self) -> int:
        r"""

        Returns
        -------
        int
            the number of arcs in the graph

        """
        return _pyAgrum.EssentialGraph_sizeArcs(self)

    def sizeEdges(self) -> int:
        r"""

        Returns
        -------
        int
            the number of edges in the graph

        """
        return _pyAgrum.EssentialGraph_sizeEdges(self)

    def sizeNodes(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of nodes in the graph

        """
        return _pyAgrum.EssentialGraph_sizeNodes(self)

    def size(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of nodes in the graph

        """
        return _pyAgrum.EssentialGraph_size(self)

    def skeleton(self) -> "pyAgrum.UndiGraph":
        return _pyAgrum.EssentialGraph_skeleton(self)

    def nodes(self) -> object:
        return _pyAgrum.EssentialGraph_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def arcs(self) -> object:
        r"""

        Returns
        -------
        list
        	The lisf of arcs in the EssentialGraph

        """
        return _pyAgrum.EssentialGraph_arcs(self)

    def parents(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        Set
            the set of the parents ids.

        """
        return _pyAgrum.EssentialGraph_parents(self, id)

    def children(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.EssentialGraph_children(self, id)

    def edges(self) -> object:
        r"""

        Returns
        -------
        List
          the list of the edges

        """
        return _pyAgrum.EssentialGraph_edges(self)

    def neighbours(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id : int
            the id of the checked node

        Returns
        -------
        Set
            The set of edges adjacent to the given node 

        """
        return _pyAgrum.EssentialGraph_neighbours(self, id)

# Register EssentialGraph in _pyAgrum:
_pyAgrum.EssentialGraph_swigregister(EssentialGraph)

class MarkovBlanket(object):
    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):
        _pyAgrum.MarkovBlanket_swiginit(self, _pyAgrum.new_MarkovBlanket(*args))
    __swig_destroy__ = _pyAgrum.delete_MarkovBlanket

    def dag(self) -> "pyAgrum.DAG":
        r"""

        Returns
        -------
        pyAgrum.DAG
          a copy of the DAG

        """
        return _pyAgrum.MarkovBlanket_dag(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format 

        """
        return _pyAgrum.MarkovBlanket_toDot(self)

    def sizeArcs(self) -> int:
        r"""

        Returns
        -------
        int
            the number of arcs in the graph

        """
        return _pyAgrum.MarkovBlanket_sizeArcs(self)

    def sizeNodes(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of nodes in the graph

        """
        return _pyAgrum.MarkovBlanket_sizeNodes(self)

    def size(self) -> int:
        r"""

        Returns
        -------
        int
            the number of nodes in the graph

        """
        return _pyAgrum.MarkovBlanket_size(self)

    def hasSameStructure(self, other: "pyAgrum.DAGmodel") -> bool:
        r"""

        Parameters
        ----------
        pyAgrum.DAGmodel
        	a direct acyclic model

        Returns
        -------
        bool
            True if all the named node are the same and all the named arcs are the same 

        """
        return _pyAgrum.MarkovBlanket_hasSameStructure(self, other)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.MarkovBlanket_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def arcs(self) -> object:
        r"""

        Returns
        -------
        List
        	the list of the arcs

        """
        return _pyAgrum.MarkovBlanket_arcs(self)

    def parents(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        Set
            the set of the parents ids.

        """
        return _pyAgrum.MarkovBlanket_parents(self, id)

    def children(self, id: int) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.MarkovBlanket_children(self, id)

# Register MarkovBlanket in _pyAgrum:
_pyAgrum.MarkovBlanket_swigregister(MarkovBlanket)

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

    def __init__(self):
        _pyAgrum.StructuralComparator_swiginit(self, _pyAgrum.new_StructuralComparator())
    __swig_destroy__ = _pyAgrum.delete_StructuralComparator

    def compare(self, *args) -> None:
        r"""

        Use to compare the edges/arcs of two structure of the same type and same sizes (either DiGraph, UndiGraph or MixedGraph).

        Could be use to compare a BN and its learned version.

        Parameters
        ----------
        ref :
        	the structure of reference
        test :
        	the structure we want to test

        """
        return _pyAgrum.StructuralComparator_compare(self, *args)

    def precision_skeleton(self) -> float:
        r"""

        Rate of true postive over labelized edges.

        Returns
        -------
        float
        	the precision of the tested graph skeleton

        """
        return _pyAgrum.StructuralComparator_precision_skeleton(self)

    def recall_skeleton(self) -> float:
        r"""

        Rate of true postive over labelized edges.

        Returns
        -------
        float
        	the recall of the tested graph skeleton

        """
        return _pyAgrum.StructuralComparator_recall_skeleton(self)

    def f_score_skeleton(self) -> float:
        r"""

        Harmonic mean between recall and precision.

        Returns
        -------
        float
        	the tarmonic mean of the tested graph skeleton

        """
        return _pyAgrum.StructuralComparator_f_score_skeleton(self)

    def precision(self) -> float:
        r"""

        Rate of true postive over postively labelized arcs/edges.

        Returns
        -------
        float
        	the precision of the tested graph

        """
        return _pyAgrum.StructuralComparator_precision(self)

    def recall(self) -> float:
        r"""

        Rate of true postive over labelized arcs/edges.

        Returns
        -------
        float
        	the recall of the tested graph

        """
        return _pyAgrum.StructuralComparator_recall(self)

    def f_score(self) -> float:
        r"""

        Harmonic mean between recall and precision.

        Returns
        -------
        float
        	the harmonic mean of the tested graph

        """
        return _pyAgrum.StructuralComparator_f_score(self)

# Register StructuralComparator in _pyAgrum:
_pyAgrum.StructuralComparator_swigregister(StructuralComparator)

class ApproximationScheme(object):
    r"""

    Used to parametrize stopping criteria in approximate inference or learning algorithm.

    ApproximationScheme(verbosity=False) -> ApproximationScheme
        Parameters:
          * **verbosity** (*bool) -- to keep (or not) tracks of the learning process (history of epsilons)

    """

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

    def __init__(self, verbosity: bool=False):
        _pyAgrum.ApproximationScheme_swiginit(self, _pyAgrum.new_ApproximationScheme(verbosity))
    __swig_destroy__ = _pyAgrum.delete_ApproximationScheme

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.ApproximationScheme_setEpsilon(self, eps)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.ApproximationScheme_epsilon(self)

    def disableEpsilon(self) -> None:
        r"""

        Disable epsilon as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_disableEpsilon(self)

    def enableEpsilon(self) -> None:
        r"""

        Enable epsilon as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_enableEpsilon(self)

    def isEnabledEpsilon(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if epsilon is used as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_isEnabledEpsilon(self)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.ApproximationScheme_setMinEpsilonRate(self, rate)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.ApproximationScheme_minEpsilonRate(self)

    def disableMinEpsilonRate(self) -> None:
        r"""

        Disable a min epsilon rate as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_disableMinEpsilonRate(self)

    def enableMinEpsilonRate(self) -> None:
        r"""

        Enable a min epsilon rate as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_enableMinEpsilonRate(self)

    def isEnabledMinEpsilonRate(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if epsilon rate is used as a stopping criterion

        """
        return _pyAgrum.ApproximationScheme_isEnabledMinEpsilonRate(self)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.ApproximationScheme_setMaxIter(self, max)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.ApproximationScheme_maxIter(self)

    def disableMaxIter(self) -> None:
        r"""

        Disable max iterations as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_disableMaxIter(self)

    def enableMaxIter(self) -> None:
        r"""

        Enable max iterations as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_enableMaxIter(self)

    def isEnabledMaxIter(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if max iterations is used as a stopping criterion

        """
        return _pyAgrum.ApproximationScheme_isEnabledMaxIter(self)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.ApproximationScheme_setMaxTime(self, timeout)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.ApproximationScheme_maxTime(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.ApproximationScheme_currentTime(self)

    def disableMaxTime(self) -> None:
        r"""

        Disable max time as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_disableMaxTime(self)

    def enableMaxTime(self) -> None:
        r"""

        Enable max time as a stopping criterion.

        """
        return _pyAgrum.ApproximationScheme_enableMaxTime(self)

    def isEnabledMaxTime(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if max time is used as a stopping criterion

        """
        return _pyAgrum.ApproximationScheme_isEnabledMaxTime(self)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.ApproximationScheme_setPeriodSize(self, p)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.ApproximationScheme_periodSize(self)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.ApproximationScheme_setVerbosity(self, v)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.ApproximationScheme_verbosity(self)

    def stateApproximationScheme(self) -> int:
        r"""

        Returns
        -------
        int
          the state of the approximation scheme

        """
        return _pyAgrum.ApproximationScheme_stateApproximationScheme(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.ApproximationScheme_nbrIterations(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.ApproximationScheme_history(self)

    def initApproximationScheme(self) -> None:
        r"""

        Initiate the approximation scheme.

        """
        return _pyAgrum.ApproximationScheme_initApproximationScheme(self)

    def startOfPeriod(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if it is a start of a period

        """
        return _pyAgrum.ApproximationScheme_startOfPeriod(self)

    def updateApproximationScheme(self, incr: int=1) -> None:
        r"""

        Update the approximation scheme.

        """
        return _pyAgrum.ApproximationScheme_updateApproximationScheme(self, incr)

    def remainingBurnIn(self) -> int:
        r"""

        Returns
        -------
        int
          the number of remaining burn in

        """
        return _pyAgrum.ApproximationScheme_remainingBurnIn(self)

    def stopApproximationScheme(self) -> None:
        r"""

        Stop the approximation scheme.

        """
        return _pyAgrum.ApproximationScheme_stopApproximationScheme(self)

    def continueApproximationScheme(self, error: float) -> bool:
        r"""

        Continue the approximation scheme.

        Parameters
        ----------
        error : float

        """
        return _pyAgrum.ApproximationScheme_continueApproximationScheme(self, error)

# Register ApproximationScheme in _pyAgrum:
_pyAgrum.ApproximationScheme_swigregister(ApproximationScheme)

FindBarrenNodesType_FIND_NO_BARREN_NODES = _pyAgrum.FindBarrenNodesType_FIND_NO_BARREN_NODES
FindBarrenNodesType_FIND_BARREN_NODES = _pyAgrum.FindBarrenNodesType_FIND_BARREN_NODES

def randomDistribution(n: int) -> List[float]:
    r"""

    Parameters
    ----------
    n : int
      The number of modalities for the ditribution.

    Returns
    -------
    a random discrete distribution. 

    """
    return _pyAgrum.randomDistribution(n)
class DiscretizedVariable(IDiscretizedVariable):
    r"""

    DiscretizedVariable is a discrete random variable with a set of ``ticks`` defining intervalls.

    DiscretizedVariable(aName, aDesc='') -> DiscretizedVariable`
        Parameters:
            * **aName** (*str*) -- the name of the variable
            * **aDesc** (*str*) -- the (optional) description of the variable

    DiscretizedVariable(aDDRV) -> DiscretizedVariable
        Parameters:
            * **aDDRV** (*pyAgrum.DiscretizedVariable*) -- the pyAgrum.DiscretizedVariable that will be copied

    Examples
    --------
    >>> import pyAgrum as gum
    >>> vX=gum.DiscretizedVariable('X','X has been discretized').addTick(1).addTick(2).addTick(3).addTick(3.1415)
    >>> print(vX)
    X:Discretized(<[1;2[,[2;3[,[3;3.1415]>)
    >>> vX.isTick(4)
    False
    >>> vX.labels()
    ('[1;2[', '[2;3[', '[3;3.1415]')
    >>> # where is the real value 2.5 ?
    >>> vX.index('2.5')
    1

    """

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

    def __init__(self, *args):
        _pyAgrum.DiscretizedVariable_swiginit(self, _pyAgrum.new_DiscretizedVariable(*args))
    __swig_destroy__ = _pyAgrum.delete_DiscretizedVariable

    def clone(self) -> "pyAgrum.DiscretizedVariable":
        r"""

        Returns
        -------
        pyAgrum.DiscretizedVariable
        	a copy of the DiscretizedVariable

        """
        return _pyAgrum.DiscretizedVariable_clone(self)

    def varType(self) -> int:
        r"""

        returns the type of variable

        Returns
        -------
        int :
        	the type of the variable, 0: DiscretizedVariable, 1: LabelizedVariable, 2: RangeVariable

        """
        return _pyAgrum.DiscretizedVariable_varType(self)

    def isTick(self, aTick: float) -> bool:
        r"""

        Parameters
        ----------
        aTick : float
        	the Tick to be tested

        Returns
        -------
        bool :
        	True if the Tick already exists

        """
        return _pyAgrum.DiscretizedVariable_isTick(self, aTick)

    def addTick(self,*args):
        """
        Parameters
        ----------
        aTick : float
            the Tick to be added

        Returns
        -------
        pyAgrum.DiscretizedVariable
            the discretized variable

        Raises
        ------
        gum.DefaultInLabel
            If the tick is already defined
        """
        _pyAgrum.DiscretizedVariable_addTick(self,*args)
        return self



    def eraseTicks(self) -> None:
        r"""

        erase all the Ticks 

        """
        return _pyAgrum.DiscretizedVariable_eraseTicks(self)

    def label(self, i: int) -> str:
        r"""

        Parameters
        ----------
        i : int
        	the index of the label we wish to return

        Returns
        -------
        str
        	the indice-th label

        Raises
        ------
        pyAgrum.OutOfBound
        	If the variable does not contain the label

        """
        return _pyAgrum.DiscretizedVariable_label(self, i)

    def numerical(self, indice: int) -> float:
        r"""

        Parameters
        ----------
        indice : int
        	an index

        Returns
        -------
        float
        	the numerical representation of the indice-th value

        """
        return _pyAgrum.DiscretizedVariable_numerical(self, indice)

    def index(self, label: str) -> int:
        r"""

        Parameters
        ----------
        label : str
        	a label

        Returns
        -------
        int
        	the indice of the label

        """
        return _pyAgrum.DiscretizedVariable_index(self, label)

    def domainSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of modalities in the variable domain

        """
        return _pyAgrum.DiscretizedVariable_domainSize(self)

    def domain(self) -> str:
        r"""

        Returns
        -------
        str
            the domain of the variable as a string

        """
        return _pyAgrum.DiscretizedVariable_domain(self)

    def stype(self) -> str:
        return _pyAgrum.DiscretizedVariable_stype(self)

    def tick(self, i: int) -> float:
        r"""

        Indicate the index of the Tick

        Parameters
        ----------
        i : int
        	the index of the Tick

        Returns
        -------
        aTick : float
        	the index-th Tick

        Raises
        ------
        pyAgrum.NotFound
        	If the index is greater than the number of Ticks

        """
        return _pyAgrum.DiscretizedVariable_tick(self, i)

    def ticks(self) -> List[float]:
        r"""

        Returns
        -------
        tuple :
        	a tuple containing all the Ticks

        """
        return _pyAgrum.DiscretizedVariable_ticks(self)

    def __repr__(self) -> str:
        return _pyAgrum.DiscretizedVariable___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.DiscretizedVariable___str__(self)

# Register DiscretizedVariable in _pyAgrum:
_pyAgrum.DiscretizedVariable_swigregister(DiscretizedVariable)

class MultiDimContainer(object):
    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 - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _pyAgrum.delete_MultiDimContainer

    def set(self, i: "Instantiation", value: float) -> None:
        return _pyAgrum.MultiDimContainer_set(self, i, value)

    def get(self, i: "Instantiation") -> float:
        return _pyAgrum.MultiDimContainer_get(self, i)

    def fill(self, d: float) -> None:
        return _pyAgrum.MultiDimContainer_fill(self, d)

    def populate(self, *args) -> None:
        return _pyAgrum.MultiDimContainer_populate(self, *args)

    def copyFrom(self, *args) -> None:
        return _pyAgrum.MultiDimContainer_copyFrom(self, *args)

    def extractFrom(self, src: "pyAgrum.Potential", mask: "Instantiation") -> None:
        return _pyAgrum.MultiDimContainer_extractFrom(self, src, mask)

    def content(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.MultiDimContainer_content(self, *args)

    def getMasterRef(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.MultiDimContainer_getMasterRef(self, *args)

    def copy(self, src: "pyAgrum.Potential") -> None:
        return _pyAgrum.MultiDimContainer_copy(self, src)

    def newFactory(self) -> "pyAgrum.Potential":
        return _pyAgrum.MultiDimContainer_newFactory(self)

    def toString(self, *args) -> str:
        return _pyAgrum.MultiDimContainer_toString(self, *args)

    def __eq__(self, p: "pyAgrum.Potential") -> bool:
        return _pyAgrum.MultiDimContainer___eq__(self, p)

    def __ne__(self, p: "pyAgrum.Potential") -> bool:
        return _pyAgrum.MultiDimContainer___ne__(self, p)

    def apply(self, f: "std::function< float (float) >") -> None:
        return _pyAgrum.MultiDimContainer_apply(self, f)

    def reduce(self, f: "std::function< float (float,float) >", base: float) -> float:
        return _pyAgrum.MultiDimContainer_reduce(self, f, base)

    def beginMultipleChanges(self) -> None:
        return _pyAgrum.MultiDimContainer_beginMultipleChanges(self)

    def endMultipleChanges(self, *args) -> None:
        return _pyAgrum.MultiDimContainer_endMultipleChanges(self, *args)

# Register MultiDimContainer in _pyAgrum:
_pyAgrum.MultiDimContainer_swigregister(MultiDimContainer)

class Potential(object):
    r"""

    Class representing a potential.

    Potential() -> Potential
        default constructor

    Potential(src) -> Potential
        Parameters:
            * **src** (*pyAgrum.Potential*) -- the Potential to copy

    """

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

    def __init__(self, *args):
        _pyAgrum.Potential_swiginit(self, _pyAgrum.new_Potential(*args))

        self._list_vars=list()



    __swig_destroy__ = _pyAgrum.delete_Potential

    def newFactory(self) -> "pyAgrum.Potential":
        r"""

        Erase the Potential content and create a new empty one.

        Returns
        -------
        pyAgrum.Potential
         a reference to the new Potential

        """
        return _pyAgrum.Potential_newFactory(self)

    def random(self) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_random(self)

    def randomDistribution(self) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_randomDistribution(self)

    def randomCPT(self) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_randomCPT(self)

    def noising(self, alpha: float) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_noising(self, alpha)

    def isNonZeroMap(self) -> "pyAgrum.Potential":
        r"""

        Returns
        -------
        pyAgrum.Potential
          a boolean-like potential using the predicate isNonZero

        """
        return _pyAgrum.Potential_isNonZeroMap(self)

    def sum(self) -> float:
        r"""

        Returns
        -------
        float :
          the sum of all elements in the Potential

        """
        return _pyAgrum.Potential_sum(self)

    def product(self) -> float:
        r"""

        Returns
        -------
        float
          the product of all elements in the Potential

        """
        return _pyAgrum.Potential_product(self)

    def max(self) -> float:
        r"""

        Returns
        -------
        float
          the maximum of all elements in the Potential

        """
        return _pyAgrum.Potential_max(self)

    def min(self) -> float:
        r"""

        Returns
        -------
        float
          the min of all elements in the Potential

        """
        return _pyAgrum.Potential_min(self)

    def maxNonOne(self) -> float:
        r"""

        Returns
        -------
        float
          the maximum of non one elements in the Potential

        Raises
        ------
        pyAgrum.NotFound
          If all value == 1.0

        """
        return _pyAgrum.Potential_maxNonOne(self)

    def minNonZero(self) -> float:
        r"""

        Returns
        -------
        float
          the min of non zero elements in the Potential

        Raises
        ------
        pyAgrum.NotFound
          If all value == 0.0

        """
        return _pyAgrum.Potential_minNonZero(self)

    def findAll(self, v: float) -> List[Dict[str,int]]:
        return _pyAgrum.Potential_findAll(self, v)

    def argmax(self) -> List[Dict[str,int]]:
        return _pyAgrum.Potential_argmax(self)

    def argmin(self) -> List[Dict[str,int]]:
        return _pyAgrum.Potential_argmin(self)

    def entropy(self) -> float:
        r"""

        Returns
        -------
        float
          the entropy of the potential

        """
        return _pyAgrum.Potential_entropy(self)

    def reorganize(self, *args) -> "pyAgrum.Potential":
        r"""

        Create a new Potential with another order.

        Returns
        -------
        varnames : list
          a list of the var names in the new order

        Returns
        -------
        pyAgrum.Potential
          a reference to the modified potential

        """
        return _pyAgrum.Potential_reorganize(self, *args)

    def putFirst(self, varname: str) -> "pyAgrum.Potential":
        r"""

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable for which the index should be 0.

        Returns
        -------
        pyAgrum.Potential
          a reference to the modified potential

        Raises
        ------
        pyAgrum.InvalidArgument
          If the var is not in the potential 

        """
        return _pyAgrum.Potential_putFirst(self, varname)

    def fillWith(self, *args) -> "pyAgrum.Potential":
        r"""

        Automatically fills the potential with v.

        Parameters
        ----------
        v : number or list or pyAgrum.Potential the number of parameters of the Potential
            a value or a list/pyAgrum.Potential containing the values to fill the Potential with.

        Warning
        -------
            if v is a list, the size of the list must be the
            if v is a pyAgrum.Potential. It must to contain variables with exactly the same names and labels but not necessarily the same variables.

        Returns
        -------
        pyAgrum.Potential
              a reference to the modified potentia

        Raises
        ------
        pyAgrum.SizeError
          If v size's does not matches the domain size. 

        """
        val = _pyAgrum.Potential_fillWith(self, *args)

        return self


        return val


    def abs(self) -> "pyAgrum.Potential":
        r"""

        Apply abs on every element of the container

        Returns
        -------
        pyAgrum.Potential
            a reference to the modified potential.

        """
        val = _pyAgrum.Potential_abs(self)

        return self


        return val


    def sq(self) -> "pyAgrum.Potential":
        r"""

        Square all the values in the Potential

        """
        val = _pyAgrum.Potential_sq(self)

        return self


        return val


    def log2(self) -> "pyAgrum.Potential":
        r"""

        log2 all the values in the Potential

        Warning
        -------
        When the Potential contains 0 or negative values, no exception are raised but `-inf` or `nan` values are assigned.

        """
        val = _pyAgrum.Potential_log2(self)

        return self


        return val


    def new_abs(self) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_new_abs(self)

    def new_sq(self) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_new_sq(self)

    def new_log2(self) -> "pyAgrum.Potential":
        return _pyAgrum.Potential_new_log2(self)

    def normalize(self) -> "pyAgrum.Potential":
        r"""

        Normalize the Potential (do nothing if sum is 0)

        Returns
        -------
        pyAgrum.Potential
          a reference to the normalized Potential

        """
        val = _pyAgrum.Potential_normalize(self)

        return self


        return val


    def KL(self, p: "Potential") -> float:
        r"""

        Check the compatibility and compute the Kullback-Leibler divergence between the potential and.

        Parameters
        ----------
        p : pyAgrum.Potential
          the potential from which we want to calculate the divergence.

        Returns
        -------
        float
          The value of the divergence

        Raises
        ------
        pyAgrum.InvalidArgument
          If p is not compatible with the potential (dimension, variables)
        pyAgrum.FatalError
          If a zero is found in p or the potential and not in the other. 

        """
        return _pyAgrum.Potential_KL(self, p)

    def normalizeAsCPT(self, varId: int=0) -> "pyAgrum.Potential":
        r"""

        Normalize the Potential as a CPT

        Returns
        -------
        pyAgrum.Potential
          a reference to the normalized Potential

        Raises
        ------
        pyAgrum.FatalError
          If some distribution sums to 0

        """
        val = _pyAgrum.Potential_normalizeAsCPT(self, varId)

        return self


        return val


    def scale(self, v: float) -> "pyAgrum.Potential":
        r"""

        Create a new potential multiplied by v.

        Parameters
        ----------
        v : float
          a multiplier

        Returns
        -------
          a reference to the modified potential

        """
        val = _pyAgrum.Potential_scale(self, v)

        return self


        return val


    def translate(self, v: float) -> "pyAgrum.Potential":
        r"""

        Create a new potential added with v.

        Parameters
        ----------
        v : float
          The value to be added

        Returns
        -------
          a reference to the modified potential

        """
        val = _pyAgrum.Potential_translate(self, v)

        return self


        return val


    def inverse(self) -> "pyAgrum.Potential":
        val = _pyAgrum.Potential_inverse(self)

        return self


        return val


    def draw(self) -> int:
        r"""

        draw a value using the potential as a probability table.

        Returns
        -------
        int
          the index of the drawn value

        """
        return _pyAgrum.Potential_draw(self)

    def __add__(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.Potential___add__(self, *args)

    def __sub__(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.Potential___sub__(self, *args)

    def __mul__(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.Potential___mul__(self, *args)

    def __truediv__(self, *args):
        return _pyAgrum.Potential___truediv__(self, *args)
    __div__ = __truediv__



    def __iadd__(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.Potential___iadd__(self, *args)

    def __imul__(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.Potential___imul__(self, *args)

    def __isub__(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.Potential___isub__(self, *args)

    def __itruediv__(self, *args):
        return _pyAgrum.Potential___itruediv__(self, *args)
    __idiv__ = __itruediv__



    def __repr__(self) -> str:
        return _pyAgrum.Potential___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.Potential___str__(self)

    def extract(self, *args) -> "pyAgrum.Potential":
        r"""

        create a new Potential extracted from self given a partial instantiation.

        Parameters
        ----------
        inst : pyAgrum.instantiation
          a partial instantiation
        dict : Dict[str,str|int]
          a dictionnary containing values for some discrete variables.

        Returns
        -------
        pyAgrum.Potential
          the new Potential

        """
        return _pyAgrum.Potential_extract(self, *args)

    def margSumOut(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using sum as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to eliminate

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        Raises
        ------
        pyAgrum.InvalidArgument
          If varnames contains only one variable that does not exist in the Potential

        """
        return _pyAgrum.Potential_margSumOut(self, varnames)

    def margProdOut(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using multiplication as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to eliminate

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        Raises
        ------
        pyAgrum.InvalidArgument
          If varnames contains only one variable that does not exist in the Potential

        """
        return _pyAgrum.Potential_margProdOut(self, varnames)

    def margMaxOut(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using max as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to eliminate

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        Raises
        ------
        pyAgrum.InvalidArgument
          If varnames contains only one variable that does not exist in the Potential

        """
        return _pyAgrum.Potential_margMaxOut(self, varnames)

    def margMinOut(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using min as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to eliminate

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        Warnings
        --------
        InvalidArgument raised if varnames contains only one variable that does not exist in the Potential

        """
        return _pyAgrum.Potential_margMinOut(self, varnames)

    def margSumIn(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using sum as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to keep

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        """
        return _pyAgrum.Potential_margSumIn(self, varnames)

    def margProdIn(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using multiplication as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to keep

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        """
        return _pyAgrum.Potential_margProdIn(self, varnames)

    def margMaxIn(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using max as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to keep

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        """
        return _pyAgrum.Potential_margMaxIn(self, varnames)

    def margMinIn(self, varnames: object) -> "pyAgrum.Potential":
        r"""

        Projection using min as operation.

        Parameters
        ----------
        varnames : set
          the set of vars to keep

        Returns
        -------
        pyAgrum.Potential
          the projected Potential

        """
        return _pyAgrum.Potential_margMinIn(self, varnames)

    def __eq__(self, *args) -> bool:
        return _pyAgrum.Potential___eq__(self, *args)

    def __ne__(self, *args) -> bool:
        return _pyAgrum.Potential___ne__(self, *args)

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

    def __rmul__(self,other):
      return self.__mul__(other)

    def __rsub__(self,other):
      return (self*-1)+other

    def __rfloordiv__(self,other):
      return Potential(self).inverse().scale(other)

    def __rtruediv__(self,other):
      return Potential(self).inverse().scale(other)

    def __rdiv__(self,other):
      return Potential(self).inverse().scale(other)

    def __neg__(self):
      return -1*self

    def __abs__(self):
      return Potential(self).abs()

    def loopIn(self):
      """
      Generator to iterate inside a Potential. 

      Yield an gum.Instantiation that iterates over all the possible values for the gum.Potential

      Examples
      --------
      >>> import pyAgrum as gum
      >>> bn=gum.fastBN("A[3]->B[3]<-C[3]")
      >>> for i in bn.cpt("B").loopIn():
            print(i)
            print(bn.cpt("B").get(i))
            bn.cpt("B").set(i,0.3) 
      """
      i=Instantiation(self)
      i.setFirst()
      while not i.end():
        yield i
        i.inc()
      return

    def fillWithFunction(self,s,noise=None):
      """
      Automatically fills the potential as a (quasi) deterministic CPT with the evaluation of the expression s.

      The expression s gives a value for the first variable using the names of the last variables.
      The computed CPT is deterministic unless noise is used to add a 'probabilistic' noise around the exact value given by the expression.


      Examples
      --------
      >>> import pyAgrum as gum
      >>> bn=gum.fastBN("A[3]->B[3]<-C[3]")
      >>> bn.cpt("B").fillWithFunction("(A+C)/2")

      Parameters
      ----------
      s : str
          an expression using the name of the last variables of the Potential and giving a value to the first variable of the Potential
      noise : list
          an (odd) list of numerics giving a pattern of 'probabilistic noise' around the value.

      Warning
      -------
          The expression may have any numerical values, but will be then transformed to the closest correct value for the range of the variable.

      Returns
      -------
      pyAgrum.Potential
            a reference to the modified potential

      Raises
      ------
      gum.InvalidArgument
        If the first variable is Labelized or Integer, or if the len of the noise is not odd.
      """
      if self.variable(0).varType()==VarType_Labelized:
        raise InvalidArgument("[pyAgrum] The variable "+self.variable(0).name()+" is a LabelizedVariable")
      if self.variable(0).varType()==VarType_Integer:
        raise InvalidArgument("[pyAgrum] The variable "+self.variable(0).name()+" is neither Range nor Discretized variable.")

      if noise==None:
        mid=0
      else:
        if len(noise)%2==0:
          raise InvalidArgument("[pyAgrum] len(noise) must not be even")
        mid=int((len(noise)-1)/2)

      self.fillWith(0)
      mi=self.variable(0).numerical(0)
      ma=self.variable(0).numerical(self.variable(0).domainSize()-1)

      I=Instantiation(self)

      I.setFirst()
      while not I.end():
        vars={self.variable(i).name():self.variable(i).numerical(I.val(i)) for i in range(1,self.nbrDim())}
        res=eval(s,None,vars)
        if res<mi:
          res=mi
        if res>ma:
          res=ma
        pos=self.variable(0).index(str(res))
        if mid==0:
          I.chgVal(0,pos)
          self.set(I,1)
        else:
          for i,v in enumerate(noise):
            if 0<=pos+i-mid<self.variable(0).domainSize():
              I.chgVal(0,pos+i-mid)
              self.set(I,v)
        I.incNotVar(self.variable(0))
      self.normalizeAsCPT()
      return self

    def variablesSequence(self):
        """
        Returns
        -------
        list
            a list containing the sequence of variables
        """
        varlist = []
        for i in range(0, self.nbrDim()):
            varlist.append(self.variable(i))
        return varlist

    def __prepareIndices__(self,ind):
      """
      From an indice (dict or tuple), returns a pair of gum.Instantiation to loop in a part of the Potential.
      """
      loopvars=Instantiation(self)
      loopvars.setMutable()

      inst=Instantiation(self)
      inst.setFirst()

      if isinstance(ind, (Number,slice)):
        i = tuple([ind])
      else:
        i = ind

      vn=self.var_names
      if isinstance(i,dict):
          for nam in vn:        
              if nam in i:
                  inst.chgVal(nam,i[nam])
                  loopvars.erase(nam)
      elif isinstance(i,tuple):
          if len(i)>self.nbrDim():
              raise KeyError("Too many values in '"+str(i)+"' for '"+str(self)+"'")
          for k,v in enumerate(i):
              if not isinstance(v,slice):
                  nam=vn[k]
                  inst.chgVal(nam,v)
                  loopvars.erase(nam)
      else:
          raise ValueError("No subscript using '"+str(i)+"'")
      return inst,loopvars

    def __getitem__(self, id):
      if isinstance(id,Instantiation):
          return self.get(id)

      inst,loopvars=self.__prepareIndices__(id)

      if loopvars.nbrDim()==0:
          return self.get(inst)

      if loopvars.nbrDim()==self.nbrDim():
        content=[]

        inst=Instantiation(self)
        while not inst.end():
            content.append(self.get(inst)) 
            inst.inc()
        tab=numpy.array(content,dtype=numpy.float64)
        tab.shape=tuple(self.var_dims)
        return tab

      names=[loopvars.variable(i-1).name() for i in range(loopvars.nbrDim(),0,-1)]
      tab=numpy.zeros(tuple([loopvars.variable(i-1).domainSize() for i in range(loopvars.nbrDim(),0,-1)]))
      while not inst.end():
          indice=[inst.val(name) for name in names]
          tab[tuple(indice)]=self.get(inst)
          inst.incIn(loopvars)
      return tab

    def __setitem__(self, id, value):
      if isinstance(id,Instantiation):
          self.set(id,value)
          return

      inst,loopvars=self.__prepareIndices__(id)

      if loopvars.nbrDim()==0:
          self.set(inst,value)
          return

      if isinstance(value,Number):
        while not inst.end():
            self.set(inst,value)
            inst.incIn(loopvars)
      else:
        if isinstance(value,list):
            value=numpy.array(value)

        shape=tuple([loopvars.variable(i-1).domainSize() for i in range(loopvars.nbrDim(),0,-1)])
        if value.shape!=shape:
          raise IndexError("Shape of '"+str(value)+"' is not '"+str(shape)+"'")

        names = [loopvars.variable(i - 1).name() for i in range(loopvars.nbrDim(), 0, -1)]
        while not inst.end():
            indice = tuple([inst.val(name) for name in names])
            self.set(inst,float(value[indice]))
            inst.incIn(loopvars)

    def tolist(self):
        """
        Returns
        -------
        list
            the potential as a list
        """
        return self.__getitem__({}).tolist()

    def toarray(self):
        """
        Returns
        -------
        array
            the potential as an array
        """
        return self.__getitem__({})

    def topandas(self):
        """
        Returns
        -------
        pandas.DataFrame
           the potential as an pandas.DataFrame
        """
        import pandas as pd
        varnames = self.var_names
        data = []
        pname = ""
        for inst in self.loopIn():
            d = {k:v for k,v in reversed(inst.todict(True).items())}
            d[pname] = self.get(inst)
            d[pname], d[varnames[-1]] = d[varnames[-1]], d[pname]
            data.append(d)
        cols = varnames[:-1] + [pname]
        return pd.DataFrame(data).set_index(cols).unstack(pname)

    def tolatex(self):
        """
        Render object to a LaTeX tabular.

        Requires to include `booktabs` package in the LaTeX document.

        Returns
        -------
        str
         the potential as LaTeX string
        """
        return self.topandas().to_latex()

    def toclipboard(self,**kwargs):
        """
        Write a text representation of object to the system clipboard. This can be pasted into spreadsheet, for instance.
        """
        return self.topandas().to_clipboard()

    @property
    def var_names(self):
        """
        Returns
        -------
        list
            a list containing the name of each variables in the potential

        Warnings
        --------
            listed in the reverse order of the enumeration order of the variables.
        """
        return [self.variable(i-1).name() for i in range(self.nbrDim(),0,-1)]

    @property
    def var_dims(self):
        """
        Returns
        -------
        list
            a list containing the dimensions of each variables in the potential
        """
        return [self.variable(i-1).domainSize() for i in range(self.nbrDim(),0,-1)]


    def get(self, i: "Instantiation") -> float:
        r"""

        Parameters
        ----------
        i : pyAgrum.Instantiation
          an Instantiation

        Returns
        -------
        float
          the value in the Potential at the position given by the instantiation

        """
        return _pyAgrum.Potential_get(self, i)

    def set(self, i: "Instantiation", value: float) -> None:
        r"""

        Change the value pointed by i

        Parameters
        ----------
        i : pyAgrum.Instantiation
          The Instantiation to be changed
        value : float
          The new value of the Instantiation

        """
        return _pyAgrum.Potential_set(self, i, value)

    def empty(self) -> bool:
        r"""

        Returns
        -------
        bool
            Returns true if no variable is in the potential. 

        """
        return _pyAgrum.Potential_empty(self)

    def pos(self, v: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable for which the index is returned.

        Returns
        -------
            Returns the index of a variable. 

        Raises
        ------
        pyAgrum.NotFound
          If v is not in this multidimensional matrix. 

        """
        return _pyAgrum.Potential_pos(self, v)

    def contains(self, v: "pyAgrum.DiscreteVariable") -> bool:
        r"""

        Parameters
        ----------
        v : pyAgrum.Potential
            a DiscreteVariable.

        Returns
        -------
        bool
            True if the var is in the potential

        """
        return _pyAgrum.Potential_contains(self, v)

    def variable(self, *args) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        i : int 
          An index of this multidimensional matrix.

        Returns
        -------
          the varible at the ith index 

        Raises
        ------
        pyAgrum.NotFound
          If i does not reference a variable in this multidimensional matrix. 

        """
        return _pyAgrum.Potential_variable(self, *args)

    def remove(self, var: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
            The variable to be removed

        Returns
        -------
        pyAgrum.Potential
          a reference to the modified potential

        Warnings
        --------
        IndexError raised if the var is not in the potential 

        """
        val = _pyAgrum.Potential_remove(self, var)

        self._list_vars.remove(var)


        return val


    def add(self, v: "pyAgrum.DiscreteVariable") -> None:
        r"""

        Add a discrete variable to the potential.

        Parameters
        ----------
        v : pyAgrum.DiscreteVariable
          the var to be added

        Raises
        ------
        DuplicateElement
          If the variable is already in this Potential.
        InvalidArgument
          If the variable is empty.

        Returns
        -------
        pyAgrum.Potential
            a reference to the modified potential.

        """
        val = _pyAgrum.Potential_add(self, v)

        self._list_vars.append(v)
        return self


        return val


    def domainSize(self) -> int:
        return _pyAgrum.Potential_domainSize(self)

    def nbrDim(self, *args) -> int:
        r"""

        Returns
        -------
        int
          the number of vars in the multidimensional container. 

        """
        return _pyAgrum.Potential_nbrDim(self, *args)

# Register Potential in _pyAgrum:
_pyAgrum.Potential_swigregister(Potential)

class IBayesNet(DAGmodel):
    r"""

    Abstract class used by BayesNet.

    """

    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 - class is abstract")
    __swig_destroy__ = _pyAgrum.delete_IBayesNet

    def cpt(self, varId: int) -> "pyAgrum.Potential":
        r"""

        Returns the CPT of a variable.

        Parameters
        ----------
        VarId : int
        	A variable's id in the pyAgrum.IBayesNet.
        name : str
        	A variable's name in the pyAgrum.IBayesNet.

        Returns
        -------
        pyAgrum.Potential
        	The variable's CPT. 

        Raises
        ------
        pyAgrum.NotFound
        	If no variable's id matches varId. 

        """
        return _pyAgrum.IBayesNet_cpt(self, varId)

    def variableNodeMap(self) -> "pyAgrum.VariableNodeMap":
        r"""

        Returns
        -------
        pyAgrum.variableNodeMap
        	the variable node map

        """
        return _pyAgrum.IBayesNet_variableNodeMap(self)

    def variable(self, id: int) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        id : int
        	a variable's id
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.IBayesNet_variable(self, id)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Parameters
        ----------
        var : pyAgrum.DiscreteVariable
        	a variable

        Returns
        -------
        int
        	the id of the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.IBayesNet_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        r"""

        Returns a variable's id given its name in the graph.

        Parameters
        ----------
        name : str
        	The variable's name from which the id is returned.

        Returns
        -------
        int :
        	The variable's node id.

        Raises
        ------
        pyAgrum.NotFound
        	If name does not match a variable in the graph

        """
        return _pyAgrum.IBayesNet_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.IBayesNet_variableFromName(self, name)

    def jointProbability(self, i: "Instantiation") -> float:
        r"""

        Parameters
        ----------
        i : pyAgrum.instantiation
        	an instantiation of the variables

        Returns
        -------
        float
        	a parameter of the joint probability for the BayesNet

        Warnings
        --------
        a variable not present in the instantiation is assumed to be instantiated to 0

        """
        return _pyAgrum.IBayesNet_jointProbability(self, i)

    def log2JointProbability(self, i: "Instantiation") -> float:
        r"""

        Parameters
        ----------
        i : pyAgrum.instantiation
        	an instantiation of the variables

        Returns
        -------
        float
        	a parameter of the log joint probability for the BayesNet

        Warnings
        --------
        a variable not present in the instantiation is assumed to be instantiated to 0

        """
        return _pyAgrum.IBayesNet_log2JointProbability(self, i)

    def __eq__(self, _from: "IBayesNet") -> bool:
        return _pyAgrum.IBayesNet___eq__(self, _from)

    def __ne__(self, _from: "IBayesNet") -> bool:
        return _pyAgrum.IBayesNet___ne__(self, _from)

    def dim(self) -> int:
        r"""

        Returns the dimension (the number of free parameters) in this BayesNet.

        Returns
        -------
        int
        	the dimension of the BayesNet

        """
        return _pyAgrum.IBayesNet_dim(self)

    def maxVarDomainSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the biggest domain size among the variables of the BayesNet

        """
        return _pyAgrum.IBayesNet_maxVarDomainSize(self)

    def minParam(self) -> float:
        r"""

        Returns
        -------
        float
            the smallest value in the CPTs of the IBayesNet

        """
        return _pyAgrum.IBayesNet_minParam(self)

    def maxParam(self) -> float:
        r"""

        Returns
        -------
        float
            the biggest value in the CPTs of the BayesNet

        """
        return _pyAgrum.IBayesNet_maxParam(self)

    def minNonZeroParam(self) -> float:
        r"""

        Returns
        -------
        float
            the smallest value (not equal to 0) in the CPTs of the IBayesNet

        """
        return _pyAgrum.IBayesNet_minNonZeroParam(self)

    def maxNonOneParam(self) -> float:
        r"""

        Returns
        -------
        float
        	The biggest value (not equal to 1) in the CPTs of the BayesNet

        """
        return _pyAgrum.IBayesNet_maxNonOneParam(self)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format

        """
        return _pyAgrum.IBayesNet_toDot(self)

    def minimalCondSet(self, *args) -> object:
        r"""

        Returns, given one or many targets and a list of variables, the minimal set of those needed to calculate the target/targets.

        Parameters
        ----------
        target : int
        	The id of the target
        targets : list
        	The ids of the targets
        list : list
        	The list of available variables

        Returns
        -------
        Set
        	The minimal set of variables

        """
        return _pyAgrum.IBayesNet_minimalCondSet(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.IBayesNet_isIndependent(self, *args)

    def names(self) -> object:
        r"""

        Returns
        -------
        list
        	The names of the graph variables

        """
        return _pyAgrum.IBayesNet_names(self)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.IBayesNet_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def arcs(self) -> object:
        r"""

        Returns
        -------
        list
        	The lisf of arcs in the IBayesNet

        """
        return _pyAgrum.IBayesNet_arcs(self)

    def parents(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        Set
            the set of the parents ids.

        """
        return _pyAgrum.IBayesNet_parents(self, norid)

    def children(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.IBayesNet_children(self, norid)

    def family(self, norid: object) -> object:
        return _pyAgrum.IBayesNet_family(self, norid)

    def descendants(self, norid: object) -> object:
        return _pyAgrum.IBayesNet_descendants(self, norid)

    def ancestors(self, norid: object) -> object:
        return _pyAgrum.IBayesNet_ancestors(self, norid)

    def moralizedAncestralGraph(self, nodes: object) -> "pyAgrum.UndiGraph":
        return _pyAgrum.IBayesNet_moralizedAncestralGraph(self, nodes)

    def __repr__(self) -> str:
        return _pyAgrum.IBayesNet___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.IBayesNet___str__(self)

# Register IBayesNet in _pyAgrum:
_pyAgrum.IBayesNet_swigregister(IBayesNet)

class BayesNet(IBayesNet):
    r"""

    BayesNet represents a Bayesian network.

    BayesNet(name='') -> BayesNet
        Parameters:
          * **name** (*str*) -- the name of the Bayes Net

    BayesNet(source) -> BayesNet
        Parameters:
          * **source** (*pyAgrum.BayesNet*) -- the Bayesian network to copy

    """

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

    @staticmethod
    def fastPrototype(dotlike: str, domainSize: int=2) -> "pyAgrum.BayesNet":
        r"""

        Create a Bayesian network with a dot-like syntax which specifies:
            - the structure 'a->b->c;b->d<-e;'.
            - the type of the variables with different syntax:

              - by default, a variable is a pyAgrum.RangeVariable using the default domain size (second argument)
              - with 'a[10]', the variable is a pyAgrum.RangeVariable using 10 as domain size (from 0 to 9)
              - with 'a[3,7]', the variable is a pyAgrum.RangeVariable using a domainSize from 3 to 7
              - with 'a[1,3.14,5,6.2]', the variable is a pyAgrum.DiscretizedVariable using the given ticks (at least 3 values)
              - with 'a{top|middle|bottom}', the variable is a pyAgrum.LabelizedVariable using the given labels.
              - with 'a{-1|5|0|3}', the variable is a pyAgrum.IntegerVariable using the sorted given values.

        Note 
        ----
          - If the dot-like string contains such a specification more than once for a variable, the first specification will be used.
          - the CPTs are randomly generated.
          - see also pyAgrum.fastBN.

        Examples
        --------
        >>> import pyAgrum as gum
        >>> bn=pyAgrum.BayesNet.fastPrototype('A->B[1,3]<-C{yes|No}->D[2,4]<-E[1,2.5,3.9]',6)

        Parameters
        ----------
        dotlike : str
                the string containing the specification
        domainSize : int
                the default domain size for variables

        Returns
        -------
        pyAgrum.BayesNet
                the resulting Bayesian network

        """
        return _pyAgrum.BayesNet_fastPrototype(dotlike, domainSize)
    __swig_destroy__ = _pyAgrum.delete_BayesNet

    def __init__(self, *args):
        _pyAgrum.BayesNet_swiginit(self, _pyAgrum.new_BayesNet(*args))

    def cpt(self, *args) -> "pyAgrum.Potential":
        r"""

        Returns the CPT of a variable.

        Parameters
        ----------
        VarId : int
        	A variable's id in the pyAgrum.BayesNet.
        name : str
        	A variable's name in the pyAgrum.BayesNet.

        Returns
        -------
        pyAgrum.Potential
        	The variable's CPT. 

        Raises
        ------
        pyAgrum.NotFound
            If no variable's id matches varId.

        """
        return _pyAgrum.BayesNet_cpt(self, *args)

    def variableNodeMap(self) -> "pyAgrum.VariableNodeMap":
        r"""

        Returns
        -------
        pyAgrum.variableNodeMap
        	the variable node map

        """
        return _pyAgrum.BayesNet_variableNodeMap(self)

    def add(self, *args) -> int:
        r"""

        Add a variable to the pyAgrum.BayesNet. 

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable added
        name : str 
        	the variable name
        nbrmod : int
        	the number of modalities for the new variable
        id : int
        	the variable forced id in the pyAgrum.BayesNet

        Returns
        -------
        int 
        	the id of the new node

        Raises
        ------
        pyAgrum.DuplicateLabel
            If variable.name() is already used in this pyAgrum.BayesNet.
        pyAgrum.NotAllowed
            If nbrmod is less than 2
        pyAgrum.DuplicateElement
            If id is already used.

        """
        return _pyAgrum.BayesNet_add(self, *args)

    def clear(self) -> None:
        r"""

        Clear the whole BayesNet  

        """
        return _pyAgrum.BayesNet_clear(self)

    def erase(self, *args) -> None:
        r"""

        Remove a variable from the pyAgrum.BayesNet.

        Removes the corresponding variable from the pyAgrum.BayesNet and from all of it's children pyAgrum.Potential.

        If no variable matches the given id, then nothing is done.

        Parameters
        ----------
        id : int
        	The variable's id to remove. 
        name : str
        	The variable's name to remove.
        var : pyAgrum.DiscreteVariable
        	A reference on the variable to remove. 

        """
        return _pyAgrum.BayesNet_erase(self, *args)

    def variable(self, *args) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        id : int
        	a variable's id
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.BayesNet_variable(self, *args)

    def changeVariableName(self, *args) -> None:
        r"""

        Changes a variable's name in the pyAgrum.BayesNet.

        This will change the "pyAgrum.DiscreteVariable" names in the pyAgrum.BayesNet.

        Parameters
        ----------
        new_name : str
        	the new name of the variable
        NodeId : int
        	the id of the node
        name : str
        	the name of the variable

        Raises
        ------
        pyAgrum.DuplicateLabel
            If new_name is already used in this BayesNet.
        pyAgrum.NotFound
            If no variable matches id.

        """
        return _pyAgrum.BayesNet_changeVariableName(self, *args)

    def changeVariableLabel(self, *args) -> None:
        r"""

        change the label of the variable associated to nodeId to the new value.

        Parameters
        ----------
        id : int
        	the id of the node
        name : str
        	the name of the variable
        old_label : str
        	the new label
        new_label : str
        	the new label

        Raises
        ------
        pyAgrum.NotFound
            if id/name is not a variable or if old_label does not exist.

        """
        return _pyAgrum.BayesNet_changeVariableLabel(self, *args)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Parameters
        ----------
        var : pyAgrum.DiscreteVariable
        	a variable

        Returns
        -------
        int
        	the id of the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.BayesNet_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        r"""

        Returns a variable's id given its name in the graph.

        Parameters
        ----------
        name : str
        	The variable's name from which the id is returned.

        Returns
        -------
        int :
        	The variable's node id.

        Raises
        ------
        pyAgrum.NotFound
        	If name does not match a variable in the graph

        """
        return _pyAgrum.BayesNet_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.BayesNet_variableFromName(self, name)

    def addArc(self, *args) -> None:
        r"""

        Add an arc in the BN, and update arc.head's CPT.

        Parameters
        ----------
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        Raises
        ------
        pyAgrum.InvalidEdge
            If arc.tail and/or arc.head are not in the BN.
        pyAgrum.DuplicateElement
            If the arc already exists.

        """
        return _pyAgrum.BayesNet_addArc(self, *args)

    def eraseArc(self, *args) -> None:
        r"""

        Removes an arc in the BN, and update head's CTP.

        If (tail, head) doesn't exist, the nothing happens.

        Parameters
        ----------
        arc : pyAgrum.Arc 
        	The arc to be removed.
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        """
        return _pyAgrum.BayesNet_eraseArc(self, *args)

    def beginTopologyTransformation(self) -> None:
        r"""

        When inserting/removing arcs, node CPTs change their dimension with a cost in time.
        begin Multiple Change for all CPTs
        These functions delay the CPTs change to be done just once at the end of a sequence of topology modification, begins a sequence of insertions/deletions of arcs without changing the dimensions of the CPTs.

        """
        return _pyAgrum.BayesNet_beginTopologyTransformation(self)

    def endTopologyTransformation(self) -> None:
        r"""

        Terminates a sequence of insertions/deletions of arcs by adjusting all CPTs dimensions.
        End Multiple Change for all CPTs.

        Returns
        -------
        pyAgrum.BayesNet

        """
        return _pyAgrum.BayesNet_endTopologyTransformation(self)

    def reverseArc(self, *args) -> None:
        r"""

        Reverses an arc while preserving the same joint distribution. 

        Parameters
        ----------
        tail
        	(int) the id of the tail variable
        head
        	(int) the id of the head variable
        tail
        	(str) the name of the tail variable
        head
        	(str) the name of the head variable
        arc : pyAgrum.Arc
        	an arc 

        Raises
        ------
        pyAgrum.InvalidArc
            If the arc does not exsit or if its reversal would induce a directed cycle.

        """
        return _pyAgrum.BayesNet_reverseArc(self, *args)

    def addNoisyOR(self, *args) -> int:
        r"""

        Add a variable, it's associate node and a noisyOR implementation.

        Since it seems that the 'classical' noisyOR is the Compound noisyOR, we keep the addNoisyOR as an alias for addNoisyORCompound.

        (The id of the new variable can be automatically generated.)

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy
        externalWeight : float
        	the added external weight
        id : int
        	The proposed id for the variable.

        Returns
        -------
        int
        	the id of the added variable. 

        Raises
        --------
        pyAgrum.DuplicateElement
            If id is already used

        """
        return _pyAgrum.BayesNet_addNoisyOR(self, *args)

    def addNoisyORNet(self, *args) -> int:
        r"""

        Add a variable, its associate node and a noisyOR implementation.

        Since it seems that the 'classical' noisyOR is the Compound noisyOR, we keep the addNoisyOR as an alias for addNoisyORCompound.

        (The id of the new variable can be automatically generated.)

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy
        externalWeight : float
        	the added external weight
        id : int
        	The proposed id for the variable.

        Returns
        -------
        int
        	the id of the added variable.

        """
        return _pyAgrum.BayesNet_addNoisyORNet(self, *args)

    def addNoisyORCompound(self, *args) -> int:
        r"""

        Add a variable, it's associate node and a noisyOR implementation.

        Since it seems that the 'classical' noisyOR is the Compound noisyOR, we keep the addNoisyOR as an alias for addNoisyORCompound.

        (The id of the new variable can be automatically generated.)

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy
        externalWeight : float
        	the added external weight
        id : int
        	The proposed id for the variable.

        Returns
        -------
        int
        	the id of the added variable.

        Raises
        --------
        pyAgrum.DuplicateElement
            If id is already used

        """
        return _pyAgrum.BayesNet_addNoisyORCompound(self, *args)

    def addNoisyAND(self, *args) -> int:
        r"""

        Add a variable, its associate node and a noisyAND implementation.

        (The id of the new variable can be automatically generated.)

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy
        externalWeight : float
        	the added external weight
        id : int
        	The proposed id for the variable.

        Returns
        -------
        int
        	the id of the added variable.

        Raises
        ------
        pyAgrum.DuplicateElement
            If id is already used

        """
        return _pyAgrum.BayesNet_addNoisyAND(self, *args)

    def addLogit(self, *args) -> int:
        r"""

        Add a variable, its associate node and a Logit implementation.

        (The id of the new variable can be automatically generated.)

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy
        externalWeight : float
        	the added external weight
        id : int
        	The proposed id for the variable.
        Returns
        -------
        int
        	the id of the added variable.

        Raises
        ------
        pyAgrum.DuplicateElement
            If id is already used

        """
        return _pyAgrum.BayesNet_addLogit(self, *args)

    def addOR(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Add a variable, it's associate node and an OR implementation.

        The id of the new variable is automatically generated.

        Warnings
        --------
        	If parents are not boolean, all value>1 is True

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy

        Returns
        -------
        int
        	the id of the added variable.

        Raises
        ------
        pyAgrum.SizeError
            If variable.domainSize()>2

        """
        return _pyAgrum.BayesNet_addOR(self, var)

    def addAND(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Add a variable, it's associate node and an AND implementation.

        The id of the new variable is automatically generated.

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy.

        Returns
        -------
        int
        	the id of the added variable. 

        Raises
        ------
        pyAgrum.SizeError
            If variable.domainSize()>2

        """
        return _pyAgrum.BayesNet_addAND(self, var)

    def addAMPLITUDE(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added value

        """
        return _pyAgrum.BayesNet_addAMPLITUDE(self, var)

    def addCOUNT(self, var: "pyAgrum.DiscreteVariable", value: int=1) -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added value

        """
        return _pyAgrum.BayesNet_addCOUNT(self, var, value)

    def addEXISTS(self, var: "pyAgrum.DiscreteVariable", value: int=1) -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added value

        """
        return _pyAgrum.BayesNet_addEXISTS(self, var, value)

    def addFORALL(self, var: "pyAgrum.DiscreteVariable", value: int=1) -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added variable.

        """
        return _pyAgrum.BayesNet_addFORALL(self, var, value)

    def addMAX(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added value

        """
        return _pyAgrum.BayesNet_addMAX(self, var)

    def addMEDIAN(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added value

        """
        return _pyAgrum.BayesNet_addMEDIAN(self, var)

    def addMIN(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable to be added

        Returns
        -------
        int
        	the id of the added value

        """
        return _pyAgrum.BayesNet_addMIN(self, var)

    def addSUM(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Others aggregators

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
                the variable to be added

        Returns
        -------
        int
                the id of the added value

        """
        return _pyAgrum.BayesNet_addSUM(self, var)

    def addWeightedArc(self, *args) -> None:
        r"""

        Add an arc in the BN, and update arc.head's CPT.

        Parameters
        ----------
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)
        causalWeight : float
        	the added causal weight

        Raises
        ------
        pyAgrum.InvalidArc
            If arc.tail and/or arc.head are not in the BN.
        pyAgrum.InvalidArc
            If variable in arc.head is not a NoisyOR variable.

        """
        return _pyAgrum.BayesNet_addWeightedArc(self, *args)

    def generateCPTs(self) -> None:
        r"""

        Randomly generates CPTs for a given structure.

        """
        return _pyAgrum.BayesNet_generateCPTs(self)

    def generateCPT(self, *args) -> None:
        r"""

        Randomly generate CPT for a given node in a given structure.

        Parameters
        ----------
        node : int
        	The variable's id.
        name : str 
        	The variable's name.

        """
        return _pyAgrum.BayesNet_generateCPT(self, *args)

    def changePotential(self, *args) -> None:
        r"""

        change the CPT associated to nodeId to newPot delete the old CPT associated to nodeId.

        Parameters
        ----------
        newPot : pyAgrum.Potential
        	the new potential
        NodeId : int
        	the id of the node
        name : str
        	the name of the variable

        Raises
        ------
        pyAgrum.NotAllowed
            If newPot has not the same signature as __probaMap[NodeId]

        """
        return _pyAgrum.BayesNet_changePotential(self, *args)

    def dag(self) -> "pyAgrum.DAG":
        r"""

        Returns
        -------
        pyAgrum.DAG
        	a constant reference to the dag of this BayesNet.

        """
        val = _pyAgrum.BayesNet_dag(self)

        val = DAG(val) # copying the DAG


        return val


    def size(self) -> int:
        r"""

        Returns
        -------
        int
            the number of nodes in the graph

        """
        return _pyAgrum.BayesNet_size(self)

    def log10DomainSize(self) -> float:
        return _pyAgrum.BayesNet_log10DomainSize(self)

    def minimalCondSet(self, *args) -> object:
        r"""

        Returns, given one or many targets and a list of variables, the minimal set of those needed to calculate the target/targets.

        Parameters
        ----------
        target : int
        	The id of the target
        targets : list
        	The ids of the targets
        list : list
        	The list of available variables

        Returns
        -------
        Set
        	The minimal set of variables

        """
        return _pyAgrum.BayesNet_minimalCondSet(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.BayesNet_isIndependent(self, *args)

    def names(self) -> object:
        r"""

        Returns
        -------
        list
        	The names of the graph variables

        """
        return _pyAgrum.BayesNet_names(self)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.BayesNet_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def arcs(self) -> object:
        r"""

        Returns
        -------
        list
        	The lisf of arcs in the IBayesNet

        """
        return _pyAgrum.BayesNet_arcs(self)

    def parents(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        Set
            the set of the parents ids.

        """
        return _pyAgrum.BayesNet_parents(self, norid)

    def children(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.BayesNet_children(self, norid)

    def family(self, norid: object) -> object:
        return _pyAgrum.BayesNet_family(self, norid)

    def descendants(self, norid: object) -> object:
        return _pyAgrum.BayesNet_descendants(self, norid)

    def ancestors(self, norid: object) -> object:
        return _pyAgrum.BayesNet_ancestors(self, norid)

    def moralizedAncestralGraph(self, nodes: object) -> "pyAgrum.UndiGraph":
        return _pyAgrum.BayesNet_moralizedAncestralGraph(self, nodes)

    def addStructureListener(self,whenNodeAdded=None,whenNodeDeleted=None,whenArcAdded=None,whenArcDeleted=None):
        """
        Add the listeners in parameters to the list of existing ones.

        Parameters
        ----------
        whenNodeAdded : lambda expression
          a function for when a node is added
        whenNodeDeleted : lambda expression
          a function for when a node is removed
        whenArcAdded : lambda expression
          a function for when an arc is added
        whenArcDeleted : lambda expression
          a function for when an arc is removed
        """
        if [whenNodeAdded,whenNodeDeleted,whenArcAdded,whenArcDeleted]==[None,None,None,None]:
          return

        if not hasattr(self,"_listeners"):
          self._listeners=[]

        nl = PythonBNListener(self, self.variableNodeMap())
        if whenNodeAdded is not None:
          nl.setWhenNodeAdded(whenNodeAdded)
        if whenNodeDeleted is not None:
          nl.setWhenNodeDeleted(whenNodeDeleted)
        if whenArcAdded is not None:
          nl.setWhenArcAdded(whenArcAdded)
        if whenArcDeleted is not None:
          nl.setWhenArcDeleted(whenArcDeleted)

        self._listeners.append(nl)


    def loadBIF(self, *args) -> str:
        r"""

        Load a BIF file.

        Parameters
        ----------
        name : str
        	the file's name
        l : list
        	list of functions to execute

        Raises
        --------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.BayesNet_loadBIF(self, *args)

    def saveBIF(self, name: str) -> None:
        r"""

        Save the BayesNet in a BIF file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.BayesNet_saveBIF(self, name)

    def loadDSL(self, *args) -> str:
        r"""

        Load a DSL file.

        Parameters
        ----------
        name : str
        	the file's name
        l : list
        	list of functions to execute

        Raises
        ------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.BayesNet_loadDSL(self, *args)

    def saveDSL(self, name: str) -> None:
        r"""

        Save the BayesNet in a DSL file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.BayesNet_saveDSL(self, name)

    def loadNET(self, *args) -> str:
        r"""

        Load a NET file.

        Parameters
        ----------
        name : str
        	the name's file
        l : list
        	list of functions to execute

        Raises
        ------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.BayesNet_loadNET(self, *args)

    def saveNET(self, name: str) -> None:
        r"""

        Save the BayesNet in a NET file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.BayesNet_saveNET(self, name)

    def loadO3PRM(self, *args) -> str:
        r"""

        Load an O3PRM file.

        Warnings
        --------
        The O3PRM language is the only language allowing to manipulate not only DiscretizedVariable but also RangeVariable and LabelizedVariable.

        Parameters
        ----------
        name : str
        	the file's name
        system : str
        	the system's name
        classpath : str
        	the classpath
        l : list
        	list of functions to execute

        Raises
        ------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.BayesNet_loadO3PRM(self, *args)

    def saveO3PRM(self, name: str) -> None:
        r"""

        Save the BayesNet in an O3PRM file.

        Warnings
        --------
        The O3PRM language is the only language allowing to manipulate not only DiscretizedVariable but also RangeVariable and LabelizedVariable.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.BayesNet_saveO3PRM(self, name)

    def loadBIFXML(self, *args) -> str:
        r"""

        Load a BIFXML file.

        Parameters
        ----------
        name : str
        	the name's file
        l : list
        	list of functions to execute

        Raises
        ------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.BayesNet_loadBIFXML(self, *args)

    def saveBIFXML(self, name: str) -> None:
        r"""

        Save the BayesNet in a BIFXML file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.BayesNet_saveBIFXML(self, name)

    def loadUAI(self, *args) -> str:
        r"""

        Load an UAI file.

        Parameters
        ----------
        name : str
        	the name's file
        l : list
        	list of functions to execute

        Raises
        ------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.BayesNet_loadUAI(self, *args)

    def saveUAI(self, name: str) -> None:
        r"""

        Save the BayesNet in an UAI file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.BayesNet_saveUAI(self, name)

    def __repr__(self) -> str:
        return _pyAgrum.BayesNet___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.BayesNet___str__(self)

# Register BayesNet in _pyAgrum:
_pyAgrum.BayesNet_swigregister(BayesNet)

def BayesNet_fastPrototype(dotlike: str, domainSize: int=2) -> "pyAgrum.BayesNet":
    r"""

    Create a Bayesian network with a dot-like syntax which specifies:
        - the structure 'a->b->c;b->d<-e;'.
        - the type of the variables with different syntax:

          - by default, a variable is a pyAgrum.RangeVariable using the default domain size (second argument)
          - with 'a[10]', the variable is a pyAgrum.RangeVariable using 10 as domain size (from 0 to 9)
          - with 'a[3,7]', the variable is a pyAgrum.RangeVariable using a domainSize from 3 to 7
          - with 'a[1,3.14,5,6.2]', the variable is a pyAgrum.DiscretizedVariable using the given ticks (at least 3 values)
          - with 'a{top|middle|bottom}', the variable is a pyAgrum.LabelizedVariable using the given labels.
          - with 'a{-1|5|0|3}', the variable is a pyAgrum.IntegerVariable using the sorted given values.

    Note 
    ----
      - If the dot-like string contains such a specification more than once for a variable, the first specification will be used.
      - the CPTs are randomly generated.
      - see also pyAgrum.fastBN.

    Examples
    --------
    >>> import pyAgrum as gum
    >>> bn=pyAgrum.BayesNet.fastPrototype('A->B[1,3]<-C{yes|No}->D[2,4]<-E[1,2.5,3.9]',6)

    Parameters
    ----------
    dotlike : str
            the string containing the specification
    domainSize : int
            the default domain size for variables

    Returns
    -------
    pyAgrum.BayesNet
            the resulting Bayesian network

    """
    return _pyAgrum.BayesNet_fastPrototype(dotlike, domainSize)

class BayesNetFragment(IBayesNet, ):
    r"""

    BayesNetFragment represents a part of a Bayesian network (subset of nodes). By default, the arcs and the CPTs are the same as the BN but local CPTs can be build to express different local dependencies. All the non local CPTs are not copied. Therefore a BayesNetFragment is a light object.

    BayesNetFragment(BayesNet bn) -> BayesNetFragment
        Parameters:
          * **bn** (*pyAgrum.BayesNet*) -- the bn refered by the fragment

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.BayesNetFragment_swiginit(self, _pyAgrum.new_BayesNetFragment(bn))
    __swig_destroy__ = _pyAgrum.delete_BayesNetFragment

    def whenNodeAdded(self, src: object, id: int) -> None:
        return _pyAgrum.BayesNetFragment_whenNodeAdded(self, src, id)

    def whenNodeDeleted(self, src: object, id: int) -> None:
        return _pyAgrum.BayesNetFragment_whenNodeDeleted(self, src, id)

    def whenArcAdded(self, src: object, _from: int, to: int) -> None:
        return _pyAgrum.BayesNetFragment_whenArcAdded(self, src, _from, to)

    def whenArcDeleted(self, src: object, _from: int, to: int) -> None:
        return _pyAgrum.BayesNetFragment_whenArcDeleted(self, src, _from, to)

    def cpt(self, *args) -> "pyAgrum.Potential":
        r"""

        Returns the CPT of a variable.

        Parameters
        ----------
        VarId : int
        	A variable's id in the pyAgrum.IBayesNet.
        name : str
        	A variable's name in the pyAgrum.IBayesNet.

        Returns
        -------
        pyAgrum.Potential
        	The variable's CPT. 

        Raises
        ------
        pyAgrum.NotFound
        	If no variable's id matches varId. 

        """
        return _pyAgrum.BayesNetFragment_cpt(self, *args)

    def variableNodeMap(self) -> "pyAgrum.VariableNodeMap":
        r"""

        Returns
        -------
        pyAgrum.variableNodeMap
        	the variable node map

        """
        return _pyAgrum.BayesNetFragment_variableNodeMap(self)

    def variable(self, *args) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        id : int
        	a variable's id
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.BayesNetFragment_variable(self, *args)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Parameters
        ----------
        var : pyAgrum.DiscreteVariable
        	a variable

        Returns
        -------
        int
        	the id of the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.BayesNetFragment_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        r"""

        Returns a variable's id given its name in the graph.

        Parameters
        ----------
        name : str
        	The variable's name from which the id is returned.

        Returns
        -------
        int :
        	The variable's node id.

        Raises
        ------
        pyAgrum.NotFound
        	If name does not match a variable in the graph

        """
        return _pyAgrum.BayesNetFragment_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the graph does not contain the variable

        """
        return _pyAgrum.BayesNetFragment_variableFromName(self, name)

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format

        """
        return _pyAgrum.BayesNetFragment_toDot(self)

    def isInstalledNode(self, *args) -> bool:
        r"""

        Check if a node is in the fragment

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.

        """
        return _pyAgrum.BayesNetFragment_isInstalledNode(self, *args)

    def installNode(self, *args) -> None:
        r"""

        Add a node to the fragment. The arcs that can be added between installed nodes are created.
        No specific CPT are created. Then either the parents of the node are already in the fragment 
        and the node is consistant, or the parents are not in the fragment and the node is not consistant.

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_installNode(self, *args)

    def installAscendants(self, *args) -> None:
        r"""

        Add the variable and all its ascendants in the fragment. No inconsistant node are created.

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_installAscendants(self, *args)

    def uninstallNode(self, *args) -> None:
        r"""

        Remove a node from the fragment. The fragment can become inconsistant.

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_uninstallNode(self, *args)

    def installMarginal(self, *args) -> None:
        r"""

        Install a local marginal for a node. Doing so, it removes the parents of the node in the fragment.

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.
        pot : Potential
          the Potential (marginal) to install

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_installMarginal(self, *args)

    def installCPT(self, *args) -> None:
        r"""

        Install a local CPT for a node. Doing so, it changes the parents of the node in the fragment.

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.
        pot : Potential
          the Potential to install

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_installCPT(self, *args)

    def uninstallCPT(self, *args) -> None:
        r"""

        Remove a local CPT. The fragment can become inconsistant.

        Parameters
        ----------
        n : int, str
        	the id or the name of the variable.

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_uninstallCPT(self, *args)

    def checkConsistency(self, *args) -> bool:
        r"""

        If a variable is added to the fragment but not its parents, there is no CPT consistant for this variable. This function checks the consistency for a variable of for all.

        Parameters
        ----------

        n : int, str (optional)
        	the id or the name of the variable. If no argument, the function checks all the variables.

        Returns
        -------
        boolean
        	True if the variable(s) is consistant.

        Raises
        ------
        pyAgrum.NotFound
          if the node is not found.

        """
        return _pyAgrum.BayesNetFragment_checkConsistency(self, *args)

    def toBN(self) -> "pyAgrum.BayesNet":
        r"""

        Create a BayesNet from a fragment.

        Raises
        ------
        pyAgrum.OperationNotAllowed
          if the fragment is not consistent.

        """
        return _pyAgrum.BayesNetFragment_toBN(self)

    def dag(self) -> "pyAgrum.DAG":
        r"""

        Returns
        -------
        pyAgrum.DAG
        	a constant reference to the dag of this BayesNet.

        """
        val = _pyAgrum.BayesNetFragment_dag(self)

        val = DAG(val) # copying the DAG


        return val


    def minimalCondSet(self, *args) -> object:
        r"""

        Returns, given one or many targets and a list of variables, the minimal set of those needed to calculate the target/targets.

        Parameters
        ----------
        target : int
        	The id of the target
        targets : list
        	The ids of the targets
        list : list
        	The list of available variables

        Returns
        -------
        Set
        	The minimal set of variables

        """
        return _pyAgrum.BayesNetFragment_minimalCondSet(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.BayesNetFragment_isIndependent(self, *args)

    def names(self) -> object:
        r"""

        Returns
        -------
        list
        	The names of the graph variables

        """
        return _pyAgrum.BayesNetFragment_names(self)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.BayesNetFragment_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def arcs(self) -> object:
        r"""

        Returns
        -------
        list
        	The lisf of arcs in the IBayesNet

        """
        return _pyAgrum.BayesNetFragment_arcs(self)

    def parents(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        Set
            the set of the parents ids.

        """
        return _pyAgrum.BayesNetFragment_parents(self, norid)

    def children(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.BayesNetFragment_children(self, norid)

    def family(self, norid: object) -> object:
        return _pyAgrum.BayesNetFragment_family(self, norid)

    def descendants(self, norid: object) -> object:
        return _pyAgrum.BayesNetFragment_descendants(self, norid)

    def ancestors(self, norid: object) -> object:
        return _pyAgrum.BayesNetFragment_ancestors(self, norid)

    def moralizedAncestralGraph(self, nodes: object) -> "pyAgrum.UndiGraph":
        return _pyAgrum.BayesNetFragment_moralizedAncestralGraph(self, nodes)

    def addStructureListener(self,whenNodeAdded=None,whenNodeDeleted=None,whenArcAdded=None,whenArcDeleted=None):
        """
        Add the listeners in parameters to the list of existing ones.

        Parameters
        ----------
        whenNodeAdded : lambda expression
          a function for when a node is added
        whenNodeDeleted : lambda expression
          a function for when a node is removed
        whenArcAdded : lambda expression
          a function for when an arc is added
        whenArcDeleted : lambda expression
          a function for when an arc is removed
        """
        if [whenNodeAdded,whenNodeDeleted,whenArcAdded,whenArcDeleted]==[None,None,None,None]:
          return

        if not hasattr(self,"_listeners"):
          self._listeners=[]

        nl = PythonBNListener(self, self.variableNodeMap())
        if whenNodeAdded is not None:
          nl.setWhenNodeAdded(whenNodeAdded)
        if whenNodeDeleted is not None:
          nl.setWhenNodeDeleted(whenNodeDeleted)
        if whenArcAdded is not None:
          nl.setWhenArcAdded(whenArcAdded)
        if whenArcDeleted is not None:
          nl.setWhenArcDeleted(whenArcDeleted)

        self._listeners.append(nl)


# Register BayesNetFragment in _pyAgrum:
_pyAgrum.BayesNetFragment_swigregister(BayesNetFragment)

class IMarkovNet(UGmodel):
    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 - class is abstract")
    __swig_destroy__ = _pyAgrum.delete_IMarkovNet

    def smallestFactorFromNode(self, *args) -> List[int]:
        return _pyAgrum.IMarkovNet_smallestFactorFromNode(self, *args)

    def factors(self) -> List[Set[int]]:
        return _pyAgrum.IMarkovNet_factors(self)

    def variableNodeMap(self) -> "pyAgrum.VariableNodeMap":
        return _pyAgrum.IMarkovNet_variableNodeMap(self)

    def variable(self, id: int) -> "pyAgrum.DiscreteVariable":
        return _pyAgrum.IMarkovNet_variable(self, id)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        return _pyAgrum.IMarkovNet_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        return _pyAgrum.IMarkovNet_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        return _pyAgrum.IMarkovNet_variableFromName(self, name)

    def __eq__(self, _from: "IMarkovNet") -> bool:
        return _pyAgrum.IMarkovNet___eq__(self, _from)

    def __ne__(self, _from: "IMarkovNet") -> bool:
        return _pyAgrum.IMarkovNet___ne__(self, _from)

    def dim(self) -> int:
        return _pyAgrum.IMarkovNet_dim(self)

    def maxVarDomainSize(self) -> int:
        return _pyAgrum.IMarkovNet_maxVarDomainSize(self)

    def minParam(self) -> float:
        return _pyAgrum.IMarkovNet_minParam(self)

    def maxParam(self) -> float:
        return _pyAgrum.IMarkovNet_maxParam(self)

    def minNonZeroParam(self) -> float:
        return _pyAgrum.IMarkovNet_minNonZeroParam(self)

    def maxNonOneParam(self) -> float:
        return _pyAgrum.IMarkovNet_maxNonOneParam(self)

    def toDot(self) -> str:
        return _pyAgrum.IMarkovNet_toDot(self)

    def toDotAsFactorGraph(self) -> str:
        return _pyAgrum.IMarkovNet_toDotAsFactorGraph(self)

    def names(self) -> object:
        return _pyAgrum.IMarkovNet_names(self)

    def nodes(self) -> object:
        return _pyAgrum.IMarkovNet_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def neighbours(self, norid: object) -> object:
        return _pyAgrum.IMarkovNet_neighbours(self, norid)

    def edges(self) -> object:
        return _pyAgrum.IMarkovNet_edges(self)

    def minimalCondSet(self, *args) -> object:
        return _pyAgrum.IMarkovNet_minimalCondSet(self, *args)

    def factor(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.IMarkovNet_factor(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.IMarkovNet_isIndependent(self, *args)

    def __repr__(self) -> str:
        return _pyAgrum.IMarkovNet___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.IMarkovNet___str__(self)

# Register IMarkovNet in _pyAgrum:
_pyAgrum.IMarkovNet_swigregister(IMarkovNet)

class MarkovNet(IMarkovNet):
    r"""

    MarkovNet represents a Markov Network.

    MarkovNet(name='') -> MarkovNet
        Parameters:
          * **name** (*str*) -- the name of the Bayes Net

    MarkovNet(source) -> MarkovNet
        Parameters:
          * **source** (*pyAgrum.MarkovNet*) -- the Markov network to copy

    """

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

    @staticmethod
    def fastPrototype(dotlike: str, domainSize: int=2) -> "pyAgrum.MarkovNet":
        r"""

        Create a Markov network with a modified dot-like syntax which specifies:
            - the structure ``a-b-c;b-d-e;``. The substring ``a-b-c`` indicates a factor with the scope (a,b,c).
            - the type of the variables with different syntax (cf documentation).

        Examples
        --------
        >>> import pyAgrum as gum
        >>> bn=pyAgrum.MarkovNet.fastPrototype('A--B[1,3]-C{yes|No}--D[2,4]--E[1,2.5,3.9]',6)

        Parameters
        ----------
        dotlike : str
                the string containing the specification
        domainSize : int
                the default domain size for variables

        Returns
        -------
        pyAgrum.MarkovNet
                the resulting Markov network 

        """
        return _pyAgrum.MarkovNet_fastPrototype(dotlike, domainSize)

    @staticmethod
    def fromBN(bn: "pyAgrum.BayesNet") -> "pyAgrum.MarkovNet":
        return _pyAgrum.MarkovNet_fromBN(bn)
    __swig_destroy__ = _pyAgrum.delete_MarkovNet

    def __init__(self, *args):
        _pyAgrum.MarkovNet_swiginit(self, _pyAgrum.new_MarkovNet(*args))

    def smallestFactorFromNode(self, node: int) -> List[int]:
        return _pyAgrum.MarkovNet_smallestFactorFromNode(self, node)

    def factors(self) -> List[Set[int]]:
        return _pyAgrum.MarkovNet_factors(self)

    def variableNodeMap(self) -> "pyAgrum.VariableNodeMap":
        return _pyAgrum.MarkovNet_variableNodeMap(self)

    def add(self, *args) -> int:
        r"""

        Add a variable to the pyAgrum.MarkovNet. 

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable added
        name : str 
        	the variable name
        nbrmod : int
        	the number of modalities for the new variable
        id : int
        	the variable forced id in the pyAgrum.MarkovNet

        Returns
        -------
        int 
        	the id of the new node

        Raises
        ------
        pyAgrum.DuplicateLabel
            If variable.name() is already used in this pyAgrum.MarkovNet.
        pyAgrum.NotAllowed
            If nbrmod is less than 2
        pyAgrum.DuplicateElement
            If id is already used.

        """
        return _pyAgrum.MarkovNet_add(self, *args)

    def clear(self) -> None:
        r"""

        Clear the whole MarkovNet  

        """
        return _pyAgrum.MarkovNet_clear(self)

    def erase(self, *args) -> None:
        r"""

        Remove a variable from the pyAgrum.MarkovNet.

        Removes the corresponding variable from the pyAgrum.MarkovNet and from all of it's children pyAgrum.Potential.

        If no variable matches the given id, then nothing is done.

        Parameters
        ----------
        id : int
        	The variable's id to remove. 
        name : str
        	The variable's name to remove.
        var : pyAgrum.DiscreteVariable
        	A reference on the variable to remove. 

        """
        return _pyAgrum.MarkovNet_erase(self, *args)

    def variable(self, *args) -> "pyAgrum.DiscreteVariable":
        return _pyAgrum.MarkovNet_variable(self, *args)

    def changeVariableName(self, *args) -> None:
        r"""

        Changes a variable's name in the pyAgrum.MarkovNet.

        This will change the "pyAgrum.DiscreteVariable" names in the pyAgrum.MarkovNet.

        Parameters
        ----------
        new_name : str
        	the new name of the variable
        NodeId : int
        	the id of the node
        name : str
        	the name of the variable

        Raises
        ------
        pyAgrum.DuplicateLabel
            If new_name is already used in this MarkovNet.
        pyAgrum.NotFound
            If no variable matches id.

        """
        return _pyAgrum.MarkovNet_changeVariableName(self, *args)

    def changeVariableLabel(self, *args) -> None:
        r"""

        change the label of the variable associated to nodeId to the new value.

        Parameters
        ----------
        id : int
        	the id of the node
        name : str
        	the name of the variable
        old_label : str
        	the new label
        new_label : str
        	the new label

        Raises
        ------
        pyAgrum.NotFound
            if id/name is not a variable or if old_label does not exist.

        """
        return _pyAgrum.MarkovNet_changeVariableLabel(self, *args)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        return _pyAgrum.MarkovNet_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        return _pyAgrum.MarkovNet_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        return _pyAgrum.MarkovNet_variableFromName(self, name)

    def generateFactors(self) -> None:
        r"""

        Randomly generates factors parameters for a given structure.

        """
        return _pyAgrum.MarkovNet_generateFactors(self)

    def generateFactor(self, vars: List[int]) -> None:
        r"""

        Randomly generate factor parameters for a given factor in a given structure.

        Parameters
        ----------
        node : int
        	The variable's id.
        name : str 
        	The variable's name.

        """
        return _pyAgrum.MarkovNet_generateFactor(self, vars)

    def beginTopologyTransformation(self) -> None:
        return _pyAgrum.MarkovNet_beginTopologyTransformation(self)

    def endTopologyTransformation(self) -> None:
        r"""

        Terminates a sequence of insertions/deletions of arcs by adjusting all CPTs dimensions.
        End Multiple Change for all CPTs.

        Returns
        -------
        pyAgrum.MarkovNet

        """
        return _pyAgrum.MarkovNet_endTopologyTransformation(self)

    def graph(self) -> "pyAgrum.UndiGraph":
        return _pyAgrum.MarkovNet_graph(self)

    def size(self) -> int:
        return _pyAgrum.MarkovNet_size(self)

    def log10DomainSize(self) -> float:
        return _pyAgrum.MarkovNet_log10DomainSize(self)

    def names(self) -> object:
        return _pyAgrum.MarkovNet_names(self)

    def nodes(self) -> object:
        return _pyAgrum.MarkovNet_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def neighbours(self, norid: object) -> object:
        return _pyAgrum.MarkovNet_neighbours(self, norid)

    def edges(self) -> object:
        return _pyAgrum.MarkovNet_edges(self)

    def minimalCondSet(self, *args) -> object:
        return _pyAgrum.MarkovNet_minimalCondSet(self, *args)

    def factor(self, *args) -> "pyAgrum.Potential":
        r"""

        Returns the factor of a set of variables (if existing).

        Parameters
        ----------
        VarId : Set[int]
        	A variable's id in the pyAgrum.MarkovNet.
        name : Set[str]
        	A variable's name in the pyAgrum.MarkovNet.

        Returns
        -------
        pyAgrum.Potential
        	The factor of the set of nodes. 

        Raises
        ------
        pyAgrum.NotFound
            If no variable's id matches varId.

        """
        return _pyAgrum.MarkovNet_factor(self, *args)

    def isIndependent(self, *args) -> bool:
        return _pyAgrum.MarkovNet_isIndependent(self, *args)

    def loadUAI(self, *args) -> str:
        r"""

        Load an UAI file.

        Parameters
        ----------
        name : str
        	the name's file
        l : list
        	list of functions to execute

        Raises
        ------
        pyAgrum.IOError
            If file not found
        pyAgrum.FatalError
            If file is not valid

        """
        return _pyAgrum.MarkovNet_loadUAI(self, *args)

    def saveUAI(self, name: str) -> None:
        r"""

        Save the MarkovNet in an UAI file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.MarkovNet_saveUAI(self, name)

    def __repr__(self) -> str:
        return _pyAgrum.MarkovNet___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.MarkovNet___str__(self)

    def addFactor(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.MarkovNet_addFactor(self, *args)

    def eraseFactor(self, *args) -> None:
        return _pyAgrum.MarkovNet_eraseFactor(self, *args)

    def addStructureListener(self,whenNodeAdded=None,whenNodeDeleted=None,whenEdgeAdded=None,whenedgeDeleted=None):
        """
        Add the listeners in parameters to the list of existing ones.

        Parameters
        ----------
        whenNodeAdded : lambda expression
          a function for when a node is added
        whenNodeDeleted : lambda expression
          a function for when a node is removed
        whenEdgeAdded : lambda expression
          a function for when an edge is added
        whenEdgeDeleted : lambda expression
          a function for when an edge is removed
        """
        if [whenNodeAdded,whenNodeDeleted,whenEdgeAdded,whenEdgeDeleted]==[None,None,None,None]:
          return

        if not hasattr(self,"_listeners"):
          self._listeners=[]

        nl = PythonMNListener(self, self.variableNodeMap())
        if whenNodeAdded is not None:
          nl.setWhenNodeAdded(whenNodeAdded)
        if whenNodeDeleted is not None:
          nl.setWhenNodeDeleted(whenNodeDeleted)
        if whenEdgeAdded is not None:
          nl.setWhenEdgeAdded(whenEdgeAdded)
        if whenEdgeDeleted is not None:
          nl.setWhenArcDeleted(whenEdgeDeleted)

        self._listeners.append(nl)


# Register MarkovNet in _pyAgrum:
_pyAgrum.MarkovNet_swigregister(MarkovNet)

def MarkovNet_fastPrototype(dotlike: str, domainSize: int=2) -> "pyAgrum.MarkovNet":
    r"""

    Create a Markov network with a modified dot-like syntax which specifies:
        - the structure ``a-b-c;b-d-e;``. The substring ``a-b-c`` indicates a factor with the scope (a,b,c).
        - the type of the variables with different syntax (cf documentation).

    Examples
    --------
    >>> import pyAgrum as gum
    >>> bn=pyAgrum.MarkovNet.fastPrototype('A--B[1,3]-C{yes|No}--D[2,4]--E[1,2.5,3.9]',6)

    Parameters
    ----------
    dotlike : str
            the string containing the specification
    domainSize : int
            the default domain size for variables

    Returns
    -------
    pyAgrum.MarkovNet
            the resulting Markov network 

    """
    return _pyAgrum.MarkovNet_fastPrototype(dotlike, domainSize)

def MarkovNet_fromBN(bn: "pyAgrum.BayesNet") -> "pyAgrum.MarkovNet":
    return _pyAgrum.MarkovNet_fromBN(bn)

class ShaferShenoyMNInference(object):
    r"""

    Class used for Shafer-Shenoy inferences for Markov network.

    ShaferShenoyInference(bn) -> ShaferShenoyInference
        Parameters:
            * **mn** (*pyAgrum.MarkovNet*) -- a Markov network

    """

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

    def __init__(self, MN: "IMarkovNet", use_binary_join_tree: bool=True):
        _pyAgrum.ShaferShenoyMNInference_swiginit(self, _pyAgrum.new_ShaferShenoyMNInference(MN, use_binary_join_tree))

        self._model=MN#first arg of the constructor



    __swig_destroy__ = _pyAgrum.delete_ShaferShenoyMNInference

    def setTriangulation(self, new_triangulation: "pyAgrum.Triangulation") -> None:
        return _pyAgrum.ShaferShenoyMNInference_setTriangulation(self, new_triangulation)

    def joinTree(self) -> "pyAgrum.CliqueGraph":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current join tree used

        """
        return _pyAgrum.ShaferShenoyMNInference_joinTree(self)

    def junctionTree(self) -> "pyAgrum.JunctionTree":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current junction tree

        """
        val = _pyAgrum.ShaferShenoyMNInference_junctionTree(self)

        val._engine=self


        return val


    def evidenceProbability(self) -> float:
        r"""

        Returns
        -------
        float
          the probability of evidence

        """
        return _pyAgrum.ShaferShenoyMNInference_evidenceProbability(self)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.ShaferShenoyMNInference_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.ShaferShenoyMNInference_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.ShaferShenoyMNInference_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.ShaferShenoyMNInference_evidenceImpact(self, target, evs)

    def jointMutualInformation(self, targets: object) -> float:
        return _pyAgrum.ShaferShenoyMNInference_jointMutualInformation(self, targets)

    def jointPosterior(self, targets: object) -> "pyAgrum.Potential":
        r"""

        Compute the joint posterior of a set of nodes.

        Parameters
        ----------
        list :
          the list of nodes whose posterior joint probability is wanted


        Warnings
        --------
        The order of the variables given by the list here or when the jointTarget is declared can not be assumed to be used bu the Potential.

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior joint probability of the set of nodes.

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.ShaferShenoyMNInference_jointPosterior(self, targets)

    def addJointTarget(self, targets: object) -> None:
        r"""

        Add a list of nodes as a new joint target. As a collateral effect, every node is added as a marginal target.

        Parameters
        ----------
        list
          a list of names of nodes

        Raises
        ------
        pyAgrum.UndefinedElement
          If some node(s) do not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_addJointTarget(self, targets)

    def eraseJointTarget(self, targets: object) -> None:
        r"""

        Remove, if existing, the joint target.

        Parameters
        ----------
        list
          a list of names or Ids of nodes

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseJointTarget(self, targets)

    def isJointTarget(self, targets: object) -> bool:
        r"""

        Parameters
        ----------
        list
          a list of nodes ids or names.

        Returns
        -------
        bool
          True if target is a joint target.

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_isJointTarget(self, targets)

    def jointTargets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of target sets

        """
        return _pyAgrum.ShaferShenoyMNInference_jointTargets(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.ShaferShenoyMNInference_makeInference(self)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.ShaferShenoyMNInference_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.ShaferShenoyMNInference_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyMNInference_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.ShaferShenoyMNInference_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the Shanon's entropy of a node given the observation

        """
        return _pyAgrum.ShaferShenoyMNInference_H(self, *args)

    def MN(self) -> "pyAgrum.IMarkovNet":
        return _pyAgrum.ShaferShenoyMNInference_MN(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.ShaferShenoyMNInference_posterior(self, *args)

    def eraseAllJointTargets(self) -> None:
        r"""

        Clear all previously defined joint targets.

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseAllJointTargets(self)

    def eraseAllMarginalTargets(self) -> None:
        r"""

        Clear all the previously defined marginal targets.

        """
        return _pyAgrum.ShaferShenoyMNInference_eraseAllMarginalTargets(self)

    def nbrJointTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of joint targets

        """
        return _pyAgrum.ShaferShenoyMNInference_nbrJointTargets(self)

    def I(self, X: int, Y: int) -> float:
        r"""

        Parameters
        ----------
        X : int or str
          a node Id or a node name
        Y : int or str
          another node Id or node name

        Returns
        -------
        float
          the Mutual Information of X and Y given the observation

        """
        return _pyAgrum.ShaferShenoyMNInference_I(self, X, Y)

    def VI(self, X: int, Y: int) -> float:
        r"""

        Parameters
        ----------
        X : int or str
           a node Id or a node name
        Y : int or str
           another node Id or node name

        Returns
        -------
        float
          variation of information between X and Y

        """
        return _pyAgrum.ShaferShenoyMNInference_VI(self, X, Y)

    def evidenceJointImpact(self, *args) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(joint targets|evs) (for all instanciation of targets and evs)

        Parameters
        ----------
        targets :
          (int) a node Id
        targets :
          (str) a node name
        evs : set
          a set of nodes ids or names.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(target|evs)

        Raises
        ------
        pyAgrum.Exception
          If some evidene entered into the Bayes net are incompatible (their joint proba = 0)

        """
        return _pyAgrum.ShaferShenoyMNInference_evidenceJointImpact(self, *args)

# Register ShaferShenoyMNInference in _pyAgrum:
_pyAgrum.ShaferShenoyMNInference_swigregister(ShaferShenoyMNInference)

class LazyPropagation(object):
    r"""

    Class used for Lazy Propagation

    LazyPropagation(bn) -> LazyPropagation
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

    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):
        _pyAgrum.LazyPropagation_swiginit(self, _pyAgrum.new_LazyPropagation(*args))

        self._model=args[0]



    __swig_destroy__ = _pyAgrum.delete_LazyPropagation

    def setTriangulation(self, new_triangulation: "pyAgrum.Triangulation") -> None:
        return _pyAgrum.LazyPropagation_setTriangulation(self, new_triangulation)

    def setRelevantPotentialsFinderType(self, type: int) -> None:
        r"""

        sets how we determine the relevant potentials to combine

        When a clique sends a message to a separator, it first constitute the set of the potentials it contains and of the potentials contained in the messages it received. If RelevantPotentialsFinderType = FIND_ALL, all these potentials are combined and projected to produce the message sent to the separator. If RelevantPotentialsFinderType = DSEP_BAYESBALL_NODES, then only the set of potentials d-connected to the variables of the separator are kept for combination and projection.

        0 = FIND_ALL
        1 = DSEP_BAYESBALL_NODES
        2 = DSEP_BAYESBALL_POTENTIALS
        3 = DSEP_KOLLER_FRIEDMAN_2009

        Parameters
        ----------
        type : int
          the finder type

        Raises
        ------
        pyAgrum.InvalidArgument
          If type is not implemented

        """
        return _pyAgrum.LazyPropagation_setRelevantPotentialsFinderType(self, type)

    def setFindBarrenNodesType(self, type: int) -> None:
        r"""

        sets how we determine barren nodes

        Barren nodes are unnecessary for probability inference, so they can be safely discarded in this case (type = FIND_BARREN_NODES). This speeds-up inference. However, there are some cases in which we do not want to remove barren nodes, typically when we want to answer queries such as Most Probable Explanations (MPE).

        0 = FIND_NO_BARREN_NODES
        1 = FIND_BARREN_NODES

        Parameters
        ----------
        type : int
          the finder type

        Raises
        ------
        pyAgrum.InvalidArgument
          If type is not implemented

        """
        return _pyAgrum.LazyPropagation_setFindBarrenNodesType(self, type)

    def joinTree(self) -> "pyAgrum.CliqueGraph":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current join tree used

        """
        return _pyAgrum.LazyPropagation_joinTree(self)

    def junctionTree(self) -> "pyAgrum.JunctionTree":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current junction tree

        """
        val = _pyAgrum.LazyPropagation_junctionTree(self)

        val._engine=self


        return val


    def evidenceProbability(self) -> float:
        r"""

        Returns
        -------
        float
          the probability of evidence

        """
        return _pyAgrum.LazyPropagation_evidenceProbability(self)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.LazyPropagation_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.LazyPropagation_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.LazyPropagation_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.LazyPropagation_evidenceImpact(self, target, evs)

    def jointMutualInformation(self, targets: object) -> float:
        return _pyAgrum.LazyPropagation_jointMutualInformation(self, targets)

    def jointPosterior(self, targets: object) -> "pyAgrum.Potential":
        r"""

        Compute the joint posterior of a set of nodes.

        Parameters
        ----------
        list :
          the list of nodes whose posterior joint probability is wanted


        Warnings
        --------
        The order of the variables given by the list here or when the jointTarget is declared can not be assumed to be used bu the Potential.

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior joint probability of the set of nodes.

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LazyPropagation_jointPosterior(self, targets)

    def addJointTarget(self, targets: object) -> None:
        r"""

        Add a list of nodes as a new joint target. As a collateral effect, every node is added as a marginal target.

        Parameters
        ----------
        list
          a list of names of nodes

        Raises
        ------
        pyAgrum.UndefinedElement
          If some node(s) do not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_addJointTarget(self, targets)

    def eraseJointTarget(self, targets: object) -> None:
        r"""

        Remove, if existing, the joint target.

        Parameters
        ----------
        list
          a list of names or Ids of nodes

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LazyPropagation_eraseJointTarget(self, targets)

    def isJointTarget(self, targets: object) -> bool:
        r"""

        Parameters
        ----------
        list
          a list of nodes ids or names.

        Returns
        -------
        bool
          True if target is a joint target.

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LazyPropagation_isJointTarget(self, targets)

    def jointTargets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of target sets

        """
        return _pyAgrum.LazyPropagation_jointTargets(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.LazyPropagation_makeInference(self)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.LazyPropagation_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LazyPropagation_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.LazyPropagation_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.LazyPropagation_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.LazyPropagation_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.LazyPropagation_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.LazyPropagation_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.LazyPropagation_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LazyPropagation_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LazyPropagation_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.LazyPropagation_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.LazyPropagation_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.LazyPropagation_BN(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LazyPropagation_posterior(self, *args)

    def eraseAllJointTargets(self) -> None:
        r"""

        Clear all previously defined joint targets.

        """
        return _pyAgrum.LazyPropagation_eraseAllJointTargets(self)

    def eraseAllMarginalTargets(self) -> None:
        r"""

        Clear all the previously defined marginal targets.

        """
        return _pyAgrum.LazyPropagation_eraseAllMarginalTargets(self)

    def nbrJointTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of joint targets

        """
        return _pyAgrum.LazyPropagation_nbrJointTargets(self)

    def I(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int or str
           a node Id or a node name
        Y : int or str
           another node Id or node name

           Returns
        -------
        float
           the Mutual Information of X and Y given the observation

        """
        return _pyAgrum.LazyPropagation_I(self, *args)

    def VI(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int or str
           a node Id or a node name
        Y : int or str
           another node Id or node name

           Returns
        -------
        float
           variation of information between X and Y

        """
        return _pyAgrum.LazyPropagation_VI(self, *args)

    def evidenceJointImpact(self, *args) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(joint targets|evs) (for all instanciation of targets and evs)

        Parameters
        ----------
        targets :
          (int) a node Id
        targets :
          (str) a node name
        evs : set
          a set of nodes ids or names.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(target|evs)

        Raises
        ------
        pyAgrum.Exception
          If some evidene entered into the Bayes net are incompatible (their joint proba = 0)

        """
        return _pyAgrum.LazyPropagation_evidenceJointImpact(self, *args)

# Register LazyPropagation in _pyAgrum:
_pyAgrum.LazyPropagation_swigregister(LazyPropagation)

class ShaferShenoyInference(object):
    r"""

    Class used for Shafer-Shenoy inferences.

    ShaferShenoyInference(bn) -> ShaferShenoyInference
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

    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):
        _pyAgrum.ShaferShenoyInference_swiginit(self, _pyAgrum.new_ShaferShenoyInference(*args))

        self._model=args[0]



    __swig_destroy__ = _pyAgrum.delete_ShaferShenoyInference

    def setTriangulation(self, new_triangulation: "pyAgrum.Triangulation") -> None:
        return _pyAgrum.ShaferShenoyInference_setTriangulation(self, new_triangulation)

    def setFindBarrenNodesType(self, type: int) -> None:
        r"""

        sets how we determine barren nodes

        Barren nodes are unnecessary for probability inference, so they can be safely discarded in this case (type = FIND_BARREN_NODES). This speeds-up inference. However, there are some cases in which we do not want to remove barren nodes, typically when we want to answer queries such as Most Probable Explanations (MPE).

        0 = FIND_NO_BARREN_NODES
        1 = FIND_BARREN_NODES

        Parameters
        ----------
        type : int
          the finder type

        Raises
        ------
        pyAgrum.InvalidArgument
          If type is not implemented

        """
        return _pyAgrum.ShaferShenoyInference_setFindBarrenNodesType(self, type)

    def joinTree(self) -> "pyAgrum.CliqueGraph":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current join tree used

        """
        return _pyAgrum.ShaferShenoyInference_joinTree(self)

    def junctionTree(self) -> "pyAgrum.JunctionTree":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current junction tree

        """
        val = _pyAgrum.ShaferShenoyInference_junctionTree(self)

        val._engine=self


        return val


    def evidenceProbability(self) -> float:
        r"""

        Returns
        -------
        float
          the probability of evidence

        """
        return _pyAgrum.ShaferShenoyInference_evidenceProbability(self)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.ShaferShenoyInference_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.ShaferShenoyInference_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.ShaferShenoyInference_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.ShaferShenoyInference_evidenceImpact(self, target, evs)

    def jointMutualInformation(self, targets: object) -> float:
        return _pyAgrum.ShaferShenoyInference_jointMutualInformation(self, targets)

    def jointPosterior(self, targets: object) -> "pyAgrum.Potential":
        r"""

        Compute the joint posterior of a set of nodes.

        Parameters
        ----------
        list :
          the list of nodes whose posterior joint probability is wanted


        Warnings
        --------
        The order of the variables given by the list here or when the jointTarget is declared can not be assumed to be used bu the Potential.

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior joint probability of the set of nodes.

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.ShaferShenoyInference_jointPosterior(self, targets)

    def addJointTarget(self, targets: object) -> None:
        r"""

        Add a list of nodes as a new joint target. As a collateral effect, every node is added as a marginal target.

        Parameters
        ----------
        list
          a list of names of nodes

        Raises
        ------
        pyAgrum.UndefinedElement
          If some node(s) do not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_addJointTarget(self, targets)

    def eraseJointTarget(self, targets: object) -> None:
        r"""

        Remove, if existing, the joint target.

        Parameters
        ----------
        list
          a list of names or Ids of nodes

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_eraseJointTarget(self, targets)

    def isJointTarget(self, targets: object) -> bool:
        r"""

        Parameters
        ----------
        list
          a list of nodes ids or names.

        Returns
        -------
        bool
          True if target is a joint target.

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_isJointTarget(self, targets)

    def jointTargets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of target sets

        """
        return _pyAgrum.ShaferShenoyInference_jointTargets(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.ShaferShenoyInference_makeInference(self)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.ShaferShenoyInference_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.ShaferShenoyInference_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.ShaferShenoyInference_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.ShaferShenoyInference_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ShaferShenoyInference_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.ShaferShenoyInference_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.ShaferShenoyInference_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.ShaferShenoyInference_BN(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.ShaferShenoyInference_posterior(self, *args)

    def eraseAllJointTargets(self) -> None:
        r"""

        Clear all previously defined joint targets.

        """
        return _pyAgrum.ShaferShenoyInference_eraseAllJointTargets(self)

    def eraseAllMarginalTargets(self) -> None:
        r"""

        Clear all the previously defined marginal targets.

        """
        return _pyAgrum.ShaferShenoyInference_eraseAllMarginalTargets(self)

    def nbrJointTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of joint targets

        """
        return _pyAgrum.ShaferShenoyInference_nbrJointTargets(self)

    def I(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int or str
           a node Id or a node name
        Y : int or str
           another node Id or node name

           Returns
        -------
        float
           the Mutual Information of X and Y given the observation

        """
        return _pyAgrum.ShaferShenoyInference_I(self, *args)

    def VI(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int or str
           a node Id or a node name
        Y : int or str
           another node Id or node name

           Returns
        -------
        float
           variation of information between X and Y

        """
        return _pyAgrum.ShaferShenoyInference_VI(self, *args)

    def evidenceJointImpact(self, *args) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(joint targets|evs) (for all instanciation of targets and evs)

        Parameters
        ----------
        targets :
          (int) a node Id
        targets :
          (str) a node name
        evs : set
          a set of nodes ids or names.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(target|evs)

        Raises
        ------
        pyAgrum.Exception
          If some evidene entered into the Bayes net are incompatible (their joint proba = 0)

        """
        return _pyAgrum.ShaferShenoyInference_evidenceJointImpact(self, *args)

# Register ShaferShenoyInference in _pyAgrum:
_pyAgrum.ShaferShenoyInference_swigregister(ShaferShenoyInference)

class VariableElimination(object):
    r"""

    Class used for Variable Elimination inference algorithm.

    VariableElimination(bn) -> VariableElimination
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

    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):
        _pyAgrum.VariableElimination_swiginit(self, _pyAgrum.new_VariableElimination(*args))

        self._model=args[0]



    __swig_destroy__ = _pyAgrum.delete_VariableElimination

    def setTriangulation(self, new_triangulation: "pyAgrum.Triangulation") -> None:
        return _pyAgrum.VariableElimination_setTriangulation(self, new_triangulation)

    def setRelevantPotentialsFinderType(self, type: int) -> None:
        r"""

        sets how we determine the relevant potentials to combine

        When a clique sends a message to a separator, it first constitute the set of the potentials it contains and of the potentials contained in the messages it received. If RelevantPotentialsFinderType = FIND_ALL, all these potentials are combined and projected to produce the message sent to the separator. If RelevantPotentialsFinderType = DSEP_BAYESBALL_NODES, then only the set of potentials d-connected to the variables of the separator are kept for combination and projection.

        0 = FIND_ALL
        1 = DSEP_BAYESBALL_NODES
        2 = DSEP_BAYESBALL_POTENTIALS
        3 = DSEP_KOLLER_FRIEDMAN_2009

        Parameters
        ----------
        type : int
          the finder type

        Raises
        ------
        pyAgrum.InvalidArgument
          If type is not implemented

        """
        return _pyAgrum.VariableElimination_setRelevantPotentialsFinderType(self, type)

    def setFindBarrenNodesType(self, type: int) -> None:
        r"""

        sets how we determine barren nodes

        Barren nodes are unnecessary for probability inference, so they can be safely discarded in this case (type = FIND_BARREN_NODES). This speeds-up inference. However, there are some cases in which we do not want to remove barren nodes, typically when we want to answer queries such as Most Probable Explanations (MPE).

        0 = FIND_NO_BARREN_NODES
        1 = FIND_BARREN_NODES

        Parameters
        ----------
        type : int
          the finder type

        Raises
        ------
        pyAgrum.InvalidArgument
          If type is not implemented

        """
        return _pyAgrum.VariableElimination_setFindBarrenNodesType(self, type)

    def junctionTree(self, id: int) -> "pyAgrum.JunctionTree":
        r"""

        Returns
        -------
        pyAgrum.CliqueGraph
          the current junction tree

        """
        val = _pyAgrum.VariableElimination_junctionTree(self, id)

        val._engine=self


        return val


    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.VariableElimination_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.VariableElimination_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.VariableElimination_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.VariableElimination_evidenceImpact(self, target, evs)

    def jointMutualInformation(self, targets: object) -> float:
        return _pyAgrum.VariableElimination_jointMutualInformation(self, targets)

    def evidenceJointImpact(self, targets: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(joint targets|evs) (for all instanciation of targets and evs)

        Parameters
        ----------
        targets :
          (int) a node Id
        targets :
          (str) a node name
        evs : set
          a set of nodes ids or names.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(target|evs)

        Raises
        ------
        pyAgrum.Exception
          If some evidene entered into the Bayes net are incompatible (their joint proba = 0)

        """
        return _pyAgrum.VariableElimination_evidenceJointImpact(self, targets, evs)

    def jointPosterior(self, targets: object) -> "pyAgrum.Potential":
        r"""

        Compute the joint posterior of a set of nodes.

        Parameters
        ----------
        list :
          the list of nodes whose posterior joint probability is wanted


        Warnings
        --------
        The order of the variables given by the list here or when the jointTarget is declared can not be assumed to be used bu the Potential.

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior joint probability of the set of nodes.

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.VariableElimination_jointPosterior(self, targets)

    def addJointTarget(self, targets: object) -> None:
        r"""

        Add a list of nodes as a new joint target. As a collateral effect, every node is added as a marginal target.

        Parameters
        ----------
        list
          a list of names of nodes

        Raises
        ------
        pyAgrum.UndefinedElement
          If some node(s) do not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_addJointTarget(self, targets)

    def eraseJointTarget(self, targets: object) -> None:
        r"""

        Remove, if existing, the joint target.

        Parameters
        ----------
        list
          a list of names or Ids of nodes

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.VariableElimination_eraseJointTarget(self, targets)

    def isJointTarget(self, targets: object) -> bool:
        r"""

        Parameters
        ----------
        list
          a list of nodes ids or names.

        Returns
        -------
        bool
          True if target is a joint target.

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.VariableElimination_isJointTarget(self, targets)

    def jointTargets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of target sets

        """
        return _pyAgrum.VariableElimination_jointTargets(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.VariableElimination_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.VariableElimination_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.VariableElimination_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.VariableElimination_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.VariableElimination_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.VariableElimination_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.VariableElimination_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.VariableElimination_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.VariableElimination_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.VariableElimination_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.VariableElimination_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.VariableElimination_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.VariableElimination_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.VariableElimination_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.VariableElimination_BN(self)

# Register VariableElimination in _pyAgrum:
_pyAgrum.VariableElimination_swigregister(VariableElimination)

class GibbsSampling(object):
    r"""

    Class for making Gibbs sampling inference in Bayesian networks.

    GibbsSampling(bn) -> GibbsSampling
        Parameters:
          * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.GibbsSampling_swiginit(self, _pyAgrum.new_GibbsSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_GibbsSampling

    def setBurnIn(self, b: int) -> None:
        r"""

        Parameters
        ----------
        b : int
          size of burn in on number of iteration

        """
        return _pyAgrum.GibbsSampling_setBurnIn(self, b)

    def burnIn(self) -> int:
        r"""

        Returns
        -------
        int
          size of burn in on number of iteration

        """
        return _pyAgrum.GibbsSampling_burnIn(self)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.GibbsSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.GibbsSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.GibbsSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.GibbsSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.GibbsSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.GibbsSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.GibbsSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.GibbsSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.GibbsSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.GibbsSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.GibbsSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.GibbsSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.GibbsSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.GibbsSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.GibbsSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.GibbsSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.GibbsSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.GibbsSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.GibbsSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.GibbsSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.GibbsSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.GibbsSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.GibbsSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.GibbsSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.GibbsSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.GibbsSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.GibbsSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.GibbsSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.GibbsSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.GibbsSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.GibbsSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.GibbsSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.GibbsSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.GibbsSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.GibbsSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.GibbsSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.GibbsSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.GibbsSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.GibbsSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.GibbsSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.GibbsSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.GibbsSampling_currentPosterior(self, *args)

    def nbrDrawnVar(self) -> int:
        r"""

        Returns
        -------
        int
          the number of variable drawn at each iteration

        """
        return _pyAgrum.GibbsSampling_nbrDrawnVar(self)

    def setNbrDrawnVar(self, _nbr: int) -> None:
        r"""

        Parameters
        ----------
        _nbr : int
          the number of variables to be drawn at each iteration

        """
        return _pyAgrum.GibbsSampling_setNbrDrawnVar(self, _nbr)

    def isDrawnAtRandom(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if variables are drawn at random

        """
        return _pyAgrum.GibbsSampling_isDrawnAtRandom(self)

    def setDrawnAtRandom(self, _atRandom: bool) -> None:
        r"""

        Parameters
        ----------
        _atRandom : bool
          indicates if variables should be drawn at random

        """
        return _pyAgrum.GibbsSampling_setDrawnAtRandom(self, _atRandom)

# Register GibbsSampling in _pyAgrum:
_pyAgrum.GibbsSampling_swigregister(GibbsSampling)

class ImportanceSampling(object):
    r"""

    Class used for inferences using the Importance Sampling algorithm.

    ImportanceSampling(bn) -> ImportanceSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.ImportanceSampling_swiginit(self, _pyAgrum.new_ImportanceSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_ImportanceSampling

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.ImportanceSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.ImportanceSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.ImportanceSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.ImportanceSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.ImportanceSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.ImportanceSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.ImportanceSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.ImportanceSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.ImportanceSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.ImportanceSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.ImportanceSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.ImportanceSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.ImportanceSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.ImportanceSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.ImportanceSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.ImportanceSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.ImportanceSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.ImportanceSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.ImportanceSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.ImportanceSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.ImportanceSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.ImportanceSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.ImportanceSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.ImportanceSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.ImportanceSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.ImportanceSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.ImportanceSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.ImportanceSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.ImportanceSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.ImportanceSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.ImportanceSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.ImportanceSampling_currentPosterior(self, *args)

# Register ImportanceSampling in _pyAgrum:
_pyAgrum.ImportanceSampling_swigregister(ImportanceSampling)

class WeightedSampling(object):
    r"""

    Class used for Weighted sampling inference algorithm.

    WeightedSampling(bn) -> WeightedSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.WeightedSampling_swiginit(self, _pyAgrum.new_WeightedSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_WeightedSampling

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.WeightedSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.WeightedSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.WeightedSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.WeightedSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.WeightedSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.WeightedSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.WeightedSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.WeightedSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.WeightedSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.WeightedSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.WeightedSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.WeightedSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.WeightedSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.WeightedSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.WeightedSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.WeightedSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.WeightedSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.WeightedSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.WeightedSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.WeightedSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.WeightedSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.WeightedSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.WeightedSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.WeightedSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.WeightedSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.WeightedSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.WeightedSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.WeightedSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.WeightedSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.WeightedSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.WeightedSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.WeightedSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.WeightedSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.WeightedSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.WeightedSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.WeightedSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.WeightedSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.WeightedSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.WeightedSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.WeightedSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.WeightedSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.WeightedSampling_currentPosterior(self, *args)

# Register WeightedSampling in _pyAgrum:
_pyAgrum.WeightedSampling_swigregister(WeightedSampling)

class MonteCarloSampling(object):
    r"""

    Class used for Monte Carlo sampling inference algorithm.

    MonteCarloSampling(bn) -> MonteCarloSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.MonteCarloSampling_swiginit(self, _pyAgrum.new_MonteCarloSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_MonteCarloSampling

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.MonteCarloSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.MonteCarloSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.MonteCarloSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.MonteCarloSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.MonteCarloSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.MonteCarloSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.MonteCarloSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.MonteCarloSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.MonteCarloSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.MonteCarloSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.MonteCarloSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.MonteCarloSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.MonteCarloSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.MonteCarloSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.MonteCarloSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.MonteCarloSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.MonteCarloSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.MonteCarloSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.MonteCarloSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.MonteCarloSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.MonteCarloSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.MonteCarloSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.MonteCarloSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.MonteCarloSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.MonteCarloSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.MonteCarloSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.MonteCarloSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.MonteCarloSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.MonteCarloSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.MonteCarloSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.MonteCarloSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.MonteCarloSampling_currentPosterior(self, *args)

# Register MonteCarloSampling in _pyAgrum:
_pyAgrum.MonteCarloSampling_swigregister(MonteCarloSampling)

class LoopyImportanceSampling(ImportanceSampling):
    r"""

    Class used for inferences using a loopy version of importance sampling.

    LoopyImportanceSampling(bn) -> LoopyImportanceSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.LoopyImportanceSampling_swiginit(self, _pyAgrum.new_LoopyImportanceSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_LoopyImportanceSampling

    def makeInference_(self) -> None:
        return _pyAgrum.LoopyImportanceSampling_makeInference_(self)

    def setVirtualLBPSize(self, vlbpsize: float) -> None:
        r"""

        Parameters
        ----------
        vlbpsize : float
          the size of the virtual LBP

        """
        return _pyAgrum.LoopyImportanceSampling_setVirtualLBPSize(self, vlbpsize)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.LoopyImportanceSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.LoopyImportanceSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.LoopyImportanceSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.LoopyImportanceSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.LoopyImportanceSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.LoopyImportanceSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.LoopyImportanceSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.LoopyImportanceSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.LoopyImportanceSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyImportanceSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.LoopyImportanceSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.LoopyImportanceSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.LoopyImportanceSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.LoopyImportanceSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.LoopyImportanceSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyImportanceSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.LoopyImportanceSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.LoopyImportanceSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.LoopyImportanceSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.LoopyImportanceSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.LoopyImportanceSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.LoopyImportanceSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyImportanceSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.LoopyImportanceSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.LoopyImportanceSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.LoopyImportanceSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.LoopyImportanceSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyImportanceSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.LoopyImportanceSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.LoopyImportanceSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.LoopyImportanceSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyImportanceSampling_currentPosterior(self, *args)

# Register LoopyImportanceSampling in _pyAgrum:
_pyAgrum.LoopyImportanceSampling_swigregister(LoopyImportanceSampling)

class LoopyWeightedSampling(WeightedSampling):
    r"""

    Class used for inferences using a loopy version of weighted sampling.

    LoopyWeightedSampling(bn) -> LoopyWeightedSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.LoopyWeightedSampling_swiginit(self, _pyAgrum.new_LoopyWeightedSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_LoopyWeightedSampling

    def makeInference_(self) -> None:
        return _pyAgrum.LoopyWeightedSampling_makeInference_(self)

    def setVirtualLBPSize(self, vlbpsize: float) -> None:
        r"""

        Parameters
        ----------
        vlbpsize : float
          the size of the virtual LBP

        """
        return _pyAgrum.LoopyWeightedSampling_setVirtualLBPSize(self, vlbpsize)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.LoopyWeightedSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.LoopyWeightedSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.LoopyWeightedSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.LoopyWeightedSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.LoopyWeightedSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.LoopyWeightedSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.LoopyWeightedSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.LoopyWeightedSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.LoopyWeightedSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyWeightedSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.LoopyWeightedSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.LoopyWeightedSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.LoopyWeightedSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.LoopyWeightedSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.LoopyWeightedSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyWeightedSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.LoopyWeightedSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.LoopyWeightedSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.LoopyWeightedSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.LoopyWeightedSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.LoopyWeightedSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.LoopyWeightedSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyWeightedSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.LoopyWeightedSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.LoopyWeightedSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.LoopyWeightedSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.LoopyWeightedSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyWeightedSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.LoopyWeightedSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.LoopyWeightedSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.LoopyWeightedSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyWeightedSampling_currentPosterior(self, *args)

# Register LoopyWeightedSampling in _pyAgrum:
_pyAgrum.LoopyWeightedSampling_swigregister(LoopyWeightedSampling)

class LoopyGibbsSampling(GibbsSampling):
    r"""

    Class used for inferences using a loopy version of Gibbs sampling.

    LoopyGibbsSampling(bn) -> LoopyGibbsSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.LoopyGibbsSampling_swiginit(self, _pyAgrum.new_LoopyGibbsSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_LoopyGibbsSampling

    def makeInference_(self) -> None:
        return _pyAgrum.LoopyGibbsSampling_makeInference_(self)

    def setVirtualLBPSize(self, vlbpsize: float) -> None:
        r"""

        Parameters
        ----------
        vlbpsize : float
          the size of the virtual LBP

        """
        return _pyAgrum.LoopyGibbsSampling_setVirtualLBPSize(self, vlbpsize)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.LoopyGibbsSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.LoopyGibbsSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.LoopyGibbsSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.LoopyGibbsSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.LoopyGibbsSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.LoopyGibbsSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.LoopyGibbsSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.LoopyGibbsSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.LoopyGibbsSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyGibbsSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.LoopyGibbsSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.LoopyGibbsSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.LoopyGibbsSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.LoopyGibbsSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.LoopyGibbsSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyGibbsSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.LoopyGibbsSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.LoopyGibbsSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.LoopyGibbsSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.LoopyGibbsSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.LoopyGibbsSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.LoopyGibbsSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyGibbsSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.LoopyGibbsSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.LoopyGibbsSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.LoopyGibbsSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.LoopyGibbsSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyGibbsSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.LoopyGibbsSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.LoopyGibbsSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.LoopyGibbsSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyGibbsSampling_currentPosterior(self, *args)

    def nbrDrawnVar(self) -> int:
        r"""

        Returns
        -------
        int
          the number of variable drawn at each iteration

        """
        return _pyAgrum.LoopyGibbsSampling_nbrDrawnVar(self)

    def setNbrDrawnVar(self, _nbr: int) -> None:
        r"""

        Parameters
        ----------
        _nbr : int
          the number of variables to be drawn at each iteration

        """
        return _pyAgrum.LoopyGibbsSampling_setNbrDrawnVar(self, _nbr)

    def isDrawnAtRandom(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if variables are drawn at random

        """
        return _pyAgrum.LoopyGibbsSampling_isDrawnAtRandom(self)

    def setDrawnAtRandom(self, _atRandom: bool) -> None:
        r"""

        Parameters
        ----------
        _atRandom : bool
          indicates if variables should be drawn at random

        """
        return _pyAgrum.LoopyGibbsSampling_setDrawnAtRandom(self, _atRandom)

    def burnIn(self) -> int:
        r"""

        Returns
        -------
        int
          size of burn in on number of iteration

        """
        return _pyAgrum.LoopyGibbsSampling_burnIn(self)

    def setBurnIn(self, b: int) -> None:
        r"""

        Parameters
        ----------
        b : int
          size of burn in on number of iteration

        """
        return _pyAgrum.LoopyGibbsSampling_setBurnIn(self, b)

# Register LoopyGibbsSampling in _pyAgrum:
_pyAgrum.LoopyGibbsSampling_swigregister(LoopyGibbsSampling)

class LoopyMonteCarloSampling(MonteCarloSampling):
    r"""

    Class used for inferences using a loopy version of Monte Carlo sampling.

    LoopyMonteCarloSampling(bn) -> LoopyMonteCarloSampling
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.LoopyMonteCarloSampling_swiginit(self, _pyAgrum.new_LoopyMonteCarloSampling(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_LoopyMonteCarloSampling

    def makeInference_(self) -> None:
        return _pyAgrum.LoopyMonteCarloSampling_makeInference_(self)

    def setVirtualLBPSize(self, vlbpsize: float) -> None:
        r"""

        Parameters
        ----------
        vlbpsize : float
          the size of the virtual LBP

        """
        return _pyAgrum.LoopyMonteCarloSampling_setVirtualLBPSize(self, vlbpsize)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.LoopyMonteCarloSampling_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.LoopyMonteCarloSampling_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.LoopyMonteCarloSampling_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.LoopyMonteCarloSampling_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.LoopyMonteCarloSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.LoopyMonteCarloSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.LoopyMonteCarloSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.LoopyMonteCarloSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.LoopyMonteCarloSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyMonteCarloSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.LoopyMonteCarloSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.LoopyMonteCarloSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.LoopyMonteCarloSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.LoopyMonteCarloSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.LoopyMonteCarloSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyMonteCarloSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.LoopyMonteCarloSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.LoopyMonteCarloSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.LoopyMonteCarloSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.LoopyMonteCarloSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.LoopyMonteCarloSampling__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.LoopyMonteCarloSampling_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyMonteCarloSampling_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.LoopyMonteCarloSampling_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.LoopyMonteCarloSampling_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.LoopyMonteCarloSampling_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.LoopyMonteCarloSampling_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyMonteCarloSampling_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.LoopyMonteCarloSampling_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.LoopyMonteCarloSampling_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.LoopyMonteCarloSampling_BN(self)

    def currentPosterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the current posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the current posterior probability of the node

        Raises
        ------
        UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyMonteCarloSampling_currentPosterior(self, *args)

# Register LoopyMonteCarloSampling in _pyAgrum:
_pyAgrum.LoopyMonteCarloSampling_swigregister(LoopyMonteCarloSampling)

class LoopyBeliefPropagation(object):
    r"""

    Class used for inferences using loopy belief propagation algorithm.

    LoopyBeliefPropagation(bn) -> LoopyBeliefPropagation
        Parameters:
            * **bn** (*pyAgrum.BayesNet*) -- a Bayesian network

    """

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

    def __init__(self, bn: "IBayesNet"):
        _pyAgrum.LoopyBeliefPropagation_swiginit(self, _pyAgrum.new_LoopyBeliefPropagation(bn))

        self._model=bn#BN



    __swig_destroy__ = _pyAgrum.delete_LoopyBeliefPropagation

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def setTargets(self, targets):
        """
        Remove all the targets and add the ones in parameter.

        Parameters
        ----------
        targets : set
          a set of targets

        Raises
        ------
        gum.UndefinedElement
            If one target is not in the Bayes net
        """
        if not isinstance(targets, set):
            raise TypeError("setTargets parameter must be a set, not %s"%(type(targets)))

        self.eraseAllTargets()
        for k in targets:
            self.addTarget(k)



    def hardEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with hard evidence

        """
        return _pyAgrum.LoopyBeliefPropagation_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        r"""

        Returns
        -------
        set
          the set of nodes with soft evidence

        """
        return _pyAgrum.LoopyBeliefPropagation_softEvidenceNodes(self)

    def targets(self) -> object:
        r"""

        Returns
        -------
        list
          the list of marginal targets

        """
        return _pyAgrum.LoopyBeliefPropagation_targets(self)

    def evidenceImpact(self, target: object, evs: object) -> "pyAgrum.Potential":
        r"""

        Create a pyAgrum.Potential for P(target|evs) (for all instanciation of target and evs)

        Parameters
        ----------
        target : set
          a set of targets ids or names.
        evs : set
          a set of nodes ids or names.

        Warnings
        --------
        if some evs are d-separated, they are not included in the Potential.

        Returns
        -------
        pyAgrum.Potential
          a Potential for P(targets|evs)

        """
        return _pyAgrum.LoopyBeliefPropagation_evidenceImpact(self, target, evs)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.LoopyBeliefPropagation_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.LoopyBeliefPropagation_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.LoopyBeliefPropagation_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.LoopyBeliefPropagation_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.LoopyBeliefPropagation_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyBeliefPropagation_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.LoopyBeliefPropagation_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.LoopyBeliefPropagation_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.LoopyBeliefPropagation_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.LoopyBeliefPropagation_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.LoopyBeliefPropagation_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.LoopyBeliefPropagation_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.LoopyBeliefPropagation_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.LoopyBeliefPropagation_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.LoopyBeliefPropagation_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.LoopyBeliefPropagation_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.LoopyBeliefPropagation__asIApproximationSchemeConfiguration(self)

    def makeInference(self) -> None:
        r"""

        Perform the heavy computations needed to compute the targets' posteriors

        In a Junction tree propagation scheme, for instance, the heavy computations are those of the messages sent in the JT.
        This is precisely what makeInference should compute. Later, the computations of the posteriors can be done 'lightly' by multiplying and projecting those messages.

        """
        return _pyAgrum.LoopyBeliefPropagation_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        r"""

        Computes and returns the posterior of a node.

        Parameters
        ----------
        var : int
          the node Id of the node for which we need a posterior probability
        nodeName : str
          the node name of the node for which we need a posterior probability

        Returns
        -------
        pyAgrum.Potential
          a const ref to the posterior probability of the node

        Raises
        ------
        pyAgrum.UndefinedElement
          If an element of nodes is not in targets

        """
        return _pyAgrum.LoopyBeliefPropagation_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        r"""

        Adds a new evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node already has an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        r"""

        Change the value of an already existing evidence on a node (might be soft or hard).

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name
        val :
          (int) a node value
        val :
          (str) the label of the node value
        vals : list
          a list of values

        Raises
        ------
        pyAgrum.InvalidArgument
          If the node does not already have an evidence
        pyAgrum.InvalidArgument
          If val is not a value for the node
        pyAgrum.InvalidArgument
          If the size of vals is different from the domain side of the node
        pyAgrum.FatalError
          If vals is a vector of 0s
        pyAgrum.UndefinedElement
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if some node(s) (or the one in parameters) have received evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the network.

        """
        return _pyAgrum.LoopyBeliefPropagation_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Remove the evidence, if any, corresponding to the node Id or name.

        Parameters
        ----------
        id : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a hard evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        r"""

        Parameters
        ----------
        id : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if node has received a soft evidence

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of hard evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        r"""

        Returns
        -------
        int
          the number of soft evidence entered into the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_nbrSoftEvidence(self)

    def eraseAllTargets(self) -> None:
        r"""

        Clear all previously defined targets (marginal and joint targets).

        As a result, no posterior can be computed (since we can only compute the posteriors of the marginal or joint targets that have been added by the user).

        """
        return _pyAgrum.LoopyBeliefPropagation_eraseAllTargets(self)

    def addAllTargets(self) -> None:
        r"""

        Add all the nodes as targets.

        """
        return _pyAgrum.LoopyBeliefPropagation_addAllTargets(self)

    def addTarget(self, *args) -> None:
        r"""

        Add a marginal target to the list of targets.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : str
          a node name

        Raises
        ------
        pyAgrum.UndefinedElement
          If target is not a NodeId in the Bayes net

        """
        return _pyAgrum.LoopyBeliefPropagation_addTarget(self, *args)

    def eraseTarget(self, *args) -> None:
        r"""

        Remove, if existing, the marginal target.

        Parameters
        ----------
        target : int
          a node Id
        nodeName : int
          a node name

        Raises
        ------
        pyAgrum.IndexError
          If one of the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_eraseTarget(self, *args)

    def isTarget(self, *args) -> bool:
        r"""

        Parameters
        ----------
        variable : int
         a node Id
        nodeName : str
          a node name

        Returns
        -------
        bool
          True if variable is a (marginal) target

        Raises
        ------
        pyAgrum.IndexError
          If the node does not belong to the Bayesian network
        pyAgrum.UndefinedElement
          If node Id is not in the Bayesian network

        """
        return _pyAgrum.LoopyBeliefPropagation_isTarget(self, *args)

    def nbrTargets(self) -> int:
        r"""

        Returns
        -------
        int
          the number of marginal targets

        """
        return _pyAgrum.LoopyBeliefPropagation_nbrTargets(self)

    def H(self, *args) -> float:
        r"""

        Parameters
        ----------
        X : int
          a node Id
        nodeName : str
          a node name

        Returns
        -------
        float
          the computed Shanon's entropy of a node given the observation

        """
        return _pyAgrum.LoopyBeliefPropagation_H(self, *args)

    def BN(self) -> "pyAgrum.IBayesNet":
        r"""

        Returns
        -------
        pyAgrum.IBayesNet
          A constant reference over the IBayesNet referenced by this class.

        Raises
        ------
        pyAgrum.UndefinedElement
          If no Bayes net has been assigned to the inference.

        """
        return _pyAgrum.LoopyBeliefPropagation_BN(self)

# Register LoopyBeliefPropagation in _pyAgrum:
_pyAgrum.LoopyBeliefPropagation_swigregister(LoopyBeliefPropagation)

class ExactBNdistance(object):
    r"""

    Class representing exacte computation of divergence and distance between BNs

    ExactBNdistance(P,Q) -> ExactBNdistance
        Parameters:
            * **P** (*pyAgrum.BayesNet*)
              a Bayesian network
            * **Q** (*pyAgrum.BayesNet*)
              another Bayesian network to compare with the first one

    ExactBNdistance(ebnd) -> ExactBNdistance
        Parameters:
            * **ebnd** (*pyAgrum.ExactBNdistance*)
              the exact BNdistance to copy

    Raises
    ------
    pyAgrum.OperationNotAllowed
    	If the 2BNs have not the same domain size of compatible node sets

    """

    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):
        _pyAgrum.ExactBNdistance_swiginit(self, _pyAgrum.new_ExactBNdistance(*args))
    __swig_destroy__ = _pyAgrum.delete_ExactBNdistance

    def compute(self) -> object:
        r"""

        Returns
        -------
        Dict[str,float]
        	a dictionnary containing the different values after the computation.

        """
        return _pyAgrum.ExactBNdistance_compute(self)

# Register ExactBNdistance in _pyAgrum:
_pyAgrum.ExactBNdistance_swigregister(ExactBNdistance)

class GibbsBNdistance(ApproximationScheme):
    r"""

    Class representing a Gibbs-Approximated computation of divergence and distance between BNs


    GibbsBNdistance(P,Q) -> GibbsBNdistance
        Parameters:
            * **P** (*pyAgrum.BayesNet*) -- a Bayesian network
            * **Q** (*pyAgrum.BayesNet*) -- another Bayesian network to compare with the first one

    GibbsBNdistance(gbnd) -> GibbsBNdistance
        Parameters:
            * **gbnd** (*pyAgrum.GibbsBNdistance*) -- the Gibbs BNdistance to copy

    Raises
    ------
    pyAgrum.OperationNotAllowed
    	If the 2BNs have not the same domain size of compatible node sets

    """

    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):
        _pyAgrum.GibbsBNdistance_swiginit(self, _pyAgrum.new_GibbsBNdistance(*args))
    __swig_destroy__ = _pyAgrum.delete_GibbsBNdistance

    def setBurnIn(self, b: int) -> None:
        r"""

        Parameters
        ----------
        b : int
        	size of burn in on number of iteration

        """
        return _pyAgrum.GibbsBNdistance_setBurnIn(self, b)

    def burnIn(self) -> int:
        r"""

        Returns
        -------
        int
        	size of burn in on number of iteration

        """
        return _pyAgrum.GibbsBNdistance_burnIn(self)

    def compute(self) -> object:
        r"""

        Returns
        -------
        Dict[str,float]
        	a dictionnary containing the different values after the computation.

        """
        return _pyAgrum.GibbsBNdistance_compute(self)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.GibbsBNdistance_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.GibbsBNdistance_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.GibbsBNdistance_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.GibbsBNdistance_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.GibbsBNdistance_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.GibbsBNdistance_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.GibbsBNdistance_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.GibbsBNdistance_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.GibbsBNdistance_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.GibbsBNdistance_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.GibbsBNdistance_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.GibbsBNdistance_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.GibbsBNdistance_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.GibbsBNdistance_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.GibbsBNdistance_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.GibbsBNdistance_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.GibbsBNdistance__asIApproximationSchemeConfiguration(self)

    def nbrDrawnVar(self) -> int:
        r"""

        Returns
        -------
        int
          the number of variable drawn at each iteration

        """
        return _pyAgrum.GibbsBNdistance_nbrDrawnVar(self)

    def setNbrDrawnVar(self, _nbr: int) -> None:
        r"""

        Parameters
        ----------
        _nbr : int
          the number of variables to be drawn at each iteration

        """
        return _pyAgrum.GibbsBNdistance_setNbrDrawnVar(self, _nbr)

    def isDrawnAtRandom(self) -> bool:
        r"""

        Returns
        -------
        bool
          True if variables are drawn at random

        """
        return _pyAgrum.GibbsBNdistance_isDrawnAtRandom(self)

    def setDrawnAtRandom(self, _atRandom: bool) -> None:
        r"""

        Parameters
        ----------
        _atRandom : bool
          indicates if variables should be drawn at random

        """
        return _pyAgrum.GibbsBNdistance_setDrawnAtRandom(self, _atRandom)

# Register GibbsBNdistance in _pyAgrum:
_pyAgrum.GibbsBNdistance_swigregister(GibbsBNdistance)

class CredalNet(object):
    r"""

    Constructor used to create a CredalNet (step by step or with two BayesNet)

    CredalNet() -> CredalNet
        default constructor

    CredalNet(src_min_num,src_max_den) -> CredalNet

    Parameters
    ----------
    src_min_num : str or pyAgrum.BayesNet
                The path to a BayesNet or the BN itself which contains lower probabilities.
    src_max_den : str or pyAgrum.BayesNet
                The (optional) path to a BayesNet or the BN itself which contains upper probabilities.


    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    NodeType_Precise = _pyAgrum.CredalNet_NodeType_Precise
    NodeType_Credal = _pyAgrum.CredalNet_NodeType_Credal
    NodeType_Vacuous = _pyAgrum.CredalNet_NodeType_Vacuous
    NodeType_Indic = _pyAgrum.CredalNet_NodeType_Indic

    def __init__(self, *args):
        _pyAgrum.CredalNet_swiginit(self, _pyAgrum.new_CredalNet(*args))
    __swig_destroy__ = _pyAgrum.delete_CredalNet

    def addVariable(self, name: str, card: int) -> int:
        r"""

        Parameters
        ----------
        name : str
        	the name of the new variable
        card: int
            the domainSize of the new variable

        Returns
        -------
        int
        	the id of the new node

        """
        return _pyAgrum.CredalNet_addVariable(self, name, card)

    def addArc(self, tail: int, head: int) -> None:
        r"""

        Adds an arc between two nodes

        Parameters
        ----------
        tail :
        	the id of the tail node
        head : int 
        	the id of the head node

        Raises
        ------
        pyAgrum.InvalidDirectedCircle
        	If any (directed) cycle is created by this arc
        pyAgrum.InvalidNode
        	If head or tail does not belong to the graph nodes
        pyAgrum.DuplicateElement
        	If one of the arc already exists

        """
        return _pyAgrum.CredalNet_addArc(self, tail, head)

    def setCPTs(self, id: int, cpt: "pyAgrum.YetUnWrapped") -> None:
        r"""

        Warnings
        --------
        (experimental function) - Parameters to be wrapped


        Set the vertices of the credal sets (all of the conditionals) of a given node

        Parameters
        ----------
        id : int
        	the NodeId of the node
        cpt	: tbw 
        	the vertices of every credal set (for each instantiation of the parents)

        Warning
        -------
        DOES not change the BayesNet (s) associated to this credal net !

        """
        return _pyAgrum.CredalNet_setCPTs(self, id, cpt)

    def setCPT(self, *args) -> None:
        r"""

        Warnings
        --------
        (experimental function) - Parameters to be wrapped


        Set the vertices of one credal set of a given node (any instantiation index)

        Parameters
        ----------
        id : int
        	the Id of the node
        entry : int
        	the index of the instantiation (from 0 to K - 1) excluding the given node (only the parents are used to compute the index of the credal set)
        ins : pyAgrum.Instantiation
        	the Instantiation (only the parents matter to find the credal set index) 
        cpt	: tbw
        	the vertices of every credal set (for each instantiation of the parents)

        Warnings
        --------
        DOES not change the BayesNet(s) associated to this credal net !

        """
        return _pyAgrum.CredalNet_setCPT(self, *args)

    def fillConstraints(self, id: int, lower: "Vector", upper: "Vector") -> None:
        r"""

        Set the interval constraints of the credal sets of a given node (all instantiations) 

        Parameters
        ----------
        id : int 
        	The id of the node
        lower : list
        	The lower value for each probability in correct order
        upper : list
        	The upper value for each probability in correct order

        Warnings
        --------
        You need to call intervalToCredal when done filling all constraints.

        Warning
        -------
        DOES change the BayesNet (s) associated to this credal net !

        """
        return _pyAgrum.CredalNet_fillConstraints(self, id, lower, upper)

    def fillConstraint(self, *args) -> None:
        r"""

        Set the interval constraints of a credal set of a given node (from an instantiation index)

        Parameters
        ----------
        id : int 
        	The id of the node
        entry : int
        	The index of the instantiation excluding the given node (only the parents are used to compute the index of the credal set)
        ins : pyAgrum.Instantiation
        	The Instantiation
        lower : list
        	The lower value for each probability in correct order
        upper : list
        	The upper value for each probability in correct order

        Warnings
        --------
        You need to call intervalToCredal when done filling all constraints.

        Warning
        -------
        DOES change the BayesNet (s) associated to this credal net ! 

        """
        return _pyAgrum.CredalNet_fillConstraint(self, *args)

    def instantiation(self, id: int) -> "pyAgrum.Instantiation":
        r"""

        Get an Instantiation from a node id, usefull to fill the constraints of the network.

        bnet accessors / shortcuts.

        Parameters
        ----------
        id : int
        	the id of the node we want an instantiation from

        Returns
        -------
        pyAgrum.Instantiation
            the instantiation 

        """
        return _pyAgrum.CredalNet_instantiation(self, id)

    def domainSize(self, id: int) -> int:
        r"""

        Parameters
        ----------
        id : int
        	The id of the node

        Returns
        -------
        int
            The cardinality of the node 

        """
        return _pyAgrum.CredalNet_domainSize(self, id)

    def bnToCredal(self, beta: float, oneNet: bool, keepZeroes: bool=False) -> None:
        r"""

        Perturbates the BayesNet provided as input for this CredalNet by generating intervals instead of point probabilities and then computes each vertex of each credal set.

        Parameters
        ----------
        beta : float
        	The beta used to perturbate the network
        oneNet : bool
        	used as a flag. Set to True if one BayesNet if provided with counts, to False if two BayesNet are provided; one with probabilities (the lower net) and one with denominators over the first modalities (the upper net)
        keepZeroes : bool
        	used as a flag as whether or not - respectively True or False - we keep zeroes as zeroes. Default is False, i.e. zeroes are not kept

        """
        return _pyAgrum.CredalNet_bnToCredal(self, beta, oneNet, keepZeroes)

    def intervalToCredalWithFiles(self) -> None:
        r"""

        Warnings
        --------
        Deprecated : use intervalToCredal (lrsWrapper with no input / output files needed).


        Computes the vertices of each credal set according to their interval definition (uses lrs).

        Use this method when using a single BayesNet storing counts of events. 

        """
        return _pyAgrum.CredalNet_intervalToCredalWithFiles(self)

    def intervalToCredal(self) -> None:
        r"""

        Computes the vertices of each credal set according to their interval definition (uses lrs).

        Use this method when using two BayesNet, one with lower probabilities and one with upper probabilities.

        """
        return _pyAgrum.CredalNet_intervalToCredal(self)

    def lagrangeNormalization(self) -> None:
        r"""

        Normalize counts of a BayesNet storing counts of each events such that no probability is 0.

        Use this method when using a single BayesNet storing counts of events. Lagrange normalization. This call is irreversible and modify counts stored by __src_bn.

        Doest not performs computations of the parameters but keeps normalized counts of events only. Call idmLearning to compute the probabilities (with any parameter value). 

        """
        return _pyAgrum.CredalNet_lagrangeNormalization(self)

    def idmLearning(self, s: int=0, keepZeroes: bool=False) -> None:
        r"""

        Learns parameters from a BayesNet storing counts of events.

        Use this method when using a single BayesNet storing counts of events. IDM model if s > 0, standard point probability if s = 0 (default value if none precised).

        Parameters
        ----------
        s : int
        	the IDM parameter.
        keepZeroes : bool
        	used as a flag as whether or not - respectively True or False - we keep zeroes as zeroes. Default is False, i.e. zeroes are not kept. 

        """
        return _pyAgrum.CredalNet_idmLearning(self, s, keepZeroes)

    def approximatedBinarization(self) -> None:
        r"""

        Approximate binarization.

        Each bit has a lower and upper probability which is the lowest - resp. highest - over all vertices of the credal set. Enlarge the orignal credal sets and may induce huge imprecision.

        Warnings
        --------
        Enlarge the orignal credal sets and therefor induce huge imprecision by propagation. Not recommended, use MCSampling or something else instead

        """
        return _pyAgrum.CredalNet_approximatedBinarization(self)

    def saveBNsMinMax(self, min_path: str, max_path: str) -> None:
        r"""

        If this CredalNet was built over a perturbed BayesNet, one can save the intervals as two BayesNet.

        to call after bnToCredal(GUM_SCALAR beta) save a BN with lower probabilities and a BN with upper ones

        Parameters
        ----------
        min_path : str
        	the path to save the BayesNet which contains the lower probabilities of each node X.
        max_path : str
        	the path to save the BayesNet which contains the upper probabilities of each node X.

        """
        return _pyAgrum.CredalNet_saveBNsMinMax(self, min_path, max_path)

    def computeBinaryCPTMinMax(self) -> None:
        return _pyAgrum.CredalNet_computeBinaryCPTMinMax(self)

    def src_bn(self) -> "pyAgrum.BayesNet":
        r"""

        Returns
        -------
        pyAgrum.BayesNet
            Returns a constant reference to the original BayesNet (used as a DAG, it's CPTs does not matter). 

        """
        return _pyAgrum.CredalNet_src_bn(self)

    def current_bn(self) -> "pyAgrum.BayesNet":
        r"""

        Returns
        -------
        pyAgrum.BayesNet
            Returs a constant reference to the actual BayesNet (used as a DAG, it's CPTs does not matter). 

        """
        return _pyAgrum.CredalNet_current_bn(self)

    def credalNet_currentCpt(self) -> "pyAgrum.YetUnWrapped":
        r"""

        Warnings
        --------
        Experimental function - Return type to be wrapped

        Returns
        -------
        tbw
            a constant reference to the (up-to-date) CredalNet CPTs.

        """
        return _pyAgrum.CredalNet_credalNet_currentCpt(self)

    def credalNet_srcCpt(self) -> "pyAgrum.YetUnWrapped":
        r"""

        Warnings
        --------
        Experimental function - Return type to be wrapped

        Returns
        -------
        tbw
            a constant reference to the (up-to-date) CredalNet CPTs.

        """
        return _pyAgrum.CredalNet_credalNet_srcCpt(self)

    def currentNodeType(self, id: int) -> int:
        r"""

        Parameters
        ----------
        id : int 
        	The constant reference to the choosen NodeId

        Returns
        -------
        pyAgrum.CredalNet
            the type of the choosen node in the (up-to-date) CredalNet __current_bn if any, __src_bn otherwise. 

        """
        return _pyAgrum.CredalNet_currentNodeType(self, id)

    def nodeType(self, id: int) -> int:
        r"""

        Parameters
        ----------
        id : int
        	the constant reference to the choosen NodeId

        Returns
        -------
        pyAgrum.CredalNet
        	the type of the choosen node in the (up-to-date) CredalNet in __src_bn. 

        """
        return _pyAgrum.CredalNet_nodeType(self, id)

    def epsilonMin(self) -> float:
        r"""

        Returns
        -------
        float
            a constant reference to the lowest perturbation of the BayesNet provided as input for this CredalNet. 

        """
        return _pyAgrum.CredalNet_epsilonMin(self)

    def epsilonMax(self) -> float:
        r"""

        Returns
        -------
        float
            a constant reference to the highest perturbation of the BayesNet provided as input for this CredalNet. 

        """
        return _pyAgrum.CredalNet_epsilonMax(self)

    def epsilonMean(self) -> float:
        r"""

        Returns
        -------
        float
            a constant reference to the average perturbation of the BayesNet provided as input for this CredalNet. 

        """
        return _pyAgrum.CredalNet_epsilonMean(self)

    def isSeparatelySpecified(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if this CredalNet is separately and interval specified, False otherwise. 

        """
        return _pyAgrum.CredalNet_isSeparatelySpecified(self)

    def hasComputedBinaryCPTMinMax(self) -> bool:
        return _pyAgrum.CredalNet_hasComputedBinaryCPTMinMax(self)

    def get_binaryCPT_min(self) -> "pyAgrum.YetUnWrapped":
        r"""

        Warnings
        --------
        Experimental function - Return type to be wrapped

        Returns
        -------
        tbw
        	a constant reference to the lower probabilities of each node X over the 'True' modality

        """
        return _pyAgrum.CredalNet_get_binaryCPT_min(self)

    def get_binaryCPT_max(self) -> "pyAgrum.YetUnWrapped":
        r"""

        Warnings
        --------
        Experimental function - Return type to be wrapped

        Returns
        -------
        tbw
        	a constant reference to the upper probabilities of each node X over the 'True' modality

        """
        return _pyAgrum.CredalNet_get_binaryCPT_max(self)

    def __repr__(self) -> str:
        return _pyAgrum.CredalNet___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.CredalNet___str__(self)

# Register CredalNet in _pyAgrum:
_pyAgrum.CredalNet_swigregister(CredalNet)

class CNMonteCarloSampling(object):
    r"""

    Class used for inferences in credal networks with Monte Carlo sampling algorithm.

    CNMonteCarloSampling(cn) -> CNMonteCarloSampling
        Parameters:
            * **cn** (*pyAgrum.CredalNet*) -- a credal network

    """

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

    def __init__(self, credalNet: "CredalNet"):
        _pyAgrum.CNMonteCarloSampling_swiginit(self, _pyAgrum.new_CNMonteCarloSampling(credalNet))

        self._model=credalNet



    __swig_destroy__ = _pyAgrum.delete_CNMonteCarloSampling

    def makeInference(self) -> None:
        r"""

        Starts the inference.

        """
        return _pyAgrum.CNMonteCarloSampling_makeInference(self)

    def insertEvidenceFile(self, path: str) -> None:
        r"""

        Insert evidence from file.

        Parameters
        ----------
        path : str
        	the path to the evidence file. 

        """
        return _pyAgrum.CNMonteCarloSampling_insertEvidenceFile(self, path)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.CNMonteCarloSampling_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.CNMonteCarloSampling_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.CNMonteCarloSampling_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.CNMonteCarloSampling_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.CNMonteCarloSampling_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.CNMonteCarloSampling_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.CNMonteCarloSampling_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.CNMonteCarloSampling_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.CNMonteCarloSampling_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.CNMonteCarloSampling_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.CNMonteCarloSampling_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.CNMonteCarloSampling_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.CNMonteCarloSampling_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.CNMonteCarloSampling_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.CNMonteCarloSampling_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.CNMonteCarloSampling_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.CNMonteCarloSampling__asIApproximationSchemeConfiguration(self)

    def setRepetitiveInd(self, flag: bool) -> None:
        r"""

        Parameters
        ----------
        flag : bool
        	True if repetitive independence is to be used, false otherwise. Only usefull with dynamic networks. 

        """
        return _pyAgrum.CNMonteCarloSampling_setRepetitiveInd(self, flag)

    def marginalMax(self, *args) -> "pyAgrum.Potential":
        r"""

        Get the upper marginals of a given node id.

        Parameters
        ----------
        id : int
        	the node id which upper marginals we want.
        varName : str
        	the variable name which upper marginals we want. 

        Returns
        -------
        list
            a constant reference to this node upper marginals.

        Raises
        ------
        pyAgrum.IndexError
        	If the node does not belong to the Credal network

        """
        return _pyAgrum.CNMonteCarloSampling_marginalMax(self, *args)

    def marginalMin(self, *args) -> "pyAgrum.Potential":
        r"""

        Get the lower marginals of a given node id.

        Parameters
        ----------
        id : int
        	the node id which lower marginals we want.
        varName : str
        	the variable name which lower marginals we want. 

        Returns
        -------
        list
            a constant reference to this node lower marginals.

        Raises
        ------
        pyAgrum.IndexError
        	If the node does not belong to the Credal network

        """
        return _pyAgrum.CNMonteCarloSampling_marginalMin(self, *args)

    def insertModalsFile(self, path: str) -> None:
        r"""

        Insert variables modalities from file to compute expectations.

        Parameters
        ----------
        path : str
        	The path to the modalities file. 

        """
        return _pyAgrum.CNMonteCarloSampling_insertModalsFile(self, path)

    def dynamicExpMax(self, varName: str) -> List[float]:
        r"""

        Get the upper dynamic expectation of a given variable prefix.

        Parameters
        ----------
        varName : str
        	the variable name prefix which upper expectation we want.

        Returns
        -------
        float
            a constant reference to the variable upper expectation over all time steps. 

        """
        return _pyAgrum.CNMonteCarloSampling_dynamicExpMax(self, varName)

    def dynamicExpMin(self, varName: str) -> List[float]:
        r"""

        Get the lower dynamic expectation of a given variable prefix.

        Parameters
        ----------
        varName : str
        	the variable name prefix which lower expectation we want.

        Returns
        -------
        float
            a constant reference to the variable lower expectation over all time steps. 

        """
        return _pyAgrum.CNMonteCarloSampling_dynamicExpMin(self, varName)

    def CN(self) -> "pyAgrum.CredalNet":
        return _pyAgrum.CNMonteCarloSampling_CN(self)

# Register CNMonteCarloSampling in _pyAgrum:
_pyAgrum.CNMonteCarloSampling_swigregister(CNMonteCarloSampling)

class CNLoopyPropagation(object):
    r"""

    Class used for inferences in credal networks with Loopy Propagation algorithm.

    CNLoopyPropagation(cn) -> CNLoopyPropagation
        Parameters:
          * **cn** (*pyAgrum.CredalNet*) -- a Credal network

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    InferenceType_nodeToNeighbours = _pyAgrum.CNLoopyPropagation_InferenceType_nodeToNeighbours
    InferenceType_ordered = _pyAgrum.CNLoopyPropagation_InferenceType_ordered
    InferenceType_randomOrder = _pyAgrum.CNLoopyPropagation_InferenceType_randomOrder

    def makeInference(self) -> None:
        r"""

        Starts the inference.

        """
        return _pyAgrum.CNLoopyPropagation_makeInference(self)

    def inferenceType(self, *args) -> int:
        r"""

        Returns
        -------
        int
        	the inference type

        """
        return _pyAgrum.CNLoopyPropagation_inferenceType(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Erase all inference related data to perform another one.

        You need to insert evidence again if needed but modalities are kept. You can insert new ones by using the appropriate method which will delete the old ones.

        """
        return _pyAgrum.CNLoopyPropagation_eraseAllEvidence(self)

    def saveInference(self, path: str) -> None:
        r"""

        Saves marginals.

        Parameters
        ----------
        path : str
        	The path to the file to save marginals. 

        """
        return _pyAgrum.CNLoopyPropagation_saveInference(self, path)

    def __init__(self, cnet: "CredalNet"):
        _pyAgrum.CNLoopyPropagation_swiginit(self, _pyAgrum.new_CNLoopyPropagation(cnet))

        self._model=cnet



    __swig_destroy__ = _pyAgrum.delete_CNLoopyPropagation

    def insertEvidenceFile(self, path: str) -> None:
        r"""

        Insert evidence from file.

        Parameters
        ----------
        path : str
        	the path to the evidence file. 

        """
        return _pyAgrum.CNLoopyPropagation_insertEvidenceFile(self, path)

    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.CNLoopyPropagation_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.CNLoopyPropagation_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.CNLoopyPropagation_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.CNLoopyPropagation_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.CNLoopyPropagation_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.CNLoopyPropagation_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.CNLoopyPropagation_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.CNLoopyPropagation_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.CNLoopyPropagation_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.CNLoopyPropagation_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.CNLoopyPropagation_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.CNLoopyPropagation_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.CNLoopyPropagation_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.CNLoopyPropagation_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.CNLoopyPropagation_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.CNLoopyPropagation_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.CNLoopyPropagation__asIApproximationSchemeConfiguration(self)

    def setRepetitiveInd(self, flag: bool) -> None:
        r"""

        Parameters
        ----------
        flag : bool
        	True if repetitive independence is to be used, false otherwise. Only usefull with dynamic networks. 

        """
        return _pyAgrum.CNLoopyPropagation_setRepetitiveInd(self, flag)

    def marginalMax(self, *args) -> "pyAgrum.Potential":
        r"""

        Get the upper marginals of a given node id.

        Parameters
        ----------
        id : int
        	the node id which upper marginals we want.
        varName : str
        	the variable name which upper marginals we want. 

        Returns
        -------
        list
            a constant reference to this node upper marginals.

        Raises
        ------
        pyAgrum.IndexError
        	If the node does not belong to the Credal network

        """
        return _pyAgrum.CNLoopyPropagation_marginalMax(self, *args)

    def marginalMin(self, *args) -> "pyAgrum.Potential":
        r"""

        Get the lower marginals of a given node id.

        Parameters
        ----------
        id : int
        	the node id which lower marginals we want.
        varName : str
        	the variable name which lower marginals we want. 

        Returns
        -------
        list
            a constant reference to this node lower marginals.

        Raises
        ------
        pyAgrum.IndexError
        	If the node does not belong to the Credal network

        """
        return _pyAgrum.CNLoopyPropagation_marginalMin(self, *args)

    def insertModalsFile(self, path: str) -> None:
        r"""

        Insert variables modalities from file to compute expectations.

        Parameters
        ----------
        path : str
        	The path to the modalities file. 

        """
        return _pyAgrum.CNLoopyPropagation_insertModalsFile(self, path)

    def dynamicExpMax(self, varName: str) -> List[float]:
        r"""

        Get the upper dynamic expectation of a given variable prefix.

        Parameters
        ----------
        varName : str
        	the variable name prefix which upper expectation we want.

        Returns
        -------
        float
            a constant reference to the variable upper expectation over all time steps. 

        """
        return _pyAgrum.CNLoopyPropagation_dynamicExpMax(self, varName)

    def dynamicExpMin(self, varName: str) -> List[float]:
        r"""

        Get the lower dynamic expectation of a given variable prefix.

        Parameters
        ----------
        varName : str
        	the variable name prefix which lower expectation we want.

        Returns
        -------
        float
            a constant reference to the variable lower expectation over all time steps. 

        """
        return _pyAgrum.CNLoopyPropagation_dynamicExpMin(self, varName)

    def CN(self) -> "pyAgrum.CredalNet":
        return _pyAgrum.CNLoopyPropagation_CN(self)

# Register CNLoopyPropagation in _pyAgrum:
_pyAgrum.CNLoopyPropagation_swigregister(CNLoopyPropagation)

class InfluenceDiagram(DAGmodel):
    r"""

    InfluenceDiagram represents an Influence Diagram.

    InfluenceDiagram() -> InfluenceDiagram
        default constructor

    InfluenceDiagram(source) -> InfluenceDiagram
        Parameters:
            * **source** (*pyAgrum.InfluenceDiagram*) -- the InfluenceDiagram to copy

    """

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

    @staticmethod
    def fastPrototype(dotlike: str, domainSize: int=2) -> "pyAgrum.InfluenceDiagram":
        r"""

        Create an Influence Diagram with a dot-like syntax which specifies:
            - the structure 'a->b<-c;b->d;c<-e;'.
            - a prefix for the type of node (chance/decision/utiliy nodes):

              - `a` : a chance node named 'a' (by default)
              - `$a` : a utility node named 'a'
              - `*a` : a decision node named 'a'

            - the type of the variables with different syntax as postfix:

              - by default, a variable is a pyAgrum.RangeVariable using the default domain size (second argument)
              - with `'a[10]'`, the variable is a pyAgrum.RangeVariable using 10 as domain size (from 0 to 9)
              - with `'a[3,7]'`, the variable is a pyAgrum.RangeVariable using a domainSize from 3 to 7
              - with `'a[1,3.14,5,6.2]'`, the variable is a pyAgrum.DiscretizedVariable using the given ticks (at least 3 values)
              - with `'a{top|middle|bottom}'`, the variable is a pyAgrum.LabelizedVariable using the given labels.
              - with 'a{-1|5|0|3}', the variable is a pyAgrum.IntegerVariable using the sorted given values.

        Note 
        ----
          - If the dot-like string contains such a specification more than once for a variable, the first specification will be used.
          - the potentials (probabilities, utilities) are randomly generated.
          - see also pyAgrum.fastID.

        Examples
        --------
        >>> import pyAgrum as gum
        >>> bn=pyAgrum.fastID('A->B[1,3]<-*C{yes|No}->$D<-E[1,2.5,3.9]',6)

        Parameters
        ----------
        dotlike : str
                the string containing the specification
        domainSize : int
                the default domain size for variables

        Returns
        -------
        pyAgrum.InfluenceDiagram
                the resulting Influence Diagram

        """
        return _pyAgrum.InfluenceDiagram_fastPrototype(dotlike, domainSize)
    __swig_destroy__ = _pyAgrum.delete_InfluenceDiagram

    def __init__(self, *args):
        _pyAgrum.InfluenceDiagram_swiginit(self, _pyAgrum.new_InfluenceDiagram(*args))

    def toDot(self) -> str:
        r"""

        Returns
        -------
        str
            a friendly display of the graph in DOT format

        """
        return _pyAgrum.InfluenceDiagram_toDot(self)

    def clear(self) -> None:
        return _pyAgrum.InfluenceDiagram_clear(self)

    def cpt(self, *args) -> "pyAgrum.Potential":
        r"""

        Returns the CPT of a variable.

        Parameters
        ----------
        VarId : int
        	A variable's id in the pyAgrum.BayesNet.

        Returns
        -------
        pyAgrum.Potential
        	The variable's CPT. 

        Raises
        ------
        pyAgrum.NotFound
        	If no variable's id matches varId. 

        """
        return _pyAgrum.InfluenceDiagram_cpt(self, *args)

    def utility(self, *args) -> "pyAgrum.Potential":
        r"""

        Parameters
        ----------
        varId : int 
        	the tested node id.

        Returns
        -------
        pyAgrum.Potential
        	the utility table of the node

        Raises
        ------
        pyAgrum.IndexError
        	If the InfluenceDiagram does not contain the variable

        """
        return _pyAgrum.InfluenceDiagram_utility(self, *args)

    def isUtilityNode(self, *args) -> bool:
        r"""

        Parameters
        ----------
        varId : int 
        	the tested node id.

        Returns
        -------
        bool
        	true if node is an utility node

        """
        return _pyAgrum.InfluenceDiagram_isUtilityNode(self, *args)

    def isDecisionNode(self, *args) -> bool:
        r"""

        Parameters
        ----------
        varId : int 
        	the tested node id.

        Returns
        -------
        bool
        	true if node is a decision node

        """
        return _pyAgrum.InfluenceDiagram_isDecisionNode(self, *args)

    def isChanceNode(self, *args) -> bool:
        r"""

        Parameters
        ----------
        varId : int 
        	the tested node id.

        Returns
        -------
        bool
        	true if node is a chance node

        """
        return _pyAgrum.InfluenceDiagram_isChanceNode(self, *args)

    def utilityNodeSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of utility nodes

        """
        return _pyAgrum.InfluenceDiagram_utilityNodeSize(self)

    def chanceNodeSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of chance nodes. 

        """
        return _pyAgrum.InfluenceDiagram_chanceNodeSize(self)

    def decisionNodeSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of decision nodes

        """
        return _pyAgrum.InfluenceDiagram_decisionNodeSize(self)

    def variable(self, *args) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        id : int
         	the node id

        Returns
        ------
        pyAgrum.DiscreteVariable
        	a constant reference over a variabe given it's node id

        Raises
        ------
        pyAgrum.NotFound
        	If no variable's id matches the parameter 

        """
        return _pyAgrum.InfluenceDiagram_variable(self, *args)

    def nodeId(self, var: "pyAgrum.DiscreteVariable") -> int:
        r"""

        Parameters
        ----------
        var : pyAgrum.DiscreteVariable
        	a variable

        Returns
        -------
        int
        	the id of the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the InfluenceDiagram does not contain the variable

        """
        return _pyAgrum.InfluenceDiagram_nodeId(self, var)

    def idFromName(self, name: str) -> int:
        r"""

        Returns a variable's id given its name.

        Parameters
        ----------
        name : str
        	the variable's name from which the id is returned.

        Returns
        -------
        int
        	the variable's node id. 

        Raises
        ------
        pyAgrum.NotFound
        	If no such name exists in the graph. 

        """
        return _pyAgrum.InfluenceDiagram_idFromName(self, name)

    def variableFromName(self, name: str) -> "pyAgrum.DiscreteVariable":
        r"""

        Parameters
        ----------
        name : str
        	a variable's name

        Returns
        -------
        pyAgrum.DiscreteVariable
        	the variable

        Raises
        ------
        pyAgrum.IndexError
        	If the InfluenceDiagram does not contain the variable

        """
        return _pyAgrum.InfluenceDiagram_variableFromName(self, name)

    def add(self, variable: "pyAgrum.DiscreteVariable", id: int=0) -> int:
        r"""

        Add a chance variable, it's associate node and it's CPT.

        The id of the new variable is automatically generated.

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	The variable added by copy.
        id : int
        	The chosen id. If 0, the NodeGraphPart will choose.

        Warnings
        --------
        give an id (not 0) should be reserved for rare and specific situations !!! 

        Returns
        -------
        int
            the id of the added variable. 

        Raises
        ------
        pyAgrum.DuplicateElement
        	If id(<>0) is already used 

        """
        return _pyAgrum.InfluenceDiagram_add(self, variable, id)

    def addDecisionNode(self, variable: "pyAgrum.DiscreteVariable", id: int=0) -> int:
        r"""

        Add a decision variable.

        The id of the new variable is automatically generated.

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable added by copy.
        id : int
        	the chosen id. If 0, the NodeGraphPart will choose.

        Warnings
        --------
        give an id (not 0) should be reserved for rare and specific situations !!! 

        Returns
        -------
        int
            the id of the added variable. 

        Raises
        ------
        pyAgrum.DuplicateElement
        	If id(<>0) is already used 

        """
        return _pyAgrum.InfluenceDiagram_addDecisionNode(self, variable, id)

    def addChanceNode(self, *args) -> int:
        r"""

        Add a chance variable, it's associate node and it's CPT.

        The id of the new variable is automatically generated.

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable added by copy.
        id : int
        	the chosen id. If 0, the NodeGraphPart will choose.

        Warnings
        --------
        give an id (not 0) should be reserved for rare and specific situations !!! 

        Returns
        -------
        int
            the id of the added variable. 

        Raises
        ------
        pyAgrum.DuplicateElement
        	If id(<>0) is already used 

        """
        return _pyAgrum.InfluenceDiagram_addChanceNode(self, *args)

    def addUtilityNode(self, *args) -> int:
        r"""

        Add a utility variable, it's associate node and it's UT. 

        The id of the new variable is automatically generated.

        Parameters
        ----------
        variable : pyAgrum.DiscreteVariable
        	the variable added by copy
        id : int
        	the chosen id. If 0, the NodeGraphPart will choose

        Warnings
        --------
        give an id (not 0) should be reserved for rare and specific situations !!! 

        Returns
        -------
        int
            the id of the added variable. 

        Raises
        ------
        pyAgrum.InvalidArgument
        	If variable has more than one label
        pyAgrum.DuplicateElement
        	If id(<>0) is already used 

        """
        return _pyAgrum.InfluenceDiagram_addUtilityNode(self, *args)

    def erase(self, *args) -> None:
        r"""

        Erase a Variable from the network and remove the variable from all his childs.

        If no variable matches the id, then nothing is done.

        Parameters
        ----------
        id : int
        	The id of the variable to erase.
        var : pyAgrum.DiscreteVariable
        	The reference on the variable to remove. 

        """
        return _pyAgrum.InfluenceDiagram_erase(self, *args)

    def changeVariableName(self, *args) -> None:
        r"""

        Parameters
        ----------
        id : int
        	the node Id
        new_name : str
        	the name of the variable 

        Raises
        ------
        pyAgrum.DuplicateLabel
        	If this name already exists
        pyAgrum.NotFound
        	If no nodes matches id. 

        """
        return _pyAgrum.InfluenceDiagram_changeVariableName(self, *args)

    def addArc(self, *args) -> None:
        r"""

        Add an arc in the ID, and update diagram's potential nodes cpt if necessary.

        Parameters
        ----------
        tail : int
          the id of the tail node
        head : int
          the id of the head node

        Raises
        ------
        pyAgrum.InvalidEdge
        	If arc.tail and/or arc.head are not in the ID.
        pyAgrum.InvalidEdge
        	If tail is a utility node 

        """
        return _pyAgrum.InfluenceDiagram_addArc(self, *args)

    def eraseArc(self, *args) -> None:
        r"""

        Removes an arc in the ID, and update diagram's potential nodes cpt if necessary.

        If (tail, head) doesn't exist, the nothing happens.

        Parameters
        ----------
        arc : pyAgrum.Arc
        	The arc to be removed.
        tail : int
          the id of the tail node
        head : int
          the id of the head node

        """
        return _pyAgrum.InfluenceDiagram_eraseArc(self, *args)

    def decisionOrderExists(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if a directed path exist with all decision node

        """
        return _pyAgrum.InfluenceDiagram_decisionOrderExists(self)

    def getDecisionGraph(self) -> "pyAgrum.DAG":
        r"""

        Returns
        -------
        pyAgrum.DAG
        	the temporal Graph. 

        """
        return _pyAgrum.InfluenceDiagram_getDecisionGraph(self)

    def decisionOrder(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.InfluenceDiagram_decisionOrder(self)

    def existsPathBetween(self, *args) -> bool:
        r"""

        Returns
        -------
        bool
        	true if a path exists between two nodes. 

        """
        return _pyAgrum.InfluenceDiagram_existsPathBetween(self, *args)

    def loadBIFXML(self, *args) -> bool:
        r"""

        Load a BIFXML file.

        Parameters
        ----------
        name : str
        	the name's file

        Raises
        ------
        pyAgrum.IOError
        	If file not found
        pyAgrum.FatalError
        	If file is not valid

        """
        return _pyAgrum.InfluenceDiagram_loadBIFXML(self, *args)

    def saveBIFXML(self, name: str) -> None:
        r"""

        Save the BayesNet in a BIFXML file.

        Parameters
        ----------
        name : str
        	the file's name

        """
        return _pyAgrum.InfluenceDiagram_saveBIFXML(self, name)

    def names(self) -> object:
        r"""

        Returns
        -------
        list
        	The names of the InfluenceDiagram variables

        """
        return _pyAgrum.InfluenceDiagram_names(self)

    def nodes(self) -> object:
        r"""

        Returns
        -------
        set
            the set of ids

        """
        return _pyAgrum.InfluenceDiagram_nodes(self)

    def connectedComponents(self):
      """ connected components from a graph/BN

      Compute the connected components of a pyAgrum's graph or Bayesian Network
      (more generally an object that has `nodes`, `children`/`parents` or `neighbours` methods)

      The firstly visited node for each component is called a 'root' and is used as a key for the component.
      This root has been arbitrarily chosen during the algorithm.

      Returns
      -------
      dict(int,Set[int])
        dict of connected components (as set of nodeIds (int)) with a nodeId (root) of each component as key.

      """
      nodes=self.nodes()
      connected_components=dict()

      def parcours(node,orig):
          cc={node}
          nodes.discard(node)
          if hasattr(self,'children'):
              for chi in self.children(node):
                  if chi!=orig:
                      if chi in nodes:
                          cc|=parcours(chi,node)

          if hasattr(self,'parents'):
              for par in self.parents(node):
                  if par!=orig:
                      if par in nodes:
                          cc|=parcours(par,node)

          if hasattr(self,'neighbours'):
              for nei in self.neighbours(node):
                  if nei!=orig:
                      if nei in nodes:
                          cc|=parcours(nei,node)
          return cc

      while (len(nodes)>0):
          root=nodes.pop()
          connected_components[root]=parcours(root,None)
      return connected_components


    def arcs(self) -> object:
        r"""

        Returns
        -------
        list:
        	the list of all the arcs in the Influence Diagram.

        """
        return _pyAgrum.InfluenceDiagram_arcs(self)

    def parents(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id :
        	The id of the child node

        Returns
        -------
        set
            the set of the parents ids.

        """
        return _pyAgrum.InfluenceDiagram_parents(self, norid)

    def children(self, norid: object) -> object:
        r"""

        Parameters
        ----------
        id : int
          the id of the parent

        Returns
        -------
        Set
        	the set of all the children

        """
        return _pyAgrum.InfluenceDiagram_children(self, norid)

    def family(self, norid: object) -> object:
        return _pyAgrum.InfluenceDiagram_family(self, norid)

    def descendants(self, norid: object) -> object:
        return _pyAgrum.InfluenceDiagram_descendants(self, norid)

    def ancestors(self, norid: object) -> object:
        return _pyAgrum.InfluenceDiagram_ancestors(self, norid)

    def moralizedAncestralGraph(self, nodes: object) -> "pyAgrum.UndiGraph":
        return _pyAgrum.InfluenceDiagram_moralizedAncestralGraph(self, nodes)

    def __repr__(self) -> str:
        return _pyAgrum.InfluenceDiagram___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.InfluenceDiagram___str__(self)

# Register InfluenceDiagram in _pyAgrum:
_pyAgrum.InfluenceDiagram_swigregister(InfluenceDiagram)

def InfluenceDiagram_fastPrototype(dotlike: str, domainSize: int=2) -> "pyAgrum.InfluenceDiagram":
    r"""

    Create an Influence Diagram with a dot-like syntax which specifies:
        - the structure 'a->b<-c;b->d;c<-e;'.
        - a prefix for the type of node (chance/decision/utiliy nodes):

          - `a` : a chance node named 'a' (by default)
          - `$a` : a utility node named 'a'
          - `*a` : a decision node named 'a'

        - the type of the variables with different syntax as postfix:

          - by default, a variable is a pyAgrum.RangeVariable using the default domain size (second argument)
          - with `'a[10]'`, the variable is a pyAgrum.RangeVariable using 10 as domain size (from 0 to 9)
          - with `'a[3,7]'`, the variable is a pyAgrum.RangeVariable using a domainSize from 3 to 7
          - with `'a[1,3.14,5,6.2]'`, the variable is a pyAgrum.DiscretizedVariable using the given ticks (at least 3 values)
          - with `'a{top|middle|bottom}'`, the variable is a pyAgrum.LabelizedVariable using the given labels.
          - with 'a{-1|5|0|3}', the variable is a pyAgrum.IntegerVariable using the sorted given values.

    Note 
    ----
      - If the dot-like string contains such a specification more than once for a variable, the first specification will be used.
      - the potentials (probabilities, utilities) are randomly generated.
      - see also pyAgrum.fastID.

    Examples
    --------
    >>> import pyAgrum as gum
    >>> bn=pyAgrum.fastID('A->B[1,3]<-*C{yes|No}->$D<-E[1,2.5,3.9]',6)

    Parameters
    ----------
    dotlike : str
            the string containing the specification
    domainSize : int
            the default domain size for variables

    Returns
    -------
    pyAgrum.InfluenceDiagram
            the resulting Influence Diagram

    """
    return _pyAgrum.InfluenceDiagram_fastPrototype(dotlike, domainSize)

class ShaferShenoyLIMIDInference(object):
    r"""

    This inference considers the provided model as a LIMID rather than an influence diagram. It is an optimized
    implementation of the LIMID resolution algorithm. However an inference on a classical influence diagram can be performed
    by adding a assumption of the existence of the sequence of decision nodes to be solved, which also implies that the
    decision choices can have an impact on the rest of the sequence (Non Forgetting Assumption,
    cf. pyAgrum.ShaferShenoyLIMIDInference.addNoForgettingAssumption).

    """

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

    def __init__(self, infDiag: "InfluenceDiagram"):
        _pyAgrum.ShaferShenoyLIMIDInference_swiginit(self, _pyAgrum.new_ShaferShenoyLIMIDInference(infDiag))

        self._model=infDiag



    __swig_destroy__ = _pyAgrum.delete_ShaferShenoyLIMIDInference

    def junctionTree(self) -> "pyAgrum.JunctionTree":
        val = _pyAgrum.ShaferShenoyLIMIDInference_junctionTree(self)

        val._engine=self


        return val


    def clear(self) -> None:
        return _pyAgrum.ShaferShenoyLIMIDInference_clear(self)

    def addNoForgettingAssumption(self, *args) -> None:
        return _pyAgrum.ShaferShenoyLIMIDInference_addNoForgettingAssumption(self, *args)

    def hasNoForgettingAssumption(self) -> bool:
        return _pyAgrum.ShaferShenoyLIMIDInference_hasNoForgettingAssumption(self)

    def reducedGraph(self) -> "pyAgrum.DAG":
        return _pyAgrum.ShaferShenoyLIMIDInference_reducedGraph(self)

    def reversePartialOrder(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.ShaferShenoyLIMIDInference_reversePartialOrder(self)

    def reducedLIMID(self) -> "pyAgrum.InfluenceDiagram":
        return _pyAgrum.ShaferShenoyLIMIDInference_reducedLIMID(self)

    def isSolvable(self) -> bool:
        return _pyAgrum.ShaferShenoyLIMIDInference_isSolvable(self)

    def optimalDecision(self, *args) -> "pyAgrum.Potential":
        r"""

        Returns best choice for decision variable given in parameter ( based upon MEU criteria )

        Parameters
        ----------
        decisionId : int,str
        	the id or name of the decision variable

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If no inference have yet been made
        pyAgrum.InvalidNode
        	If node given in parmaeter is not a decision node 

        """
        return _pyAgrum.ShaferShenoyLIMIDInference_optimalDecision(self, *args)

    def posteriorUtility(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.ShaferShenoyLIMIDInference_posteriorUtility(self, *args)

    def setEvidence(self, evidces):
        """
        Erase all the evidences and apply addEvidence(key,value) for every pairs in evidces.

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the influence diagram
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))
        self.eraseAllEvidence()
        for k,v in evidces.items():
            self.addEvidence(k,v)



    def updateEvidence(self, evidces):
        """
        Apply chgEvidence(key,value) for every pairs in evidces (or addEvidence).

        Parameters
        ----------
        evidces : dict
          a dict of evidences

        Raises
        ------
        gum.InvalidArgument
            If one value is not a value for the node
        gum.InvalidArgument
            If the size of a value is different from the domain side of the node
        gum.FatalError
            If one value is a vector of 0s
        gum.UndefinedElement
            If one node does not belong to the Bayesian network
        """
        if not isinstance(evidces, dict):
            raise TypeError("setEvidence parameter must be a dict, not %s"%(type(evidces)))

        for k,v in evidces.items():
            if self.hasEvidence(k):
                self.chgEvidence(k,v)
            else:
                self.addEvidence(k,v)



    def hardEvidenceNodes(self) -> object:
        return _pyAgrum.ShaferShenoyLIMIDInference_hardEvidenceNodes(self)

    def softEvidenceNodes(self) -> object:
        return _pyAgrum.ShaferShenoyLIMIDInference_softEvidenceNodes(self)

    def MEU(self, *args) -> object:
        r"""

        Returns maximum expected utility obtained from inference.

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If no inference have yet been made 

        """
        return _pyAgrum.ShaferShenoyLIMIDInference_MEU(self, *args)

    def meanVar(self, *args) -> object:
        return _pyAgrum.ShaferShenoyLIMIDInference_meanVar(self, *args)

    def makeInference(self) -> None:
        r"""

        Makes the inference. 

        """
        return _pyAgrum.ShaferShenoyLIMIDInference_makeInference(self)

    def posterior(self, *args) -> "pyAgrum.Potential":
        return _pyAgrum.ShaferShenoyLIMIDInference_posterior(self, *args)

    def addEvidence(self, *args) -> None:
        return _pyAgrum.ShaferShenoyLIMIDInference_addEvidence(self, *args)

    def chgEvidence(self, *args) -> None:
        return _pyAgrum.ShaferShenoyLIMIDInference_chgEvidence(self, *args)

    def hasEvidence(self, *args) -> bool:
        return _pyAgrum.ShaferShenoyLIMIDInference_hasEvidence(self, *args)

    def eraseAllEvidence(self) -> None:
        r"""

        Removes all the evidence entered into the diagram.

        """
        return _pyAgrum.ShaferShenoyLIMIDInference_eraseAllEvidence(self)

    def eraseEvidence(self, *args) -> None:
        r"""

        Parameters
        ----------
        evidence : pyAgrum.Potential
        	the evidence to remove

        Raises
        ------
        pyAgrum.IndexError
        	If the evidence does not belong to the influence diagram

        """
        return _pyAgrum.ShaferShenoyLIMIDInference_eraseEvidence(self, *args)

    def hasHardEvidence(self, nodeName: str) -> bool:
        return _pyAgrum.ShaferShenoyLIMIDInference_hasHardEvidence(self, nodeName)

    def hasSoftEvidence(self, *args) -> bool:
        return _pyAgrum.ShaferShenoyLIMIDInference_hasSoftEvidence(self, *args)

    def nbrEvidence(self) -> int:
        return _pyAgrum.ShaferShenoyLIMIDInference_nbrEvidence(self)

    def nbrHardEvidence(self) -> int:
        return _pyAgrum.ShaferShenoyLIMIDInference_nbrHardEvidence(self)

    def nbrSoftEvidence(self) -> int:
        return _pyAgrum.ShaferShenoyLIMIDInference_nbrSoftEvidence(self)

    def influenceDiagram(self) -> "pyAgrum.InfluenceDiagram":
        r"""

        Returns a constant reference over the InfluenceDiagram on which this class work.

        Returns
        -------
        pyAgrum.InfluenceDiagram
        	the InfluenceDiagram on which this class work

        """
        return _pyAgrum.ShaferShenoyLIMIDInference_influenceDiagram(self)

# Register ShaferShenoyLIMIDInference in _pyAgrum:
_pyAgrum.ShaferShenoyLIMIDInference_swigregister(ShaferShenoyLIMIDInference)

class BNLearner(object):
    r"""

    BNLearner(filename,inducedTypes=True) -> BNLearner
        Parameters:
            * **filename** (*str*) -- the file to learn from
            * **inducedTypes** (*Bool*) -- whether BNLearner should try to automatically find the type of each variable

    BNLearner(filename,src) -> BNLearner
        Parameters:
            * **filename** (*str*) -- the file to learn from
            * **src** (*pyAgrum.BayesNet*) -- the Bayesian network used to find those modalities

    BNLearner(learner) -> BNLearner
        Parameters:
            * **learner** (*pyAgrum.BNLearner*) -- the BNLearner to copy

    """

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

    def __init__(self, *args):
        _pyAgrum.BNLearner_swiginit(self, _pyAgrum.new_BNLearner(*args))
    __swig_destroy__ = _pyAgrum.delete_BNLearner

    def learnBN(self) -> "pyAgrum.BayesNet":
        r"""

        learn a BayesNet from a file (must have read the db before)

        Returns
        -------
        pyAgrum.BayesNet
        	the learned BayesNet

        """
        return _pyAgrum.BNLearner_learnBN(self)

    def learnParameters(self, *args) -> "pyAgrum.BayesNet":
        r"""

        learns a BN (its parameters) when its structure is known.

        Parameters
        ----------
        dag : pyAgrum.DAG
        bn : pyAgrum.BayesNet
        take_into_account_score : bool
        	The dag passed in argument may have been learnt from a structure learning. In this case, if the score used to learn the structure has an implicit apriori (like K2 which has a 1-smoothing apriori), it is important to also take into account this implicit apriori for parameter learning. By default, if a score exists, we will learn parameters by taking into account the apriori specified by methods useAprioriXXX () + the implicit apriori of the score, else we just take into account the apriori specified by useAprioriXXX ()

        Returns
        -------
        pyAgrum.BayesNet
        	the learned BayesNet

        Raises
        ------
        pyAgrum.MissingVariableInDatabase
        	If a variable of the BN is not found in the database
        pyAgrum.UnknownLabelInDatabase
        	If a label is found in the database that do not correspond to the variable

        """
        return _pyAgrum.BNLearner_learnParameters(self, *args)

    def __repr__(self) -> str:
        return _pyAgrum.BNLearner___repr__(self)

    def __str__(self) -> str:
        return _pyAgrum.BNLearner___str__(self)

    def chi2(self, *args) -> object:
        r"""

        chi2 computes the chi2 statistic and pvalue for two columns, given a list of other columns.


        Parameters
        ----------
        name1: str
        	the name of the first column

        name2 : str
        	the name of the second column

        knowing : [str]
        	the list of names of conditioning columns

        Returns
        -------
        statistic,pvalue
        	the chi2 statistic and the associated p-value as a Tuple

        """
        return _pyAgrum.BNLearner_chi2(self, *args)

    def G2(self, *args) -> object:
        r"""

        G2 computes the G2 statistic and pvalue for two columns, given a list of other columns.


        Parameters
        ----------
        name1: str
        	the name of the first column

        name2 : str
        	the name of the second column

        knowing : [str]
        	the list of names of conditioning columns

        Returns
        -------
        statistic,pvalue
        	the G2 statistic and the associated p-value as a Tuple

        """
        return _pyAgrum.BNLearner_G2(self, *args)

    def state(self) -> object:
        return _pyAgrum.BNLearner_state(self)

    def pseudoCount(self,vars):
        """ access to pseudo-count (priors taken into account)

        Parameters
        ----------
        vars : list[str]
          a list of name of vars to add in the pseudo_count

        Returns
        -------
        a Potential containing this pseudo-counts
        """
        p=Potential()
        lv=list()
        for i in vars:
            if type(i) is str:
                name=i
            else:
                name=self.nameFromId(i)
            p.add(RangeVariable(name,name,0,self.domainSize(i)-1))
            lv.append(name)
        p.fillWith(self.rawPseudoCount(lv))
        return p


    def setVerbosity(self, v: bool) -> None:
        r"""

        Parameters
        ----------
        v : bool
                verbosity

        """
        return _pyAgrum.BNLearner_setVerbosity(self, v)

    def setEpsilon(self, eps: float) -> None:
        r"""

        Parameters
        ----------
        eps : float
        	the epsilon we want to use

        Raises
        ------
        pyAgrum.OutOfBounds
        	If eps<0

        """
        return _pyAgrum.BNLearner_setEpsilon(self, eps)

    def setMinEpsilonRate(self, rate: float) -> None:
        r"""

        Parameters
        ----------
        rate : float
        	the minimal epsilon rate

        """
        return _pyAgrum.BNLearner_setMinEpsilonRate(self, rate)

    def setMaxIter(self, max: int) -> None:
        r"""

        Parameters
        ----------
        max : int
        	the maximum number of iteration

        Raises
        ------
        pyAgrum.OutOfBounds
        	If max <= 1

        """
        return _pyAgrum.BNLearner_setMaxIter(self, max)

    def setMaxTime(self, timeout: float) -> None:
        r"""

        Parameters
        ----------
        tiemout : float
        	stopping criterion on timeout (in seconds)

        Raises
        ------
        pyAgrum.OutOfBounds
        	If timeout<=0.0

        """
        return _pyAgrum.BNLearner_setMaxTime(self, timeout)

    def setPeriodSize(self, p: int) -> None:
        r"""

        Parameters
        ----------
        p : int
        	number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.BNLearner_setPeriodSize(self, p)

    def verbosity(self) -> bool:
        r"""

        Returns
        -------
        bool
        	True if the verbosity is enabled

        """
        return _pyAgrum.BNLearner_verbosity(self)

    def epsilon(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of epsilon

        """
        return _pyAgrum.BNLearner_epsilon(self)

    def minEpsilonRate(self) -> float:
        r"""

        Returns
        -------
        float
        	the value of the minimal epsilon rate

        """
        return _pyAgrum.BNLearner_minEpsilonRate(self)

    def maxIter(self) -> int:
        r"""

        Returns
        -------
        int
        	the criterion on number of iterations

        """
        return _pyAgrum.BNLearner_maxIter(self)

    def maxTime(self) -> float:
        r"""

        Returns
        -------
        float
        	the timeout(in seconds)

        """
        return _pyAgrum.BNLearner_maxTime(self)

    def periodSize(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of samples between 2 stopping

        Raises
        ------
        pyAgrum.OutOfBounds
        	If p<1

        """
        return _pyAgrum.BNLearner_periodSize(self)

    def nbrIterations(self) -> int:
        r"""

        Returns
        -------
        int
        	the number of iterations

        """
        return _pyAgrum.BNLearner_nbrIterations(self)

    def currentTime(self) -> float:
        r"""

        Returns
        -------
        float
        	get the current running time in second (float)

        """
        return _pyAgrum.BNLearner_currentTime(self)

    def messageApproximationScheme(self) -> str:
        r"""

        Returns
        -------
        str
        	the approximation scheme message

        """
        return _pyAgrum.BNLearner_messageApproximationScheme(self)

    def history(self) -> List[float]:
        r"""

        Returns
        -------
        tuple
        	the scheme history

        Raises
        ------
        pyAgrum.OperationNotAllowed
        	If the scheme did not performed or if verbosity is set to false

        """
        return _pyAgrum.BNLearner_history(self)

    def _asIApproximationSchemeConfiguration(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.BNLearner__asIApproximationSchemeConfiguration(self)

    def learnDAG(self) -> "pyAgrum.DAG":
        r"""

        learn a structure from a file

        Returns
        -------
        pyAgrum.DAG
        	the learned DAG

        """
        return _pyAgrum.BNLearner_learnDAG(self)

    def names(self) -> List[str]:
        r"""

        Returns
        -------
        List[str]
        	the names of the variables in the database

        """
        return _pyAgrum.BNLearner_names(self)

    def idFromName(self, var_name: str) -> int:
        r"""

        Parameters
        ----------
        var_names : str
        	a variable's name

        Returns
        -------
        int
        	the column id corresponding to a variable name

        Raises
        ------
        pyAgrum.MissingVariableInDatabase
        	If a variable of the BN is not found in the database.

        """
        return _pyAgrum.BNLearner_idFromName(self, var_name)

    def nameFromId(self, id: int) -> str:
        r"""

        Parameters
        ----------
        id
        	a node id

        Returns
        -------
        str
        	the variable's name

        """
        return _pyAgrum.BNLearner_nameFromId(self, id)

    def useScoreAIC(self) -> None:
        return _pyAgrum.BNLearner_useScoreAIC(self)

    def useScoreBD(self) -> None:
        return _pyAgrum.BNLearner_useScoreBD(self)

    def useScoreBDeu(self) -> None:
        return _pyAgrum.BNLearner_useScoreBDeu(self)

    def useScoreBIC(self) -> None:
        return _pyAgrum.BNLearner_useScoreBIC(self)

    def useScoreK2(self) -> None:
        return _pyAgrum.BNLearner_useScoreK2(self)

    def useScoreLog2Likelihood(self) -> None:
        return _pyAgrum.BNLearner_useScoreLog2Likelihood(self)

    def setDatabaseWeight(self, new_weight: float) -> None:
        r"""

        Set the database weight which is given as an equivalent sample size.

        Parameters
        ----------
        weight : float
        	the database weight

        """
        return _pyAgrum.BNLearner_setDatabaseWeight(self, new_weight)

    def setRecordWeight(self, i: int, weight: float) -> None:
        return _pyAgrum.BNLearner_setRecordWeight(self, i, weight)

    def databaseWeight(self) -> float:
        return _pyAgrum.BNLearner_databaseWeight(self)

    def recordWeight(self, i: int) -> float:
        return _pyAgrum.BNLearner_recordWeight(self, i)

    def useNoApriori(self) -> None:
        return _pyAgrum.BNLearner_useNoApriori(self)

    def useAprioriSmoothing(self, *args) -> None:
        return _pyAgrum.BNLearner_useAprioriSmoothing(self, *args)

    def useAprioriDirichlet(self, *args) -> None:
        return _pyAgrum.BNLearner_useAprioriDirichlet(self, *args)

    def useAprioriBDeu(self, *args) -> None:
        r"""

        The BDeu apriori adds weight to all the cells of the counting tables.
        In other words, it adds weight rows in the database with equally probable
        values.

        Parameters
        ----------
        weight : float
        	the apriori weight

        """
        return _pyAgrum.BNLearner_useAprioriBDeu(self, *args)

    def useGreedyHillClimbing(self) -> None:
        return _pyAgrum.BNLearner_useGreedyHillClimbing(self)

    def useLocalSearchWithTabuList(self, *args) -> None:
        r"""

        Indicate that we wish to use a local search with tabu list

        Parameters
        ----------
        tabu_size : int
                The size of the tabu list

        nb_decrease : int
                The max number of changes decreasing the score consecutively that we allow to apply

        """
        return _pyAgrum.BNLearner_useLocalSearchWithTabuList(self, *args)

    def useK2(self, *args) -> None:
        r"""

        Indicate to use the K2 algorithm (which needs a total ordering of the variables).

        Parameters
        ----------
        order : list[int or str]
              sequences of (ids or name)

        """
        return _pyAgrum.BNLearner_useK2(self, *args)

    def setMaxIndegree(self, max_indegree: int) -> None:
        return _pyAgrum.BNLearner_setMaxIndegree(self, max_indegree)

    def setSliceOrder(self, *args) -> None:
        r"""

        Set a partial order on the nodes.

        Parameters
        ----------
        l : list
                a list of sequences (composed of ids of rows or string)

        """
        return _pyAgrum.BNLearner_setSliceOrder(self, *args)

    def setPossibleSkeleton(self, skeleton: "pyAgrum.UndiGraph") -> None:
        return _pyAgrum.BNLearner_setPossibleSkeleton(self, skeleton)

    def addPossibleEdge(self, *args) -> None:
        return _pyAgrum.BNLearner_addPossibleEdge(self, *args)

    def erasePossibleEdge(self, *args) -> None:
        r"""

        Allow the 2 arcs to be added if necessary.

        Parameters
        ----------
        arc : pyAgrum
        	an arc
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        """
        return _pyAgrum.BNLearner_erasePossibleEdge(self, *args)

    def addForbiddenArc(self, *args) -> None:
        r"""

        The arc in parameters won't be added.

        Parameters
        ----------
        arc : pyAgrum.Arc
        	an arc
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        """
        return _pyAgrum.BNLearner_addForbiddenArc(self, *args)

    def eraseForbiddenArc(self, *args) -> None:
        r"""

        Allow the arc to be added if necessary.

        Parameters
        ----------
        arc : pyAgrum
        	an arc
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        """
        return _pyAgrum.BNLearner_eraseForbiddenArc(self, *args)

    def addMandatoryArc(self, *args) -> None:
        r"""

        Allow to add prior structural knowledge.

        Parameters
        ----------
        arc : pyAgrum.Arc
        	an arc
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        Raises
        ------
        pyAgrum.InvalidDirectedCycle
        	If the added arc creates a directed cycle in the DAG

        """
        return _pyAgrum.BNLearner_addMandatoryArc(self, *args)

    def eraseMandatoryArc(self, *args) -> None:
        r"""

        Parameters
        ----------
        arc : pyAgrum
        	an arc
        head :
        	a variable's id (int)
        tail :
        	a variable's id (int)
        head :
        	a variable's name (str)
        tail :
        	a variable's name (str)

        """
        return _pyAgrum.BNLearner_eraseMandatoryArc(self, *args)

    def useEM(self, epsilon: float) -> None:
        r"""

        Indicates if we use EM for parameter learning.

        Parameters
        ----------
        epsilon : float
        	if epsilon=0.0 then EM is not used
        	if epsilon>0 then EM is used and stops when the sum of the cumulative squared error on parameters is les than epsilon.

        """
        return _pyAgrum.BNLearner_useEM(self, epsilon)

    def hasMissingValues(self) -> bool:
        r"""

        Indicates whether there are missing values in the database.

        Returns
        -------
        bool
            True if there are some missing values in the database.

        """
        return _pyAgrum.BNLearner_hasMissingValues(self)

    def logLikelihood(self, *args) -> float:
        r"""

        logLikelihood computes the log-likelihood for the columns in vars, given the columns in the list knowing (optional)


        Parameters
        ----------
        vars: List[str]
        	the name of the columns of interest

        knowing : List[str]
        	the (optional) list of names of conditioning columns

        Returns
        -------
        float
        	the log-likelihood (base 2)

        """
        return _pyAgrum.BNLearner_logLikelihood(self, *args)

    def rawPseudoCount(self, *args) -> List[float]:
        return _pyAgrum.BNLearner_rawPseudoCount(self, *args)

    def nbRows(self) -> int:
        r"""

        Return the number of row in the database


        Returns
        -------
        int
        	the number of rows in the database

        """
        return _pyAgrum.BNLearner_nbRows(self)

    def nbCols(self) -> int:
        r"""

        Return the nimber of columns in the database


        Returns
        -------
        int
        	the number of columns in the database

        """
        return _pyAgrum.BNLearner_nbCols(self)

    def domainSize(self, *args) -> int:
        return _pyAgrum.BNLearner_domainSize(self, *args)

    def setInitialDAG(self, g: "DAG") -> None:
        r"""

        Parameters
        ----------
        dag : pyAgrum.DAG
        	an initial DAG structure

        """
        return _pyAgrum.BNLearner_setInitialDAG(self, g)

    def use3off2(self) -> None:
        r"""

        Indicate that we wish to use 3off2.

        """
        return _pyAgrum.BNLearner_use3off2(self)

    def useMIIC(self) -> None:
        r"""

        Indicate that we wish to use MIIC.

        """
        return _pyAgrum.BNLearner_useMIIC(self)

    def useNMLCorrection(self) -> None:
        r"""

        Indicate that we wish to use the NML correction for 3off2 or MIIC

        """
        return _pyAgrum.BNLearner_useNMLCorrection(self)

    def useMDLCorrection(self) -> None:
        r"""

        Indicate that we wish to use the MDL correction for 3off2 or MIIC

        """
        return _pyAgrum.BNLearner_useMDLCorrection(self)

    def useNoCorrection(self) -> None:
        r"""

        Indicate that we wish to use the NoCorr correction for 3off2 or MIIC

        """
        return _pyAgrum.BNLearner_useNoCorrection(self)

    def latentVariables(self, *args) -> List[Tuple[int,int]]:
        r"""

        Warnings
        --------
        learner must be using 3off2 or MIIC algorithm

        Returns
        -------
        list
        	the list of latent variables

        """
        return _pyAgrum.BNLearner_latentVariables(self, *args)

    def learnMixedStructure(self) -> "pyAgrum.MixedGraph":
        r"""

        Warnings
        --------
        learner must be using 3off2 or MIIC algorithm

        Returns
        -------
        pyAgrum.EssentialGraph
        	the learned structure as an EssentialGraph

        """
        val = _pyAgrum.BNLearner_learnMixedStructure(self)

        bn=BayesNet()
        for i in range(len(self.names())):
          bn.add(self.nameFromId(i),2)
        ge=EssentialGraph(bn,val)
        ge._bn=bn
        return ge


        return val


# Register BNLearner in _pyAgrum:
_pyAgrum.BNLearner_swigregister(BNLearner)

class BNDatabaseGenerator(object):
    r"""

    BNDatabaseGenerator is used to easily generate databases from a pyAgrum.BayesNet.

    Parameters
    ----------
    bn: pyAgrum.BayesNet
      the Bayesian network used to generate data.

    """

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

    def __init__(self, bn: "pyAgrum.BayesNet"):
        r"""

        BNDatabaseGenerator is used to easily generate databases from a pyAgrum.BayesNet.

        Parameters
        ----------
        bn: pyAgrum.BayesNet
          the Bayesian network used to generate data.

        """
        _pyAgrum.BNDatabaseGenerator_swiginit(self, _pyAgrum.new_BNDatabaseGenerator(bn))
    __swig_destroy__ = _pyAgrum.delete_BNDatabaseGenerator

    def drawSamples(self, nbSamples: int) -> float:
        return _pyAgrum.BNDatabaseGenerator_drawSamples(self, nbSamples)

    def toCSV(self, *args) -> None:
        return _pyAgrum.BNDatabaseGenerator_toCSV(self, *args)

    def toDatabaseTable(self, useLabels: bool=True) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.BNDatabaseGenerator_toDatabaseTable(self, useLabels)

    def database(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.BNDatabaseGenerator_database(self)

    def setVarOrder(self, *args) -> None:
        return _pyAgrum.BNDatabaseGenerator_setVarOrder(self, *args)

    def setVarOrderFromCSV(self, *args) -> None:
        return _pyAgrum.BNDatabaseGenerator_setVarOrderFromCSV(self, *args)

    def setTopologicalVarOrder(self) -> None:
        return _pyAgrum.BNDatabaseGenerator_setTopologicalVarOrder(self)

    def setAntiTopologicalVarOrder(self) -> None:
        return _pyAgrum.BNDatabaseGenerator_setAntiTopologicalVarOrder(self)

    def setRandomVarOrder(self) -> None:
        return _pyAgrum.BNDatabaseGenerator_setRandomVarOrder(self)

    def varOrder(self) -> "pyAgrum.YetUnWrapped":
        return _pyAgrum.BNDatabaseGenerator_varOrder(self)

    def varOrderNames(self) -> List[str]:
        return _pyAgrum.BNDatabaseGenerator_varOrderNames(self)

    def log2likelihood(self) -> float:
        return _pyAgrum.BNDatabaseGenerator_log2likelihood(self)

# Register BNDatabaseGenerator in _pyAgrum:
_pyAgrum.BNDatabaseGenerator_swigregister(BNDatabaseGenerator)


def statsObj() -> None:
    return _pyAgrum.statsObj()


