<tb@panthema.net>
<http://www.gnu.org/licenses/>
#ifndef BISPANNING_GRAPH_EIGEN_HEADER
#define BISPANNING_GRAPH_EIGEN_HEADER
#include "debug.h"
#include "graph.h"
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>
template <typename GraphType>
class AlgExpansion
{
public:
static const bool debug = false;
const GraphType& m_g;
std::vector<char> m_mark;
double m_expansion;
void test(size_t c)
{
DBG(vector_join(m_mark, " "));
size_t border = 0;
for (auto e = m_g.edge_begin(); e != m_g.edge_end(); ++e)
{
if (m_mark[e.head_id()] + m_mark[e.tail_id()] == 1)
++border;
}
DBG("border: " << border << ", exp " << border / static_cast<double>(c));
m_expansion = std::min(m_expansion, border / static_cast<double>(c));
}
void recurse(unsigned int p, size_t c)
{
if (c > m_mark.size() / 2) return;
if (c != 0) test(c);
for (unsigned int i = p; i < m_mark.size(); ++i)
{
assert(m_mark[i] == 0);
m_mark[i] = 1;
recurse(i + 1, c + 1);
m_mark[i] = 0;
}
}
explicit AlgExpansion(const GraphType& g)
: m_g(g),
m_mark(g.num_vertex(), 0),
m_expansion(std::numeric_limits<double>::max())
{
recurse(0, 0);
DBG("edge expansion: " << m_expansion);
}
};
template <typename GraphType>
void calcExpansionParameters(const GraphType& g, bool debug = false, bool result = true)
{
using namespace Eigen;
MatrixXf m(g.num_vertex(), g.num_vertex());
m.setZero();
for (typename GraphType::const_edge_iterator e = g.edge_begin();
e != g.edge_end(); ++e)
{
m(e.head_id(), e.tail_id()) = 1;
m(e.tail_id(), e.head_id()) = 1;
}
DBG(m);
SelfAdjointEigenSolver<MatrixXf> eigensolver(m);
if (eigensolver.info() != Success) {
std::cerr << "Error calculating eigenvalues\n";
return;
}
VectorXf ev = eigensolver.eigenvalues();
DBG2(debug, "eigenvalues:");
for (int i = 0; i < ev.size(); ++i)
{
DBG2(debug, " " << ev(ev.size() - 1 - i));
if (result && 0)
std::cout << " eigen" << i << "=" << ev(ev.size() - 1 - i);
}
DBG3(debug, "\n");
DBG("spectral gap: " << (ev(ev.size() - 1) - ev(ev.size() - 2)));
if (result)
std::cout << " spectral_gap=" << (ev(ev.size() - 1) - ev(ev.size() - 2));
if (1)
{
DBG("edge expansion: " << AlgExpansion<GraphType>(g).m_expansion);
if (result)
std::cout << " expansion=" << AlgExpansion<GraphType>(g).m_expansion;
}
int reg = g.get_regularity();
DBG("regularity: " << reg);
if (reg > 0 && debug)
{
float lambda2 = ev(ev.size() - 2);
float lambda = std::max(fabs(lambda2), fabs(ev(0)));
std::cout << "expansion bounds: " << (reg - lambda2) / 2 << " and " << sqrt(2 * reg * (reg - lambda2)) << "\n";
std::cout << "Ramanujan: " << lambda << " <=? " << (2 * sqrt(reg - 1)) << "\n";
}
}
#endif