Commit 2d134e6d authored by Tiago Peixoto's avatar Tiago Peixoto

Implement bipartite maximum weighted matching

parent cc5d0046
......@@ -11,8 +11,6 @@
#define BOOST_GRAPH_MAXIMUM_WEIGHTED_MATCHING_HPP
#include <algorithm> // for std::iter_swap
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/graph/max_cardinality_matching.hpp>
namespace boost
......@@ -80,7 +78,7 @@ namespace boost
{
public:
typedef boost::shared_ptr<blossom> blossom_ptr_t;
typedef std::shared_ptr<blossom> blossom_ptr_t;
std::vector<blossom_ptr_t> sub_blossoms;
edge_property_t dual_var;
blossom_ptr_t father;
......@@ -148,7 +146,7 @@ namespace boost
vertex_descriptor_t trivial_vertex;
};
typedef boost::shared_ptr<blossom> blossom_ptr_t;
typedef std::shared_ptr<blossom> blossom_ptr_t;
typedef typename std::vector<blossom_ptr_t>::iterator blossom_iterator_t;
typedef typename map_vertex_to_<blossom_ptr_t>::type vertex_to_blossom_map_t;
......@@ -190,8 +188,11 @@ namespace boost
{
edge_property_t w = get(weight, *ei);
max_weight = std::max(max_weight, w);
if (abs(w) > 0)
min_abs = std::min(min_abs, edge_property_t(abs(w)));
if constexpr (std::is_floating_point_v<edge_property_t>)
{
if (abs(w) > 0)
min_abs = std::min(min_abs, edge_property_t(abs(w)));
}
}
typename std::vector<std::vector<std::pair<edge_descriptor_t, bool> > >::iterator vei;
......@@ -201,7 +202,7 @@ namespace boost
vertex_descriptor_t u = *vi;
mate[u] = get(arg_mate, u);
dual_var[u] = 2 * max_weight;
in_blossom[u] = boost::make_shared<trivial_blossom>(u);
in_blossom[u] = std::make_shared<trivial_blossom>(u);
outlet[u] = u;
critical_edge_vector.push_back(vertex_to_edge_map_t(vei->begin(), vm));
}
......@@ -721,7 +722,7 @@ namespace boost
is_old_base[*vi] = true;
}
blossom_ptr_t b = boost::make_shared<blossom>();
blossom_ptr_t b = std::make_shared<blossom>();
add_sub_blossom(b, nca);
label_T[w_prime] = v;
......
......@@ -46,6 +46,7 @@ libgraph_tool_topology_la_SOURCES = \
libgraph_tool_topology_la_include_HEADERS = \
graph_bipartite_weighted_matching.hh \
graph_components.hh \
graph_kcore.hh \
graph_maximal_cliques.hh \
......
This diff is collapsed.
......@@ -22,6 +22,8 @@
#include <boost/graph/max_cardinality_matching.hpp>
#include <boost/graph/maximum_weighted_matching.hpp>
#include "graph_bipartite_weighted_matching.hh"
using namespace std;
using namespace boost;
using namespace graph_tool;
......@@ -99,7 +101,43 @@ void get_max_weighted_matching(GraphInterface& gi, boost::any oweight,
matching[v] = match[v];
}
},
writable_edge_scalar_properties())(oweight);
edge_scalar_properties())(oweight);
}
void get_max_bip_weighted_matching(GraphInterface& gi, boost::any opartition,
boost::any oweight, boost::any omatching)
{
typedef typename vprop_map_t<int64_t>::type vprop_t;
vprop_t::unchecked_t matching = any_cast<vprop_t>(omatching).get_unchecked();
typedef UnityPropertyMap<int, GraphInterface::edge_t> ecmap_t;
typedef boost::mpl::push_back<edge_scalar_properties, ecmap_t>::type
weight_props_t;
if (oweight.empty())
oweight = ecmap_t();
run_action<graph_tool::detail::never_directed>()
(gi,
[&](auto& g, auto part, auto w)
{
typedef std::remove_reference_t<decltype(g)> g_t;
typedef typename graph_traits<g_t>::vertex_descriptor vertex_t;
typename vprop_map_t<vertex_t>::type match(get(vertex_index,g));
maximum_bipartite_weighted_matching(g, part, w, match);
for (auto v : vertices_range(g))
{
if (match[v] == graph_traits<g_t>::null_vertex())
matching[v] = std::numeric_limits<int64_t>::max();
else
matching[v] = match[v];
}
},
vertex_properties(), weight_props_t())(opartition, oweight);
}
void match_edges(GraphInterface& gi, boost::any omatching,
......@@ -132,5 +170,6 @@ void export_matching()
{
def("get_max_matching", &get_max_matching);
def("get_max_weighted_matching", &get_max_weighted_matching);
def("get_max_bip_weighted_matching", &get_max_bip_weighted_matching);
def("match_edges", &match_edges);
}
......@@ -2933,32 +2933,36 @@ def is_DAG(g):
return is_DAG
def max_cardinality_matching(g, weight=None, init_match="extra_greedy",
heuristic=False, minimize=False, edges=False,
brute_force=False):
def max_cardinality_matching(g, weight=None, bipartite=False,
init_match="extra_greedy", heuristic=False,
minimize=False, edges=False, brute_force=False):
r"""Find a maximum cardinality matching in the graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
weight : :class:`~graph_tool.EdgePropertyMap` (optional, default: `None`)
weight : :class:`~graph_tool.EdgePropertyMap` (optional, default: ``None``)
If provided, the matching will maximize the sum of edge weights.
init_match : string (optional, default: ``"extra_greedy"``)
bipartite : ``bool`` or :class:`~graph_tool.VertexPropertyMap` (optional, default: ``False``)
If ``True``, the graph will be assumed to be bipartite. If a
:class:`~graph_tool.VertexPropertyMap` is passed, it should correspond
to an existing bi-partition.
init_match : ``string`` (optional, default: ``"extra_greedy"``)
Initial matching strategy. Can be one of: `"empty"`, `"greedy"`,
`"extra_greedy"`. Ignored if ``weight`` is given, or
``heuristic == True``.
minimize : bool (optional, default: `True`)
If `True`, the matching will minimize the weights, otherwise they will
minimize : ``bool`` (optional, default: ``True``)
If ``True``, the matching will minimize the weights, otherwise they will
be maximized. This option has no effect if ``heuristic == False``.
heuristic : bool (optional, default: `False`)
If `True`, a random heuristic will be used, which runs in linear time.
edges : bool (optional, default: `False`)
If `True`, an edge property map will be returned, instead of a vertex
heuristic : ``bool`` (optional, default: ``False``)
If ``True``, a random heuristic will be used, which runs in linear time.
edges : ``bool`` (optional, default: ``False``)
If ``True``, an edge property map will be returned, instead of a vertex
property map.
brute_force : bool (optional, default: `False`)
If `True`, and `weight` is not `None` and `heuristic` is `False`, a
slower, brute-force algorithm is used.
brute_force : ``bool`` (optional, default: ``False``)
If ``True``, and ``weight`` is not ``None`` and ``heuristic`` is
``False``, a slower, brute-force algorithm is used.
Returns
-------
......@@ -3033,15 +3037,28 @@ def max_cardinality_matching(g, weight=None, init_match="extra_greedy",
u = GraphView(g, directed=False)
if not heuristic:
if weight is None:
libgraph_tool_topology.\
get_max_matching(u._Graph__graph, init_match,
_prop("v", u, match))
if bipartite is False:
if weight is None:
libgraph_tool_topology.\
get_max_matching(u._Graph__graph, init_match,
_prop("v", u, match))
else:
libgraph_tool_topology.\
get_max_weighted_matching(u._Graph__graph,
_prop("e", u, weight),
_prop("v", u, match), brute_force)
else:
if isinstance(bipartite, VertexPropertyMap):
partition = bipartite
else:
is_bip, partition = is_bipartite(u, partition=True)
if not is_bip:
raise ValueError("Supplied graph is not bipartite")
libgraph_tool_topology.\
get_max_weighted_matching(u._Graph__graph,
_prop("e", u, weight),
_prop("v", u, match), brute_force)
get_max_bip_weighted_matching(u._Graph__graph,
_prop("v", u, partition),
_prop("e", u, weight),
_prop("v", u, match))
else:
libgraph_tool_topology.\
random_matching(u._Graph__graph, _prop("e", u, weight),
......
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