158 lines
4.3 KiB
C++
158 lines
4.3 KiB
C++
/*
|
|
LA: linear algebra C++ interface library
|
|
Copyright (C) 2023 Jiri Pittner <jiri.pittner@jh-inst.cas.cz> or <jiri@pittnerovi.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
//this is a haphazard collection of graph theoretical algorithms I happened to need
|
|
|
|
#include "graph.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
namespace LA {
|
|
|
|
template<typename G>
|
|
NRVec<int> neighbors(const G &adjacency, const int v)
|
|
{
|
|
if(v<0||v>=adjacency.nrows()) laerror("invalid vertex number in neighbors");
|
|
int n=0;
|
|
for(int i=0; i<adjacency.nrows(); ++i) if(adjacency(v,i) && v!=i) ++n;
|
|
int ii=0;
|
|
NRVec<int> r(n);
|
|
for(int i=0; i<adjacency.nrows(); ++i) if(adjacency(v,i) && v!=i) r[ii++]=i;
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
template<typename G>
|
|
NRVec<int> nonneighbors(const G &adjacency, const int v)
|
|
{
|
|
if(v<0||v>=adjacency.nrows()) laerror("invalid vertex number in nonneighbors");
|
|
int n=0;
|
|
for(int i=0; i<adjacency.nrows(); ++i) if(!adjacency(v,i) && v!=i) ++n;
|
|
int ii=0;
|
|
NRVec<int> r(n);
|
|
for(int i=0; i<adjacency.nrows(); ++i) if(!adjacency(v,i) && v!=i) r[ii++]=i;
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
//heuristic algorithm by Boppana and Halldorsson, BIT 32, 180, (1992)
|
|
template<typename G>
|
|
NRVec<int> findclique(const G &adjacency, const int v)
|
|
{
|
|
NRVec<int> r(0);
|
|
if(adjacency.nrows())
|
|
{
|
|
if(v<0||v>=adjacency.nrows()) laerror("invalid vertex number in findclique");
|
|
NRVec<int> neighb = neighbors(adjacency,v);
|
|
NRVec<int> nonneighb = nonneighbors(adjacency,v);
|
|
NRVec<int> c1(0),c2(0);
|
|
if(neighb.size())
|
|
{
|
|
G subg1 = adjacency.submatrix(neighb);
|
|
c1 = findclique(subg1);
|
|
//reindex to original graph
|
|
for(int i=0; i<c1.size(); ++i) c1[i] = neighb[c1[i]];
|
|
}
|
|
if(nonneighb.size())
|
|
{
|
|
G subg2 = adjacency.submatrix(nonneighb);
|
|
c2 = findclique(subg2);
|
|
//reindex to original graph
|
|
for(int i=0; i<c2.size(); ++i) c2[i] = nonneighb[c2[i]];
|
|
}
|
|
c1.append(v);
|
|
c1.sort();
|
|
c2.sort();
|
|
if(c1.size()>=c2.size()) r=c1; else r=c2;
|
|
}
|
|
return (r);
|
|
}
|
|
|
|
|
|
template<typename G>
|
|
NRVec<int> complement(const G &adjacency, const NRVec<int> & vertexlist)
|
|
{
|
|
int n=adjacency.nrows();
|
|
NRVec<char> occ(n);
|
|
occ.clear();
|
|
for(int i=0; i<vertexlist.size(); ++i)
|
|
{
|
|
if(vertexlist[i]<0||vertexlist[i]>=n) laerror("illegal vertex in complement");
|
|
occ[vertexlist[i]]=1;
|
|
}
|
|
int m=0;
|
|
for(int i=0; i<n; ++i) if(!occ[i]) ++m;
|
|
NRVec<int> r(m);
|
|
m=0;
|
|
for(int i=0; i<n; ++i) if(!occ[i]) r[m++]=i;
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
//found cliques releatedly until the whole graph is covered
|
|
//could be recursive but we made it iterative
|
|
template<typename G>
|
|
NRVec<int> cliquecover(const G &adjacency, int *ncliques)
|
|
{
|
|
int n=adjacency.nrows();
|
|
NRVec<int> r(n); r.clear();
|
|
G graph = adjacency;
|
|
int cliquenumber=0;
|
|
int remaining=n;
|
|
NRVec<int> cliques(0);
|
|
NRVec<int> notincliques(n);
|
|
for(int i=0; i<n; ++i) notincliques[i]=i;
|
|
while(remaining)
|
|
{
|
|
NRVec<int> clique = findclique(graph);
|
|
NRVec<int> cliqueorignum(clique.size());
|
|
for(int i=0; i<clique.size(); ++i) cliqueorignum[i] = notincliques[clique[i]];
|
|
cliques.concatme(cliqueorignum);
|
|
++cliquenumber;
|
|
for(int i=0; i<clique.size(); ++i) r[cliqueorignum[i]] = cliquenumber;
|
|
notincliques = complement(adjacency,cliques);
|
|
remaining=notincliques.size();
|
|
if(remaining)
|
|
{
|
|
graph= adjacency.submatrix(notincliques);
|
|
}
|
|
}
|
|
if(ncliques) *ncliques = cliquenumber;
|
|
return r;
|
|
}
|
|
|
|
|
|
//force instantization
|
|
#define INSTANTIZE(T) \
|
|
template NRVec<int> neighbors(const NRSMat<T> &adjacency, const int v); \
|
|
template NRVec<int> nonneighbors(const NRSMat<T> &adjacency, const int v); \
|
|
template NRVec<int> findclique(const NRSMat<T> &adjacency, const int v); \
|
|
template NRVec<int> complement(const NRSMat<T> &adjacency, const NRVec<int> & vertexlist); \
|
|
template NRVec<int> cliquecover(const NRSMat<T> &adjacency, int *ncliques); \
|
|
|
|
|
|
|
|
INSTANTIZE(char)
|
|
|
|
}//namespace
|