Commit 7477469e authored by Tiago Peixoto's avatar Tiago Peixoto

Fix problem with and improve BlockState.get_edges_prob()

parent 666ccd25
This diff is collapsed.
......@@ -33,6 +33,7 @@ from numpy import *
import numpy
import copy
import collections
import itertools
from . util import *
......@@ -977,84 +978,91 @@ class BlockState(object):
else:
return self._state.get_move_prob(int(v), s, self.b[v], c, True)
def get_edges_prob(self, edge_list, missing=True, entropy_args={}):
"""Compute the unnormalized log-probability of the missing (or spurious if
``missing=False``) edges given by ``edge_list`` (a list of ``(source,
target)`` tuples, or :meth:`~graph_tool.Edge` instances). The values in
``entropy_args`` are passed to :meth:`graph_tool.BlockState.entropy()`
to calculate the log-probability.
def get_edges_prob(self, missing, spurious=[], entropy_args={}):
"""Compute the joint log-probability of the missing and spurious edges given by
``missing`` and ``spurious`` (a list of ``(source, target)``
tuples, or :meth:`~graph_tool.Edge` instances), together with the
observed edges.
More precisely, the log-likelihood returned is
.. math::
\ln P(\boldsymbol G + \delta \boldsymbol G | \boldsymbol b)
where :math:`\boldsymbol G + \delta \boldsymbol G` is the modified graph
(with missing edges added and spurious edges deleted).
The values in ``entropy_args`` are passed to
:meth:`graph_tool.BlockState.entropy()` to calculate the
log-probability.
"""
pos = {}
for u, v in edge_list:
for u, v in itertools.chain(missing, spurious):
pos[u] = self.b[u]
pos[v] = self.b[v]
Si = self.entropy(**entropy_args)
self.remove_vertex(pos.keys())
try:
if missing:
new_es = []
for u, v in edge_list:
if not self.is_weighted:
new_es = []
for u, v in missing:
if not self.is_weighted:
e = self.g.add_edge(u, v)
else:
e = self.g.edge(u, v)
if e is None:
e = self.g.add_edge(u, v)
else:
e = self.g.edge(u, v)
if e is None:
e = self.g.add_edge(u, v)
self.eweight[e] = 0
self.eweight[e] += 1
new_es.append(e)
else:
old_es = []
for e in edge_list:
u, v = e
if isinstance(e, tuple):
e = self.g.edge(u, v)
if e is None:
raise ValueError("edge not found: (%d, %d)" % (int(u),
int(v)))
if self.is_weighted:
self.eweight[e] -= 1
if self.eweight[e] == 0:
self.g.remove_edge(e)
else:
self.eweight[e] = 0
self.eweight[e] += 1
new_es.append(e)
old_es = []
for e in spurious:
u, v = e
if isinstance(e, tuple):
e = self.g.edge(u, v)
if e is None:
raise ValueError("edge not found: (%d, %d)" % (int(u),
int(v)))
if self.is_weighted:
self.eweight[e] -= 1
if self.eweight[e] == 0:
self.g.remove_edge(e)
old_es.append((u, v))
else:
self.g.remove_edge(e)
old_es.append((u, v))
self.add_vertex(pos.keys(), pos.values())
Sf = self.entropy(**entropy_args)
Sf = self.entropy(**overlay(dict(partition_dl=False),
**entropy_args))
self.remove_vertex(pos.keys())
finally:
if missing:
if self.is_weighted:
for e in reversed(new_es):
self.eweight[e] -= 1
if self.eweight[e] == 0:
self.g.remove_edge(e)
else:
for e in reversed(new_es):
if self.is_weighted:
for e in reversed(new_es):
self.eweight[e] -= 1
if self.eweight[e] == 0:
self.g.remove_edge(e)
else:
for u, v in old_es:
if self.is_weighted:
e = self.g.edge(u, v)
if e is None:
e = self.g.add_edge(u, v)
self.eweight[e] = 0
self.eweight[e] += 1
else:
self.g.add_edge(u, v)
for e in reversed(new_es):
self.g.remove_edge(e)
for u, v in old_es:
if self.is_weighted:
e = self.g.edge(u, v)
if e is None:
e = self.g.add_edge(u, v)
self.eweight[e] = 0
self.eweight[e] += 1
else:
self.g.add_edge(u, v)
self.add_vertex(pos.keys(), pos.values())
L = Si - Sf
L = -Sf
if _bm_test():
state = self.copy()
......
......@@ -644,16 +644,28 @@ class LayeredBlockState(OverlapBlockState, BlockState):
u = self.vmap[v][i]
return u
def get_edges_prob(self, edge_list, missing=True, entropy_args={}):
"""Compute the log-probability of the missing (or spurious if ``missing=False``)
edges given by ``edge_list`` (a list of ``(source, target, ec)`` tuples, or
:meth:`~graph_tool.Edge` instances). The values in ``entropy_args`` are
passed to :meth:`graph_tool.LayeredBlockState.entropy()` to calculate the
def get_edges_prob(self, missing, spurious=[], entropy_args={}):
"""Compute the joint log-probability of the missing and spurious edges given by
``missing`` and ``spurious`` (a list of ``(source, target, layer)``
tuples, or :meth:`~graph_tool.Edge` instances), together with the
observed edges.
More precisely, the log-likelihood returned is
.. math::
\ln P(\boldsymbol G + \delta \boldsymbol G | \boldsymbol b)
where :math:`\boldsymbol G + \delta \boldsymbol G` is the modified graph
(with missing edges added and spurious edges deleted).
The values in ``entropy_args`` are passed to
:meth:`graph_tool.BlockState.entropy()` to calculate the
log-probability.
"""
pos = {}
nes = []
for e in edge_list:
for e in itertools.chain(missing, spurious):
try:
u, v = e
l = self.ec[e]
......@@ -669,87 +681,83 @@ class LayeredBlockState(OverlapBlockState, BlockState):
edge_list = nes
Si = self.entropy(**entropy_args)
self.remove_vertex(pos.keys())
agg_state = self.agg_state
try:
if missing:
new_es = []
for u, v, l in edge_list:
if not l[1]:
state = self.agg_state
else:
state = self.layer_states[l[0]]
e = state.g.add_edge(u, v)
if not l[1]:
self.ec[e] = l[0]
if state.is_weighted:
state.eweight[e] = 1
new_es.append((e, l))
else:
old_es = []
for u, v, l in edge_list:
if not l[1]:
state = self.agg_state
es = state.g.edge(u, v, all_edges=True)
es = [e for e in es if self.ec[e] == l[0]]
if len(es) > 0:
e = es[0]
else:
e = None
else:
state = self.layer_states[l[0]]
e = state.g.edge(u, v)
if e is None:
raise ValueError("edge not found: (%d, %d, %d)" % \
(int(u), int(v), l[0]))
if state.is_weighted:
staete.eweight[e] -= 1
if state.eweight[e] == 0:
state.g.remove_edge(e)
new_es = []
for u, v, l in missing:
if not l[1]:
state = self.agg_state
else:
state = self.layer_states[l[0]]
e = state.g.add_edge(u, v)
if not l[1]:
self.ec[e] = l[0]
if state.is_weighted:
state.eweight[e] = 1
new_es.append((e, l))
old_es = []
for u, v, l in spurious:
if not l[1]:
state = self.agg_state
es = state.g.edge(u, v, all_edges=True)
es = [e for e in es if self.ec[e] == l[0]]
if len(es) > 0:
e = es[0]
else:
e = None
else:
state = self.layer_states[l[0]]
e = state.g.edge(u, v)
if e is None:
raise ValueError("edge not found: (%d, %d, %d)" % \
(int(u), int(v), l[0]))
if state.is_weighted:
staete.eweight[e] -= 1
if state.eweight[e] == 0:
state.g.remove_edge(e)
old_es.append((u, v, l))
else:
state.g.remove_edge(e)
old_es.append((u, v, l))
self.add_vertex(pos.keys(), pos.values())
Sf = self.entropy(**entropy_args)
Sf = self.entropy(**overlay(dict(partition_dl=False),
**entropy_args))
self.remove_vertex(pos.keys())
finally:
if missing:
for e, l in new_es:
if not l[1]:
state = self.agg_state
else:
state = self.layer_states[l[0]]
state.g.remove_edge(e)
else:
for u, v, l in old_es:
if not l[1]:
state = self.agg_state
else:
state = self.layer_states[l[0]]
if state.is_weighted:
e = state.g.edge(u, v)
if e is None:
e = state.g.add_edge(u, v)
state.eweight[e] = 0
if not l[1]:
self.ec[e] = l[0]
state.eweight[e] += 1
else:
for e, l in new_es:
if not l[1]:
state = self.agg_state
else:
state = self.layer_states[l[0]]
state.g.remove_edge(e)
for u, v, l in old_es:
if not l[1]:
state = self.agg_state
else:
state = self.layer_states[l[0]]
if state.is_weighted:
e = state.g.edge(u, v)
if e is None:
e = state.g.add_edge(u, v)
state.eweight[e] = 0
if not l[1]:
self.ec[e] = l[0]
state.eweight[e] += 1
else:
e = state.g.add_edge(u, v)
if not l[1]:
self.ec[e] = l[0]
self.add_vertex(pos.keys(), pos.values())
L = Si - Sf
L = -Sf
if _bm_test():
state = self.copy()
......
......@@ -306,13 +306,26 @@ class NestedBlockState(object):
self.levels[0].add_vertex(v, r)
self._regen_levels()
def get_edges_prob(self, edge_list, missing=True, entropy_args={}):
"""Compute the log-probability of the missing (or spurious if ``missing=False``)
edges given by ``edge_list`` (a list of ``(source, target)`` tuples, or
:meth:`~graph_tool.Edge` instances). The values in ``entropy_args`` are
passed to :meth:`graph_tool.NestedBlockState.entropy()` to calculate the
def get_edges_prob(self, missing, spurious=[], entropy_args={}):
"""Compute the joint log-probability of the missing and spurious edges given by
``missing`` and ``spurious`` (a list of ``(source, target)``
tuples, or :meth:`~graph_tool.Edge` instances), together with the
observed edges.
More precisely, the log-likelihood returned is
.. math::
\ln P(\boldsymbol G + \delta \boldsymbol G | \boldsymbol b)
where :math:`\boldsymbol G + \delta \boldsymbol G` is the modified graph
(with missing edges added and spurious edges deleted).
The values in ``entropy_args`` are passed to
:meth:`graph_tool.BlockState.entropy()` to calculate the
log-probability.
"""
L = 0
for l, lstate in enumerate(self.levels):
if l > 0:
......@@ -329,11 +342,14 @@ class NestedBlockState(object):
lstate._state.sync_emat()
lstate._state.clear_egroups()
L += lstate.get_edges_prob(edge_list, missing, entropy_args=eargs)
L += lstate.get_edges_prob(missing, spurious, entropy_args=eargs)
if isinstance(self.levels[0], LayeredBlockState):
edge_list = [(lstate.b[u], lstate.b[v], l) for u, v, l in edge_list]
missing = [(lstate.b[u], lstate.b[v], l_) for u, v, l_ in missing]
spurious = [(lstate.b[u], lstate.b[v], l_) for u, v, l_ in spurious]
else:
edge_list = [(lstate.b[u], lstate.b[v]) for u, v in (tuple(e_) for e_ in edge_list)]
missing = [(lstate.b[u], lstate.b[v]) for u, v in missing]
spurious = [(lstate.b[u], lstate.b[v]) for u, v in spurious]
return L
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment