class_docstr: Base class for Markov Model.
  
  A MarkovNetwork stores nodes and edges with potentials
  
  MarkovNetwork holds undirected edges.
  
  Parameters
  ----------
  data : input graph
      Data to initialize graph.  If data=None (default) an empty
      graph is created.  The data can be an edge list, or any
      NetworkX graph object.
  
  Examples
  --------
  Create an empty Markov Model with no nodes and no edges.
  
  >>> from pgmpy.models import MarkovNetwork
  >>> G = MarkovNetwork()
  
  G can be grown in several ways.
  
  **Nodes:**
  
  Add one node at a time:
  
  >>> G.add_node('a')
  
  Add the nodes from any container (a list, set or tuple or the nodes
  from another graph).
  
  >>> G.add_nodes_from(['a', 'b'])
  
  **Edges:**
  
  G can also be grown by adding edges.
  
  Add one edge,
  
  >>> G.add_edge('a', 'b')
  
  a list of edges,
  
  >>> G.add_edges_from([('a', 'b'), ('b', 'c')])
  
  If some edges connect nodes not yet in the model, the nodes
  are added automatically.  There are no errors when adding
  nodes or edges that already exist.
  
  **Shortcuts:**
  
  Many common graph features allow python syntax for speed reporting.
  
  >>> 'a' in G     # check if node in graph
  True
  >>> len(G)  # number of nodes in graph
  3
class_docstr_tok: ["Base","class","for","Markov","Model",".","A","MarkovNetwork","stores","nodes","and","edges","with","potentials","MarkovNetwork","holds","undirected","edges",".","Parameters","--","--","--","--","--","data",":","input","graph","Data","to","initialize","graph",".","If","data=None","(","default",")","an","empty","graph","is","created",".","The","data","can","be","an","edge","list",",","or","any","NetworkX","graph","object",".","Examples","--","--","--","--","Create","an","empty","Markov","Model","with","no","nodes","and","no","edges",".",">",">",">","from","pgmpy.models","import","MarkovNetwork",">",">",">","G","=","MarkovNetwork","(",")","G","can","be","grown","in","several","ways",".","*","*","Nodes",":","*","*","Add","one","node","at","a","time",":",">",">",">","G.add_node","(","'","a","'",")","Add","the","nodes","from","any","container","(","a","list",",","set","or","tuple","or","the","nodes","from","another","graph",")",".",">",">",">","G.add_nodes_from","(","[","'","a","'",",","'","b","'","]",")","*","*","Edges",":","*","*","G","can","also","be","grown","by","adding","edges",".","Add","one","edge",",",">",">",">","G.add_edge","(","'","a","'",",","'","b","'",")","a","list","of","edges",",",">",">",">","G.add_edges_from","(","[","(","'","a","'",",","'","b","'",")",",","(","'","b","'",",","'","c","'",")","]",")","If","some","edges","connect","nodes","not","yet","in","the","model",",","the","nodes","are","added","automatically",".","There","are","no","errors","when","adding","nodes","or","edges","that","already","exist",".","*","*","Shortcuts",":","*","*","Many","common","graph","features","allow","python","syntax","for","speed","reporting",".",">",">",">","'","a","'","in","G","#","check","if","node","in","graph","True",">",">",">","len","(","G",")","#","number","of","nodes","in","graph","3"]
docstr: Creates a Bayesian Model which is a minimum I-Map for this Markov Model.
  
  The ordering of parents may not remain constant. It would depend on the
  ordering of variable in the junction tree (which is not constant) all the
  time. Also, if the model is not connected, the connected components are
  treated as separate models, converted, and then joined together.
  
  Examples
  --------
  >>> from pgmpy.models import MarkovNetwork
  >>> from pgmpy.factors.discrete import DiscreteFactor
  >>> mm = MarkovNetwork()
  >>> mm.add_nodes_from(['x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7'])
  >>> mm.add_edges_from([('x1', 'x3'), ('x1', 'x4'), ('x2', 'x4'),
  ...                    ('x2', 'x5'), ('x3', 'x6'), ('x4', 'x6'),
  ...                    ('x4', 'x7'), ('x5', 'x7')])
  >>> phi = [DiscreteFactor(edge, [2, 2], np.random.rand(4)) for edge in mm.edges()]
  >>> mm.add_factors(*phi)
  >>> bm = mm.to_bayesian_model()
docstr_tok: ["Creates","a","Bayesian","Model","which","is","a","minimum","I-Map","for","this","Markov","Model",".","The","ordering","of","parents","may","not","remain","constant",".","It","would","depend","on","the","ordering","of","variable","in","the","junction","tree","(","which","is","not","constant",")","all","the","time",".","Also",",","if","the","model","is","not","connected",",","the","connected","components","are","treated","as","separate","models",",","converted",",","and","then","joined","together",".","Examples","--","--","--","--",">",">",">","from","pgmpy.models","import","MarkovNetwork",">",">",">","from","pgmpy.factors.discrete","import","DiscreteFactor",">",">",">","mm","=","MarkovNetwork","(",")",">",">",">","mm.add_nodes_from","(","[","'x1","'",",","'x2","'",",","'x3","'",",","'x4","'",",","'x5","'",",","'x6","'",",","'x7","'","]",")",">",">",">","mm.add_edges_from","(","[","(","'x1","'",",","'x3","'",")",",","(","'x1","'",",","'x4","'",")",",","(","'x2","'",",","'x4","'",")",",","...","(","'x2","'",",","'x5","'",")",",","(","'x3","'",",","'x6","'",")",",","(","'x4","'",",","'x6","'",")",",","...","(","'x4","'",",","'x7","'",")",",","(","'x5","'",",","'x7","'",")","]",")",">",">",">","phi","=","[","DiscreteFactor","(","edge",",","[","2",",","2","]",",","np.random.rand","(","4",")",")","for","edge","in","mm.edges","(",")","]",">",">",">","mm.add_factors","(","*","phi",")",">",">",">","bm","=","mm.to_bayesian_model","(",")"]
code: def to_bayesian_model(self):
      """
      Creates a Bayesian Model which is a minimum I-Map for this Markov Model.
  
      The ordering of parents may not remain constant. It would depend on the
      ordering of variable in the junction tree (which is not constant) all the
      time. Also, if the model is not connected, the connected components are
      treated as separate models, converted, and then joined together.
  
      Examples
      --------
      >>> from pgmpy.models import MarkovNetwork
      >>> from pgmpy.factors.discrete import DiscreteFactor
      >>> mm = MarkovNetwork()
      >>> mm.add_nodes_from(['x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7'])
      >>> mm.add_edges_from([('x1', 'x3'), ('x1', 'x4'), ('x2', 'x4'),
      ...                    ('x2', 'x5'), ('x3', 'x6'), ('x4', 'x6'),
      ...                    ('x4', 'x7'), ('x5', 'x7')])
      >>> phi = [DiscreteFactor(edge, [2, 2], np.random.rand(4)) for edge in mm.edges()]
      >>> mm.add_factors(*phi)
      >>> bm = mm.to_bayesian_model()
      """
      from pgmpy.models import BayesianNetwork
  
      # If the graph is not connected, treat them as separate models and join them together in the end.
      bms = []
      for node_set in connected_components(self):
          bm = BayesianNetwork()
          var_clique_dict = defaultdict(tuple)
          var_order = []
  
          subgraph = self.subgraph(node_set)
  
          # Create a Junction Tree from the Markov Model.
          # Creation of Clique Tree involves triangulation, finding maximal cliques
          # and creating a tree from these cliques
          junction_tree = MarkovNetwork(
              subgraph.edges()
          ).to_junction_tree()
  
          # create an ordering of the nodes based on the ordering of the clique
          # in which it appeared first
          root_node = next(iter(junction_tree.nodes()))
          bfs_edges = nx.bfs_edges(junction_tree, root_node)
          for node in root_node:
              var_clique_dict[node] = root_node
              var_order.append(node)
          for edge in bfs_edges:
              clique_node = edge[1]
              for node in clique_node:
                  if not var_clique_dict[node]:
                      var_clique_dict[node] = clique_node
                      var_order.append(node)
  
          # create a Bayesian Network by adding edges from parent of node to node as
          # par(x_i) = (var(c_k) - x_i) \cap {x_1, ..., x_{i-1}}
          for node_index in range(len(var_order)):
              node = var_order[node_index]
              node_parents = (
                  set(var_clique_dict[node]) - set([node])
              ).intersection(set(var_order[:node_index]))
              bm.add_edges_from(
                  [(parent, node) for parent in node_parents]
              )
              # TODO : Convert factor into CPDs
          bms.append(bm)
  
      # Join the bms in a single model.
      final_bm = BayesianNetwork()
      for bm in bms:
          final_bm.add_edges_from(bm.edges())
          final_bm.add_nodes_from(bm.nodes())
      return final_bm
  
imports: import itertools
  from collections import defaultdict
  import networkx
  import numpy
  from networkx.algorithms.components import connected_components
  from pgmpy.base import UndirectedGraph
  from pgmpy.factors import factor_product
  from pgmpy.factors.discrete import DiscreteFactor
  from pgmpy.independencies import Independencies
label_desc: Use image node_id 14 for calling the MarkovNetwork obj's underlying member method code with example usage: obj.to_bayesian_model() and returns: final_bm