Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Tiago Peixoto
graph-tool
Commits
a1b97fbe
Commit
a1b97fbe
authored
Mar 27, 2020
by
Tiago Peixoto
Browse files
dynamics: implement weighted versions of epidemic models
This fixes issue
#624
parent
3fb37596
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/graph/dynamics/graph_discrete.cc
View file @
a1b97fbe
...
@@ -120,7 +120,6 @@ struct add_ptr
...
@@ -120,7 +120,6 @@ struct add_ptr
};
};
};
};
template
<
class
State
>
template
<
class
State
>
void
export_state
()
void
export_state
()
{
{
...
@@ -132,31 +131,57 @@ void export_state()
...
@@ -132,31 +131,57 @@ void export_state()
});
});
}
}
template
<
template
<
bool
...>
class
Base
,
bool
...
As
>
void
export_SI_state
()
{
export_state
<
Base
<
As
...,
false
,
false
>>
();
export_state
<
Base
<
As
...,
true
,
false
>>
();
export_state
<
Base
<
As
...,
true
,
true
>>
();
}
template
<
template
<
bool
...>
class
Base
,
bool
...
As
>
python
::
object
make_SI_state
(
GraphInterface
&
gi
,
boost
::
any
as
,
boost
::
any
as_temp
,
python
::
dict
params
,
rng_t
&
rng
,
bool
weighted
,
bool
constant_beta
)
{
if
(
weighted
)
{
if
(
constant_beta
)
return
make_state
<
Base
<
As
...,
true
,
true
>>
(
gi
,
as
,
as_temp
,
params
,
rng
);
else
return
make_state
<
Base
<
As
...,
true
,
false
>>
(
gi
,
as
,
as_temp
,
params
,
rng
);
}
else
{
return
make_state
<
Base
<
As
...,
false
,
false
>>
(
gi
,
as
,
as_temp
,
params
,
rng
);
}
}
void
export_discrete
()
void
export_discrete
()
{
{
export_state
<
SI_state
<
false
>
>
();
export_
SI_
state
<
SI_state
,
false
>
();
def
(
"make_SI_state"
,
&
make_state
<
SI_state
<
false
>
>
);
def
(
"make_SI_state"
,
&
make_
SI_
state
<
SI_state
,
false
>
);
export_state
<
SIS_state
<
false
,
false
>
>
();
export_
SI_
state
<
SIS_state
,
false
,
false
>
();
def
(
"make_SIS_state"
,
&
make_state
<
SIS_state
<
false
,
false
>
>
);
def
(
"make_SIS_state"
,
&
make_
SI_
state
<
SIS_state
,
false
,
false
>
);
export_state
<
SIS_state
<
false
,
true
>
>
();
export_
SI_
state
<
SIS_state
,
false
,
true
>
();
def
(
"make_SIR_state"
,
&
make_state
<
SIS_state
<
false
,
true
>
>
);
def
(
"make_SIR_state"
,
&
make_
SI_
state
<
SIS_state
,
false
,
true
>
);
export_state
<
SIRS_state
<
false
>
>
();
export_
SI_
state
<
SIRS_state
,
false
>
();
def
(
"make_SIRS_state"
,
&
make_state
<
SIRS_state
<
false
>
>
);
def
(
"make_SIRS_state"
,
&
make_
SI_
state
<
SIRS_state
,
false
>
);
export_state
<
SI_state
<
true
>
>
();
export_
SI_
state
<
SI_state
,
true
>
();
def
(
"make_SEI_state"
,
&
make_state
<
SI_state
<
true
>
>
);
def
(
"make_SEI_state"
,
&
make_
SI_
state
<
SI_state
,
true
>
);
export_state
<
SIS_state
<
true
,
false
>
>
();
export_
SI_
state
<
SIS_state
,
true
,
false
>
();
def
(
"make_SEIS_state"
,
&
make_state
<
SIS_state
<
true
,
false
>
>
);
def
(
"make_SEIS_state"
,
&
make_
SI_
state
<
SIS_state
,
true
,
false
>
);
export_state
<
SIS_state
<
true
,
true
>
>
();
export_
SI_
state
<
SIS_state
,
true
,
true
>
();
def
(
"make_SEIR_state"
,
&
make_state
<
SIS_state
<
true
,
true
>
>
);
def
(
"make_SEIR_state"
,
&
make_
SI_
state
<
SIS_state
,
true
,
true
>
);
export_state
<
SIRS_state
<
true
>
>
();
export_
SI_
state
<
SIRS_state
,
true
>
();
def
(
"make_SEIRS_state"
,
&
make_state
<
SIRS_state
<
true
>
>
);
def
(
"make_SEIRS_state"
,
&
make_
SI_
state
<
SIRS_state
,
true
>
);
export_state
<
voter_state
>
();
export_state
<
voter_state
>
();
def
(
"make_voter_state"
,
&
make_state
<
voter_state
>
);
def
(
"make_voter_state"
,
&
make_state
<
voter_state
>
);
...
...
src/graph/dynamics/graph_discrete.hh
View file @
a1b97fbe
...
@@ -21,6 +21,7 @@
...
@@ -21,6 +21,7 @@
#include
"graph.hh"
#include
"graph.hh"
#include
"graph_filtering.hh"
#include
"graph_filtering.hh"
#include
"graph_util.hh"
#include
"graph_util.hh"
#include
"graph_python_interface.hh"
#ifdef _OPENMP
#ifdef _OPENMP
#include
<omp.h>
#include
<omp.h>
#endif
#endif
...
@@ -63,36 +64,74 @@ public:
...
@@ -63,36 +64,74 @@ public:
std
::
shared_ptr
<
std
::
vector
<
size_t
>>
_active
;
std
::
shared_ptr
<
std
::
vector
<
size_t
>>
_active
;
};
};
template
<
bool
exposed
>
template
<
bool
exposed
,
bool
weighted
,
bool
constant_beta
>
class
SI_state
:
public
discrete_state_base
<>
class
SI_state
:
public
discrete_state_base
<>
{
{
public:
public:
enum
State
{
S
,
I
,
R
,
E
};
enum
State
{
S
,
I
,
R
,
E
};
typedef
typename
eprop_map_t
<
double
>::
type
::
unchecked_t
bmap_t
;
typedef
std
::
conditional_t
<
weighted
,
bmap_t
,
double
>
beta_t
;
template
<
class
Graph
,
class
RNG
>
template
<
class
Graph
,
class
RNG
>
SI_state
(
Graph
&
g
,
smap_t
s
,
smap_t
s_temp
,
python
::
dict
params
,
RNG
&
)
SI_state
(
Graph
&
g
,
smap_t
s
,
smap_t
s_temp
,
python
::
dict
params
,
RNG
&
)
:
discrete_state_base
(
s
,
s_temp
),
:
discrete_state_base
(
s
,
s_temp
),
_beta
(
python
::
extract
<
double
>
(
params
[
"beta"
])),
_epsilon
(
python
::
extract
<
double
>
(
params
[
"epsilon"
])),
_epsilon
(
python
::
extract
<
double
>
(
params
[
"epsilon"
])),
_r
(
python
::
extract
<
double
>
(
params
[
"r"
])),
_r
(
python
::
extract
<
double
>
(
params
[
"r"
])),
_m
(
num_vertices
(
g
)),
_m
(
num_vertices
(
g
)),
_m_temp
(
num_vertices
(
g
))
_m_temp
(
num_vertices
(
g
))
{
{
size_t
M
=
0
;
python
::
object
obeta
=
params
[
"beta"
];
for
(
auto
v
:
vertices_range
(
g
))
if
constexpr
(
weighted
)
{
obeta
=
obeta
.
attr
(
"_get_any"
)();
boost
::
any
&
abeta
=
python
::
extract
<
boost
::
any
&>
(
obeta
);
_beta
=
boost
::
any_cast
<
typename
beta_t
::
checked_t
>
(
abeta
).
get_unchecked
();
}
else
{
{
size_t
k
=
0
;
_beta
=
python
::
extract
<
beta_t
>
(
obeta
);
for
(
auto
w
:
in_or_out_neighbors_range
(
v
,
g
))
}
if
constexpr
(
!
weighted
)
{
size_t
M
=
0
;
for
(
auto
v
:
vertices_range
(
g
))
{
{
_m
[
v
]
+=
(
_s
[
w
]
==
State
::
I
);
size_t
k
=
0
;
++
k
;
for
(
auto
w
:
in_or_out_neighbors_range
(
v
,
g
))
{
_m
[
v
]
+=
(
_s
[
w
]
==
State
::
I
);
++
k
;
}
_m_temp
[
v
]
=
_m
[
v
];
M
=
std
::
max
(
M
,
k
);
}
for
(
size_t
m
=
0
;
m
<
M
+
1
;
++
m
)
_prob
.
push_back
(
1
-
std
::
pow
(
1
-
_beta
,
m
));
}
else
{
if
constexpr
(
constant_beta
)
{
eprop_map_t
<
double
>::
type
beta
(
get
(
edge_index_t
(),
g
));
for
(
auto
e
:
edges_range
(
g
))
beta
[
e
]
=
std
::
log1p
(
-
_beta
[
e
]);
_beta
=
beta
;
}
for
(
auto
v
:
vertices_range
(
g
))
{
for
(
auto
e
:
in_or_out_edges_range
(
v
,
g
))
{
auto
w
=
(
source
(
e
,
g
)
!=
v
)
?
source
(
e
,
g
)
:
target
(
e
,
g
);
if
(
_s
[
w
]
==
State
::
I
)
_m
[
v
]
+=
get_p
(
e
);
}
_m_temp
[
v
]
=
_m
[
v
];
}
}
_m_temp
[
v
]
=
_m
[
v
];
M
=
std
::
max
(
M
,
k
);
}
}
for
(
size_t
m
=
0
;
m
<
M
+
1
;
++
m
)
_prob
.
push_back
(
1
-
std
::
pow
(
1
-
_beta
,
m
));
};
};
template
<
class
Graph
>
template
<
class
Graph
>
...
@@ -101,23 +140,57 @@ public:
...
@@ -101,23 +140,57 @@ public:
s_out
[
v
]
=
State
::
E
;
s_out
[
v
]
=
State
::
E
;
}
}
template
<
class
Edge
>
constexpr
double
get_p
(
Edge
&
e
)
{
if
constexpr
(
constant_beta
)
return
_beta
[
e
];
else
return
std
::
log1p
(
-
_beta
[
e
]);
}
template
<
bool
sync
,
class
Graph
>
template
<
bool
sync
,
class
Graph
>
void
infect
(
Graph
&
g
,
size_t
v
,
smap_t
&
s_out
)
void
infect
(
Graph
&
g
,
size_t
v
,
smap_t
&
s_out
)
{
{
s_out
[
v
]
=
State
::
I
;
s_out
[
v
]
=
State
::
I
;
if
(
sync
)
if
constexpr
(
!
weighted
)
{
{
for
(
auto
w
:
out_neighbors_range
(
v
,
g
)
)
if
constexpr
(
sync
)
{
{
auto
&
m
=
_m_temp
[
w
];
for
(
auto
w
:
out_neighbors_range
(
v
,
g
))
#pragma omp atomic
{
m
++
;
auto
&
m
=
_m_temp
[
w
];
#pragma omp atomic
m
++
;
}
}
else
{
for
(
auto
w
:
out_neighbors_range
(
v
,
g
))
_m
[
w
]
++
;
}
}
}
}
else
else
{
{
for
(
auto
w
:
out_neighbors_range
(
v
,
g
))
if
constexpr
(
sync
)
_m
[
w
]
++
;
{
for
(
auto
e
:
out_edges_range
(
v
,
g
))
{
auto
w
=
target
(
e
,
g
);
auto
&
m
=
_m_temp
[
w
];
auto
p
=
get_p
(
e
);
#pragma omp atomic
m
+=
p
;
}
}
else
{
for
(
auto
e
:
out_edges_range
(
v
,
g
))
{
auto
w
=
target
(
e
,
g
);
_m
[
w
]
+=
get_p
(
e
);
}
}
}
}
}
}
...
@@ -150,8 +223,14 @@ public:
...
@@ -150,8 +223,14 @@ public:
auto
m
=
_m
[
v
];
auto
m
=
_m
[
v
];
std
::
bernoulli_distribution
minfect
(
_prob
[
m
]);
double
prob
=
0
;
if
(
m
>
0
&&
minfect
(
rng
))
if
constexpr
(
!
weighted
)
prob
=
_prob
[
m
];
else
prob
=
1
-
std
::
exp
(
m
);
std
::
bernoulli_distribution
minfect
(
prob
);
if
(
prob
>
0
&&
minfect
(
rng
))
{
{
if
constexpr
(
exposed
)
if
constexpr
(
exposed
)
expose
(
g
,
v
,
s_out
);
expose
(
g
,
v
,
s_out
);
...
@@ -175,27 +254,32 @@ public:
...
@@ -175,27 +254,32 @@ public:
constexpr
bool
has_absorbing
()
{
return
true
;
}
constexpr
bool
has_absorbing
()
{
return
true
;
}
protected:
protected:
double
_beta
;
beta_t
_beta
;
double
_epsilon
;
double
_epsilon
;
double
_r
;
double
_r
;
discrete_state_base
<>::
smap_t
_m
,
_m_temp
;
typedef
std
::
conditional_t
<
weighted
,
typename
vprop_map_t
<
double
>::
type
::
unchecked_t
,
discrete_state_base
<>::
smap_t
>
m_t
;
m_t
_m
,
_m_temp
;
std
::
vector
<
double
>
_prob
;
std
::
vector
<
double
>
_prob
;
};
};
template
<
bool
exposed
,
bool
recovered
>
template
<
bool
exposed
,
bool
recovered
,
bool
weighted
,
bool
constant_beta
>
class
SIS_state
:
public
SI_state
<
exposed
>
class
SIS_state
:
public
SI_state
<
exposed
,
weighted
,
constant_beta
>
{
{
public:
public:
typedef
typename
SI_state
<
exposed
>::
smap_t
smap_t
;
typedef
SI_state
<
exposed
,
weighted
,
constant_beta
>
base_t
;
typedef
typename
SI_state
<
exposed
>::
State
State
;
typedef
typename
base_t
::
smap_t
smap_t
;
using
SI_state
<
exposed
>::
_s
;
typedef
typename
base_t
::
State
State
;
using
SI_state
<
exposed
>::
_m
;
using
base_t
::
_s
;
using
SI_state
<
exposed
>::
_m_temp
;
using
base_t
::
_m
;
using
base_t
::
_m_temp
;
template
<
class
Graph
,
class
RNG
>
template
<
class
Graph
,
class
RNG
>
SIS_state
(
Graph
&
g
,
smap_t
s
,
smap_t
s_temp
,
python
::
dict
params
,
RNG
&
rng
)
SIS_state
(
Graph
&
g
,
smap_t
s
,
smap_t
s_temp
,
python
::
dict
params
,
RNG
&
rng
)
:
SI_state
<
exposed
>
(
g
,
s
,
s_temp
,
params
,
rng
),
:
base_t
(
g
,
s
,
s_temp
,
params
,
rng
),
_gamma
(
python
::
extract
<
double
>
(
params
[
"gamma"
]))
_gamma
(
python
::
extract
<
double
>
(
params
[
"gamma"
]))
{};
{};
...
@@ -203,19 +287,44 @@ public:
...
@@ -203,19 +287,44 @@ public:
void
recover
(
Graph
&
g
,
size_t
v
,
smap_t
&
s_out
)
void
recover
(
Graph
&
g
,
size_t
v
,
smap_t
&
s_out
)
{
{
s_out
[
v
]
=
recovered
?
State
::
R
:
State
::
S
;
s_out
[
v
]
=
recovered
?
State
::
R
:
State
::
S
;
if
constexpr
(
sync
)
if
constexpr
(
!
weighted
)
{
{
for
(
auto
w
:
out_neighbors_range
(
v
,
g
)
)
if
constexpr
(
sync
)
{
{
auto
&
m
=
_m_temp
[
w
];
for
(
auto
w
:
out_neighbors_range
(
v
,
g
))
#pragma omp atomic
{
m
--
;
auto
&
m
=
_m_temp
[
w
];
#pragma omp atomic
m
--
;
}
}
else
{
for
(
auto
w
:
out_neighbors_range
(
v
,
g
))
_m
[
w
]
--
;
}
}
}
}
else
else
{
{
for
(
auto
w
:
out_neighbors_range
(
v
,
g
))
if
constexpr
(
sync
)
_m
[
w
]
--
;
{
for
(
auto
e
:
out_edges_range
(
v
,
g
))
{
auto
w
=
target
(
e
,
g
);
auto
&
m
=
_m_temp
[
w
];
auto
p
=
base_t
::
get_p
(
e
);
#pragma omp atomic
m
-=
p
;
}
}
else
{
for
(
auto
e
:
out_edges_range
(
v
,
g
))
{
auto
w
=
target
(
e
,
g
);
_m
[
w
]
-=
base_t
::
get_p
(
e
);
}
}
}
}
}
}
...
@@ -232,7 +341,7 @@ public:
...
@@ -232,7 +341,7 @@ public:
}
}
return
0
;
return
0
;
}
}
return
SI_state
<
exposed
>
::
template
update_node
<
sync
>(
g
,
v
,
s_out
,
rng
);
return
base_t
::
template
update_node
<
sync
>(
g
,
v
,
s_out
,
rng
);
}
}
template
<
class
Graph
>
template
<
class
Graph
>
...
@@ -245,18 +354,18 @@ protected:
...
@@ -245,18 +354,18 @@ protected:
double
_gamma
;
double
_gamma
;
};
};
template
<
bool
exposed
>
template
<
bool
exposed
,
bool
weighted
,
bool
constant_beta
>
class
SIRS_state
:
public
SIS_state
<
exposed
,
true
>
class
SIRS_state
:
public
SIS_state
<
exposed
,
true
,
weighted
,
constant_beta
>
{
{
public:
public:
typedef
SIS_state
<
exposed
,
true
,
weighted
,
constant_beta
>
base_t
;
typedef
typename
SI_state
<
exposed
>
::
smap_t
smap_t
;
typedef
typename
base_t
::
smap_t
smap_t
;
typedef
typename
SI_state
<
exposed
>
::
State
State
;
typedef
typename
base_t
::
State
State
;
using
SI_state
<
exposed
>
::
_s
;
using
base_t
::
_s
;
template
<
class
Graph
,
class
RNG
>
template
<
class
Graph
,
class
RNG
>
SIRS_state
(
Graph
&
g
,
smap_t
s
,
smap_t
s_temp
,
python
::
dict
params
,
RNG
&
rng
)
SIRS_state
(
Graph
&
g
,
smap_t
s
,
smap_t
s_temp
,
python
::
dict
params
,
RNG
&
rng
)
:
SIS_state
<
exposed
,
true
>
(
g
,
s
,
s_temp
,
params
,
rng
),
:
base_t
(
g
,
s
,
s_temp
,
params
,
rng
),
_mu
(
python
::
extract
<
double
>
(
params
[
"mu"
]))
_mu
(
python
::
extract
<
double
>
(
params
[
"mu"
]))
{};
{};
...
@@ -274,7 +383,7 @@ public:
...
@@ -274,7 +383,7 @@ public:
}
}
return
0
;
return
0
;
}
}
return
SIS_state
<
exposed
,
true
>
::
template
update_node
<
sync
>(
g
,
v
,
s_out
,
rng
);
return
base_t
::
template
update_node
<
sync
>(
g
,
v
,
s_out
,
rng
);
}
}
template
<
class
Graph
>
template
<
class
Graph
>
...
...
src/graph/graph_python_interface.cc
View file @
a1b97fbe
...
@@ -805,6 +805,11 @@ void do_add_edge_list_hashed(GraphInterface& gi, python::object aedge_list,
...
@@ -805,6 +805,11 @@ void do_add_edge_list_hashed(GraphInterface& gi, python::object aedge_list,
void
do_add_edge_list_iter
(
GraphInterface
&
gi
,
python
::
object
edge_list
,
void
do_add_edge_list_iter
(
GraphInterface
&
gi
,
python
::
object
edge_list
,
python
::
object
eprops
);
python
::
object
eprops
);
bool
hasattr
(
boost
::
python
::
object
obj
,
std
::
string
const
&
attrName
)
{
return
PyObject_HasAttrString
(
obj
.
ptr
(),
attrName
.
c_str
());
}
}
// namespace graph_tool
}
// namespace graph_tool
// register everything
// register everything
...
...
src/graph/graph_python_interface.hh
View file @
a1b97fbe
...
@@ -738,6 +738,7 @@ private:
...
@@ -738,6 +738,7 @@ private:
std
::
istream
&
_s
;
std
::
istream
&
_s
;
};
};
bool
hasattr
(
boost
::
python
::
object
obj
,
std
::
string
const
&
attrName
);
}
//graph_tool namespace
}
//graph_tool namespace
...
...
src/graph/inference/uncertain/graph_blockmodel_dynamics_continuous.hh
View file @
a1b97fbe
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include
<vector>
#include
<vector>
#include
"graph_blockmodel_dynamics.hh"
#include
"graph_blockmodel_dynamics.hh"
#include
"graph_python_interface.hh"
namespace
graph_tool
namespace
graph_tool
{
{
...
@@ -234,8 +235,6 @@ double l2sinha(T x) // log((exp(x) - exp(-x))/x)
...
@@ -234,8 +235,6 @@ double l2sinha(T x) // log((exp(x) - exp(-x))/x)
return
x
+
log1p
(
-
exp
(
-
2
*
x
))
-
log
(
x
);
return
x
+
log1p
(
-
exp
(
-
2
*
x
))
-
log
(
x
);
}
}
bool
hasattr
(
boost
::
python
::
object
obj
,
std
::
string
const
&
attrName
);
class
CIsingBaseState
class
CIsingBaseState
{
{
public:
public:
...
...
src/graph/inference/uncertain/graph_blockmodel_dynamics_discrete.hh
View file @
a1b97fbe
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include
<vector>
#include
<vector>
#include
"graph_blockmodel_dynamics.hh"
#include
"graph_blockmodel_dynamics.hh"
#include
"graph_python_interface.hh"
namespace
graph_tool
namespace
graph_tool
{
{
...
@@ -697,8 +698,6 @@ double l1p2cosh(T x) // log(1 + exp(x) + exp(-x))
...
@@ -697,8 +698,6 @@ double l1p2cosh(T x) // log(1 + exp(x) + exp(-x))
}
}
bool
hasattr
(
boost
::
python
::
object
obj
,
std
::
string
const
&
attrName
);
class
IsingBaseState
class
IsingBaseState
{
{
public:
public:
...
...
src/graph/inference/uncertain/graph_blockmodel_dynamics_pseudo_ising.cc
View file @
a1b97fbe
...
@@ -60,14 +60,6 @@ python::object make_pseudo_ising_state(boost::python::object oblock_state,
...
@@ -60,14 +60,6 @@ python::object make_pseudo_ising_state(boost::python::object oblock_state,
return
state
;
return
state
;
}
}
namespace
graph_tool
{
bool
hasattr
(
boost
::
python
::
object
obj
,
std
::
string
const
&
attrName
)
{
return
PyObject_HasAttrString
(
obj
.
ptr
(),
attrName
.
c_str
());
}
}
void
export_pseudo_ising_state
()
void
export_pseudo_ising_state
()
{
{
using
namespace
boost
::
python
;
using
namespace
boost
::
python
;
...
...
src/graph/inference/uncertain/graph_blockmodel_dynamics_pseudo_ising_mcmc_h.hh
View file @
a1b97fbe
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
#include
"graph_tool.hh"
#include
"graph_tool.hh"
#include
"../support/graph_state.hh"
#include