2303 lines
85 KiB
C++
2303 lines
85 KiB
C++
#include "../Utils/leak_detector.h"
|
||
|
||
#include <algorithm>
|
||
#include <string>
|
||
#include <assert.h>
|
||
#include <chrono>
|
||
#include <vector>
|
||
#include <queue>
|
||
#include <map>
|
||
#include <set>
|
||
#include <tuple>
|
||
#include <limits.h>
|
||
|
||
#if _WIN32 && NDEBUG && __BOOST
|
||
#include <boost/thread.hpp>
|
||
#endif
|
||
extern int passDone;
|
||
|
||
#include "Cycle.h"
|
||
#include "Arrays.h"
|
||
#include "Array.h"
|
||
#include "../Utils/errors.h"
|
||
#include "../Utils/utils.h"
|
||
#include "../VisualizerCalls/get_information.h"
|
||
#include "../VisualizerCalls/SendMessage.h"
|
||
|
||
#include "GraphCSR.h"
|
||
|
||
using std::vector;
|
||
using std::queue;
|
||
using std::map;
|
||
using std::set;
|
||
using std::pair;
|
||
using std::make_pair;
|
||
using std::tuple;
|
||
using std::string;
|
||
using std::wstring;
|
||
using namespace std::chrono;
|
||
|
||
enum { WHITE, GREY, BLACK };
|
||
enum { CONFLICT_TYPE_1, CONFLICT_TYPE_2 };
|
||
|
||
#define MIN_CYCLE_DIM 2
|
||
#define PRINT_TIMES 1
|
||
|
||
namespace Distribution
|
||
{
|
||
template<typename vType, typename wType, typename attrType>
|
||
vType GraphCSR<vType, wType, attrType>::
|
||
GetLocalVNum(const vType &V, bool &ifNew)
|
||
{
|
||
vType localV;
|
||
if (V >= (vType)localIdx.size())
|
||
{
|
||
localV = lastNumOfV;
|
||
if ((vType)localIdx.size() <= V)
|
||
{
|
||
vType oldSize = (vType)localIdx.size();
|
||
localIdx.resize(V + 1);
|
||
for (vType i = oldSize; i < (vType)localIdx.size(); ++i)
|
||
localIdx[i] = -1;
|
||
}
|
||
localIdx[V] = localV;
|
||
globalIdx.push_back(V);
|
||
lastNumOfV++;
|
||
ifNew = true;
|
||
}
|
||
else
|
||
{
|
||
if (localIdx[V] == -1)
|
||
{
|
||
localV = lastNumOfV;
|
||
lastNumOfV++;
|
||
localIdx[V] = localV;
|
||
globalIdx.push_back(V);
|
||
ifNew = true;
|
||
}
|
||
else
|
||
{
|
||
localV = localIdx[V];
|
||
ifNew = false;
|
||
}
|
||
}
|
||
|
||
return localV;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
AddEdgeToGraph(const vType &V1, const vType &V2, const wType &W, const attrType &attr, const bool &ifNew, const uint8_t linkType_)
|
||
{
|
||
if (!ifNew)
|
||
{
|
||
for (vType i = V1 + 1; i < numVerts + 1; ++i)
|
||
neighbors[i]++;
|
||
}
|
||
else
|
||
{
|
||
if (neighbors.size() == 0)
|
||
{
|
||
neighbors.push_back(0);
|
||
neighbors.push_back(1);
|
||
}
|
||
else
|
||
neighbors.push_back(neighbors.back() + 1);
|
||
numVerts++;
|
||
}
|
||
|
||
edges.insert(edges.begin() + neighbors[V1], V2);
|
||
weights.insert(weights.begin() + neighbors[V1], W);
|
||
attributes.insert(attributes.begin() + neighbors[V1], attr);
|
||
linkType.insert(linkType.begin() + neighbors[V1], linkType_);
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
IncreaseWeight(const int &idx, const int &idxRev, const wType &W)
|
||
{
|
||
weights[idx] += W;
|
||
weights[idxRev] += W;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
CheckExist(const vType &V1, const vType &V2, const attrType &attr, const bool &ifNew, const uint8_t &linkTypeIn)
|
||
{
|
||
int ifExist = -1;
|
||
if (!ifNew)
|
||
{
|
||
auto currNeigh = neighbors.data();
|
||
auto currEdges = edges.data();
|
||
auto currAttr = attributes.data();
|
||
auto currLinks = linkType.data();
|
||
|
||
for (vType i = currNeigh[V1]; i < currNeigh[V1 + 1]; ++i)
|
||
{
|
||
const vType k = currEdges[i];
|
||
if (k == V2 && attr == currAttr[i] && linkTypeIn == currLinks[i])
|
||
{
|
||
ifExist = (int)i;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return ifExist;
|
||
}
|
||
|
||
//old algorithm without sort in the fly
|
||
//TODO: need to update
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
FindLoop(vector<Cycle<vType, wType, attrType>> &cycles, const vType V, const vType VPrev)
|
||
{
|
||
/*color[V] = GREY;
|
||
for (vType i = neighbors[V]; i < neighbors[V + 1]; ++i)
|
||
{
|
||
vType k = edges[i];
|
||
if (k == VPrev)
|
||
continue;
|
||
|
||
if (color[k] == WHITE)
|
||
{
|
||
activeV.push_back(k);
|
||
activeArcs.push_back(make_pair(weights[i], attributes[i]));
|
||
|
||
FindLoop(cycles, k, V);
|
||
|
||
activeV.pop_back();
|
||
activeArcs.pop_back();
|
||
}
|
||
else if (color[k] == GREY && k == findFrom)
|
||
{
|
||
activeArcs.push_back(make_pair(weights[i], attributes[i]));
|
||
|
||
auto idx = activeV.end();
|
||
auto idxVal = activeArcs.end();
|
||
Cycle<vType, wType, attrType> newLoop;
|
||
|
||
idx--;
|
||
idxVal--;
|
||
vType last = globalIdx[k];
|
||
while (*idx != k)
|
||
{
|
||
newLoop.AddArc(last, globalIdx[*idx], (*idxVal), 0);
|
||
last = globalIdx[*idx];
|
||
idxVal--;
|
||
idx--;
|
||
}
|
||
newLoop.AddArc(last, globalIdx[k], (*idxVal), 0);
|
||
cycles.push_back(newLoop);
|
||
//cyclesNum++;
|
||
activeArcs.pop_back();
|
||
}
|
||
}
|
||
color[V] = WHITE;*/
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
FindLoop(vector<map<vector<unsigned>, Cycle<vType, wType, attrType>>> &cycles,
|
||
const vType V, const vType VPrev, const vector<vType> &numbers)
|
||
{
|
||
if (activeCounter > maxChainLen)
|
||
return;
|
||
|
||
color[V] = GREY;
|
||
createNeededException();
|
||
|
||
for (vType i = neighbors[V]; i < neighbors[V + 1]; ++i)
|
||
{
|
||
vType k = edges[i];
|
||
if (k == VPrev)
|
||
continue;
|
||
|
||
if (color[k] == WHITE)
|
||
{
|
||
activeV[activeCounter] = k;
|
||
activeE[activeCounter] = numbers[i];
|
||
activeArcs[activeCounter] = make_pair(weights[i], attributes[i]);
|
||
activeCounter++;
|
||
|
||
FindLoop(cycles, k, V, numbers);
|
||
|
||
activeCounter--;
|
||
}
|
||
else if (color[k] == GREY && k == findFrom)
|
||
{
|
||
activeArcs[activeCounter] = make_pair(weights[i], attributes[i]);
|
||
activeE[activeCounter] = numbers[i];
|
||
|
||
|
||
int idx = activeCounter - 1;
|
||
int idxE = activeCounter;
|
||
int idxVal = activeCounter;
|
||
Cycle<vType, wType, attrType> newLoop;
|
||
|
||
vector<unsigned> shortBitLoop(numEdges / (2 * 32) + 1);
|
||
vType last = k;
|
||
//int dim = 0;
|
||
while (activeV[idx] != k)
|
||
{
|
||
//dim++;
|
||
const unsigned position = activeE[idxE];
|
||
shortBitLoop[position / 32] |= (1 << (position % 32));
|
||
|
||
newLoop.AddArc(activeV[idx], last, activeArcs[idxVal], position);
|
||
last = activeV[idx];
|
||
|
||
idxVal--;
|
||
idxE--;
|
||
idx--;
|
||
}
|
||
//dim++;
|
||
const unsigned position = activeE[idxE];
|
||
shortBitLoop[position / 32] |= (1 << (position % 32));
|
||
|
||
newLoop.AddArc(k, last, activeArcs[idxVal], position);
|
||
const int currDimSize = newLoop.GetNumArcs();
|
||
|
||
if (currDimSize <= maxLoopDim)
|
||
{
|
||
auto itFound = cycles[currDimSize].find(shortBitLoop);
|
||
if (itFound == cycles[currDimSize].end())
|
||
{
|
||
usedMem += sizeof(unsigned) * shortBitLoop.capacity() + newLoop.getFullSize() + sizeof(void*);
|
||
if (usedMem > maxAvailMemory && maxAvailMemory > 0)
|
||
{
|
||
printf("used %lld maxAvail %lld\n", usedMem, maxAvailMemory);
|
||
fflush(NULL);
|
||
throw -2;
|
||
}
|
||
cycles[currDimSize].insert(itFound, make_pair(shortBitLoop, newLoop));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
color[V] = WHITE;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
RemoveDuplicates(vector<Cycle<vType, wType, attrType>> &cycles)
|
||
{
|
||
auto timeR = steady_clock::now();
|
||
__spf_print(PRINT_TIMES, "PROF: RemoveDuplicates: start removing with %d cycles\n", (int)cycles.size());
|
||
|
||
vector<vector<pair<pair<vType, vType>, attrType>>> allUniqEdges(cycles.size());
|
||
//map<int, int> sizes;
|
||
vector<int> parts;
|
||
parts.push_back(0);
|
||
int lastSize = cycles[0].GetNumArcs();
|
||
|
||
int maxSize = 0;
|
||
for (vType i = 0; i < (vType)cycles.size(); ++i)
|
||
{
|
||
if (lastSize != cycles[i].GetNumArcs())
|
||
{
|
||
parts.push_back(i);
|
||
lastSize = cycles[0].GetNumArcs();
|
||
}
|
||
//sizes[cycles[i].GetNumArcs()]++;
|
||
maxSize = std::max(maxSize, cycles[i].GetNumArcs());
|
||
const vector<pair<vType, vType>> &currUniqArcs = cycles[i].GetArcs();
|
||
const vector<attrType> &currUniqAttrArcs = cycles[i].GetAttributesArcs();
|
||
|
||
for (vType m = 0; m < (vType)currUniqArcs.size(); ++m)
|
||
allUniqEdges[i].push_back(make_pair(currUniqArcs[m], currUniqAttrArcs[m]));
|
||
|
||
//TODO: remove multiple arcs
|
||
std::sort(allUniqEdges[i].begin(), allUniqEdges[i].end());
|
||
}
|
||
parts.push_back((int)cycles.size());
|
||
/*for (map<int, int>::iterator it = sizes.begin(); it != sizes.end(); it++)
|
||
printf("%d: %d\n", it->first, it->second);*/
|
||
|
||
maxSize++;
|
||
vector<vector<vType>> uniqLoops(maxSize);
|
||
__spf_print(PRINT_TIMES, "PROF: RemoveDuplicates: done inserting\n");
|
||
|
||
const vType part = vType((vType)cycles.size() * 0.1);
|
||
auto timeT = steady_clock::now();
|
||
//#pragma omp parallel for schedule(dynamic)
|
||
for (int p = 0; p < (int)parts.size() - 1; ++p)
|
||
{
|
||
for (vType it = parts[p]; it < parts[p + 1]; ++it)
|
||
{
|
||
if (it % part == 0 && PRINT_TIMES)
|
||
{
|
||
auto timeT1 = steady_clock::now();
|
||
__spf_print(PRINT_TIMES, "PROF: %d done with time %.3f sec\n", it, (duration_cast<duration<double>>(timeT1 - timeT)).count());
|
||
timeT = timeT1;
|
||
}
|
||
|
||
const int dimention = cycles[it].GetNumArcs();
|
||
if (uniqLoops[dimention].size() == 0)
|
||
uniqLoops[dimention].push_back(it);
|
||
else
|
||
{
|
||
const vector<pair<vType, vType>> &currArcs = cycles[it].GetArcs();
|
||
const vector<attrType> &currAttrArcs = cycles[it].GetAttributesArcs();
|
||
|
||
bool uniq = true;
|
||
for (int k = (int)uniqLoops[dimention].size() - 1; k >= 0; --k)
|
||
{
|
||
const vector<pair<pair<vType, vType>, attrType>> &edgesUniq = allUniqEdges[uniqLoops[dimention][k]];
|
||
bool sameAll = true;
|
||
for (vType m = 0; m < (vType)currArcs.size(); ++m)
|
||
{
|
||
pair<vType, vType> revCurrArcs = make_pair(currArcs[m].second, currArcs[m].first);
|
||
/*bool notFound = (edgesUniq.find(make_pair(currArcs[m], currAttrArcs[m])) == edgesUniq.end()) &&
|
||
(edgesUniq.find(make_pair(revCurrArcs, currAttrArcs[m])) == edgesUniq.end());*/
|
||
/*bool notFound = (find(edgesUniq.begin(), edgesUniq.end(), (make_pair(currArcs[m], currAttrArcs[m]))) == edgesUniq.end()) &&
|
||
(find(edgesUniq.begin(), edgesUniq.end(), (make_pair(revCurrArcs, currAttrArcs[m]))) == edgesUniq.end());*/
|
||
|
||
const pair<pair<vType, vType>, attrType> f1 = make_pair(currArcs[m], currAttrArcs[m]);
|
||
const pair<pair<vType, vType>, attrType> f2 = make_pair(revCurrArcs, currAttrArcs[m]);
|
||
bool notFound = true;
|
||
for (int t = 0; t < (int)edgesUniq.size(); ++t)
|
||
{
|
||
if (edgesUniq[t] == f1 || edgesUniq[t] == f2)
|
||
{
|
||
notFound = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (notFound)
|
||
{
|
||
sameAll = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (sameAll)
|
||
{
|
||
uniq = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (uniq)
|
||
uniqLoops[dimention].push_back(it);
|
||
}
|
||
}
|
||
}
|
||
|
||
vector<Cycle<vType, wType, attrType>> newLoops;
|
||
for (vType k = 0; k < maxSize; ++k)
|
||
for (vType i = 0; i < (vType)uniqLoops[k].size(); ++i)
|
||
newLoops.push_back(cycles[uniqLoops[k][i]]);
|
||
|
||
cycles = newLoops;
|
||
__spf_print(PRINT_TIMES, "PROF: RemoveDuplicates: done removing with %d cycles, time %f sec\n", (int)cycles.size(), (duration_cast<duration<double>>(steady_clock::now() - timeR)).count());
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
bool GraphCSR<vType, wType, attrType>::
|
||
findLink(const vType v1, pair<int, int> &inGraphAttr1, const vType v2, pair<int, int> &inGraphAttr2)
|
||
{
|
||
bool wasFound = false;
|
||
for (int k = neighbors[v1]; k < neighbors[v1 + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
if (currV == v2)
|
||
{
|
||
wasFound = true;
|
||
inGraphAttr2 = attributes[k].second;
|
||
inGraphAttr1 = attributes[k].first;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (wasFound)
|
||
return true;
|
||
else
|
||
{
|
||
for (int k = neighbors[v1]; k < neighbors[v1 + 1]; ++k)
|
||
{
|
||
if (color[edges[k]] == 1)
|
||
continue;
|
||
|
||
color[edges[k]] = 1;
|
||
wasFound = findLink(edges[k], inGraphAttr1, v2, inGraphAttr2);
|
||
|
||
if (wasFound)
|
||
{
|
||
inGraphAttr1 = attributes[k].first;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return wasFound;
|
||
}
|
||
|
||
pair<int, int> Fx(const pair<int, int> &x, const pair<int, int> &F)
|
||
{
|
||
return make_pair(x.first * F.first, x.second * F.first + F.second);
|
||
}
|
||
|
||
static pair<double, double> Fx(const pair<double, double> &x, const pair<double, double> &F)
|
||
{
|
||
return make_pair(x.first * F.first, x.second * F.first + F.second);
|
||
}
|
||
|
||
static pair<RationalNum, RationalNum> Fx(const pair<RationalNum, RationalNum> &x, const pair<RationalNum, RationalNum> &F)
|
||
{
|
||
return make_pair(x.first * F.first, x.second * F.first + F.second);
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
bool GraphCSR<vType, wType, attrType>::
|
||
hasLinkWithTempate(const vType root, const Arrays<vType> &allArrays, bool increaseLink, int newValue)
|
||
{
|
||
set<vType> next = { root };
|
||
set<vType> done;
|
||
|
||
bool found = false;
|
||
while (next.size())
|
||
{
|
||
set<vType> nextLoc;
|
||
for (auto &v1 : next)
|
||
{
|
||
Array *tmp = allArrays.GetArrayByVertex(globalIdx[v1]);
|
||
if (tmp)
|
||
{
|
||
if (tmp->IsTemplate())
|
||
{
|
||
found = true;
|
||
if (increaseLink)
|
||
{
|
||
if (neighbors[v1 + 1] - neighbors[v1] != 1)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
const int k = neighbors[v1];
|
||
|
||
const vType edgeV = edges[k];
|
||
if (newValue == 0)
|
||
attributes[k].first.first++;
|
||
else
|
||
attributes[k].first.first = newValue;
|
||
|
||
bool done = false;
|
||
for (int z = neighbors[edgeV]; z < neighbors[edgeV + 1]; ++z)
|
||
{
|
||
const vType currV = edges[z];
|
||
if (currV == v1)
|
||
{
|
||
if (newValue == 0)
|
||
attributes[z].second.first++;
|
||
else
|
||
attributes[z].second.first = newValue;
|
||
done = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!done)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (int k = neighbors[v1]; k < neighbors[v1 + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
|
||
auto it = done.find(currV);
|
||
if (it == done.end())
|
||
{
|
||
done.insert(it, currV);
|
||
nextLoc.insert(currV);
|
||
}
|
||
}
|
||
}
|
||
next = nextLoc;
|
||
}
|
||
return found;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
pair<RationalNum, RationalNum> GraphCSR<vType, wType, attrType>::
|
||
findLinkWithTempate2(const vType v1, int &templV, Array *&templ, const Arrays<vType> &allArrays, set<vType> wasDone)
|
||
{
|
||
const pair<RationalNum, RationalNum> nulPair = make_pair(0, 0);
|
||
|
||
wasDone.insert(v1);
|
||
bool wasFound = false;
|
||
for (int k = neighbors[v1]; k < neighbors[v1 + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
Array *tmp = allArrays.GetArrayByVertex(globalIdx[currV]);
|
||
if (tmp)
|
||
{
|
||
if (tmp->IsTemplate())
|
||
{
|
||
wasFound = true;
|
||
|
||
templV = globalIdx[currV];
|
||
templ = tmp;
|
||
return make_pair(attributes[k].second.first, attributes[k].second.second);
|
||
//return make_pair(1.0f, 0.0f);
|
||
}
|
||
}
|
||
}
|
||
|
||
auto it = cacheLinks.find(v1);
|
||
if (it == cacheLinks.end())
|
||
it = cacheLinks.insert(it, make_pair(v1, map<vType, tuple<int, Array*, pair<RationalNum, RationalNum>>>()));
|
||
|
||
for (int k = neighbors[v1]; k < neighbors[v1 + 1]; ++k)
|
||
{
|
||
if (wasDone.find(edges[k]) != wasDone.end())
|
||
continue;
|
||
|
||
auto ruleCache = it->second.find(edges[k]);
|
||
|
||
pair<RationalNum, RationalNum> ruleToTemplate;
|
||
if (ruleCache == it->second.end())
|
||
{
|
||
ruleToTemplate = findLinkWithTempate2(edges[k], templV, templ, allArrays, wasDone);
|
||
it->second.insert(ruleCache, make_pair(edges[k], make_tuple(templV, templ, ruleToTemplate)));
|
||
}
|
||
else
|
||
{
|
||
templV = std::get<0>(ruleCache->second);
|
||
templ = std::get<1>(ruleCache->second);
|
||
ruleToTemplate = std::get<2>(ruleCache->second);
|
||
}
|
||
|
||
if (ruleToTemplate != nulPair)
|
||
{
|
||
auto currAttribute = attributes[k];
|
||
pair<RationalNum, RationalNum> left = currAttribute.first;
|
||
pair<RationalNum, RationalNum> right = currAttribute.second;
|
||
|
||
// calculate transition
|
||
pair<RationalNum, RationalNum> X;
|
||
X.first = right.first / left.first;
|
||
|
||
left.first *= X.first;
|
||
left.second *= X.first;
|
||
|
||
X.second = right.second - left.second;
|
||
|
||
return Fx(X, ruleToTemplate);
|
||
}
|
||
}
|
||
|
||
return nulPair;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
findDimNumLink(const vType v, const Array *to, const Arrays<vType> &allArrays, set<vType> &wasDone) const
|
||
{
|
||
int foundD = -1;
|
||
int err = -1;
|
||
for (int k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
err = allArrays.GetDimNumber(to, globalIdx[currV], foundD);
|
||
if (err != -1)
|
||
break;
|
||
}
|
||
|
||
if (err != -1)
|
||
return foundD;
|
||
else
|
||
{
|
||
for (int k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
if (wasDone.find(currV) != wasDone.end())
|
||
continue;
|
||
|
||
wasDone.insert(v);
|
||
foundD = findDimNumLink(currV, to, allArrays, wasDone);
|
||
auto itToErase = wasDone.find(v);
|
||
if (itToErase != wasDone.end())
|
||
wasDone.erase(itToErase);
|
||
|
||
if (foundD != -1)
|
||
break;
|
||
}
|
||
return foundD;
|
||
}
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
AddToGraph(const vType &V1, const vType &V2, const wType &W, const attrType &attr, const uint8_t linkType)
|
||
{
|
||
if (V1 == V2)
|
||
return -1;
|
||
|
||
countRequestsToAdd++;
|
||
|
||
vType localV1, localV2;
|
||
bool ifNew1, ifNew2;
|
||
localV1 = GetLocalVNum(V1, ifNew1);
|
||
localV2 = GetLocalVNum(V2, ifNew2);
|
||
attrType attrRev = make_pair(attr.second, attr.first);
|
||
|
||
|
||
int idxExist = -1, idxExistRev = -1;
|
||
|
||
idxExist = CheckExist(localV1, localV2, attr, ifNew1, linkType);
|
||
idxExistRev = CheckExist(localV2, localV1, attrRev, ifNew2, linkType);
|
||
|
||
bool ifExist = (idxExist != -1) && (idxExistRev != -1);
|
||
|
||
int status = 0;
|
||
if (!ifExist)
|
||
{
|
||
AddEdgeToGraph(localV1, localV2, W, attr, ifNew1, linkType);
|
||
AddEdgeToGraph(localV2, localV1, W, attrRev, ifNew2, linkType);
|
||
numEdges += 2;
|
||
countMissToAdd++;
|
||
}
|
||
else
|
||
{
|
||
IncreaseWeight(idxExist, idxExistRev, W);
|
||
status = 1;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
set<vType> GraphCSR<vType, wType, attrType>::
|
||
FindTrees(vector<vType> &inTree, vector<vector<vType>> &vertByTrees)
|
||
{
|
||
inTree.resize(numVerts);
|
||
for (int i = 0; i < numVerts; ++i)
|
||
inTree[i] = i;
|
||
|
||
while (true)
|
||
{
|
||
bool mod = false;
|
||
for (int i = 0; i < numVerts; ++i)
|
||
{
|
||
for (int k = neighbors[i]; k < neighbors[i + 1]; ++k)
|
||
{
|
||
const vType V = edges[k];
|
||
if (inTree[i] != inTree[V])
|
||
{
|
||
mod = true;
|
||
if (inTree[i] < inTree[V])
|
||
inTree[V] = inTree[i];
|
||
else
|
||
inTree[i] = inTree[V];
|
||
}
|
||
}
|
||
}
|
||
if (!mod)
|
||
break;
|
||
}
|
||
|
||
set<vType> allTrees;
|
||
for (int i = 0; i < numVerts; ++i)
|
||
allTrees.insert(inTree[i]);
|
||
|
||
map<vType, vType> newIdx;
|
||
int idx = 0;
|
||
for (auto it = allTrees.begin(); it != allTrees.end(); ++it, ++idx)
|
||
newIdx.insert(make_pair(*it, idx));
|
||
|
||
vertByTrees.resize(allTrees.size());
|
||
for (int i = 0; i < numVerts; ++i)
|
||
vertByTrees[newIdx[inTree[i]]].push_back(i);
|
||
return allTrees;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
GetAllSimpleLoops(vector<vector<Cycle<vType, wType, attrType>>> &cycles, bool needPrint, bool useSavedQuality)
|
||
{
|
||
//cyclesNum = 0;
|
||
if (!useSavedQuality)
|
||
treesQuality.clear();
|
||
cycles.clear();
|
||
color.resize(numVerts);
|
||
activeCounter = 0;
|
||
|
||
activeV = new vType[std::max(numVerts, numEdges) + 1];
|
||
activeE = new vType[std::max(numVerts, numEdges) + 1];
|
||
activeArcs = new pair<wType, attrType>[std::max(numVerts, numEdges) + 1];
|
||
|
||
map<tuple<pair<vType, vType>, wType, attrType>, int> uniqArcs;
|
||
vector<vType> numbers(edges.size());
|
||
int num = 0;
|
||
|
||
for (int i = 0; i < numVerts; ++i)
|
||
{
|
||
for (int k = neighbors[i]; k < neighbors[i + 1]; ++k)
|
||
{
|
||
const vType V = edges[k];
|
||
attrType reverse = make_pair(attributes[k].second, attributes[k].first);
|
||
tuple<pair<vType, vType>, wType, attrType> tmp = std::make_tuple(make_pair(i, V), weights[k], attributes[k]);
|
||
tuple<pair<vType, vType>, wType, attrType> tmp1 = std::make_tuple(make_pair(V, i), weights[k], reverse);
|
||
auto it = uniqArcs.find(tmp);
|
||
if (it == uniqArcs.end())
|
||
{
|
||
numbers[k] = num;
|
||
uniqArcs[tmp] = num;
|
||
uniqArcs[tmp1] = num;
|
||
num++;
|
||
}
|
||
else
|
||
numbers[k] = it->second;
|
||
}
|
||
}
|
||
int maxNum = 0;
|
||
for (int i = 0; i < numEdges; ++i)
|
||
maxNum = std::max(maxNum, numbers[i]);
|
||
__spf_print(PRINT_TIMES && needPrint, "max num value = %d\n", maxNum);
|
||
|
||
auto timeFind = steady_clock::now();
|
||
__spf_print(PRINT_TIMES && needPrint, "graph size: |V| = %d, |E| = %d, quality: [%d, %d]\n", numVerts, numEdges / 2, maxLoopDim, maxChainLen);
|
||
if (maxNum + 1 != numEdges / 2 && maxNum != 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
if (numVerts == 0 && numEdges == 0)
|
||
return;
|
||
|
||
vector<vType> trees;
|
||
vector<vector<vType>> vertByTrees;
|
||
set<vType> unqieTrees = FindTrees(trees, vertByTrees);
|
||
__spf_print(PRINT_TIMES && needPrint, "trees count %d\n", (int)unqieTrees.size());
|
||
|
||
if (unqieTrees.size() == 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
vector<vector<map<vector<unsigned>, Cycle<vType, wType, attrType>>>> cyclesTmp(unqieTrees.size());
|
||
usedMem = 0;
|
||
for (int i = 0; i < unqieTrees.size(); ++i)
|
||
{
|
||
cyclesTmp[i].resize(numVerts + 1);
|
||
usedMem += cyclesTmp[i].capacity() * sizeof(map<vector<unsigned>, Cycle<vType, wType, attrType>>);
|
||
}
|
||
|
||
__spf_print(PRINT_TIMES && needPrint, "cycles find started\n");
|
||
// find all cycles with dim >= 3
|
||
try
|
||
{
|
||
for (int t = 0; t < vertByTrees.size(); ++t)
|
||
{
|
||
const int vertArraySize = vertByTrees[t].size();
|
||
int wasMaxChainLen = maxChainLen;
|
||
int wasMaxLoopDim = maxLoopDim;
|
||
|
||
int newQuality = vertArraySize * maxLoopDim / 100;
|
||
int newSpeed = vertArraySize * maxChainLen / 100;
|
||
|
||
if (newQuality < 3) newQuality = 3;
|
||
if (newSpeed < 3) newSpeed = 3;
|
||
|
||
if (!useSavedQuality)
|
||
{
|
||
maxLoopDim = newQuality;
|
||
maxChainLen = newSpeed;
|
||
|
||
treesQuality.push_back(make_pair(maxLoopDim, maxChainLen));
|
||
}
|
||
else
|
||
{
|
||
if (t < treesQuality.size())
|
||
{
|
||
maxLoopDim = treesQuality[t].first;
|
||
maxChainLen = treesQuality[t].second;
|
||
}
|
||
else
|
||
{
|
||
maxLoopDim = newQuality;
|
||
maxChainLen = newSpeed;
|
||
}
|
||
}
|
||
|
||
if (needPrint)
|
||
printf("SAPFOR: [TREE %d], arrays num %d, maxLoopDim %d, maxChainLen %d\n", t, vertArraySize, maxLoopDim, maxChainLen);
|
||
|
||
wstring treeM;
|
||
if (needPrint)
|
||
treeM = std::to_wstring(t + 1) + L"/" + std::to_wstring(vertByTrees.size());
|
||
|
||
for (int k = 0; k < vertByTrees[t].size(); ++k)
|
||
{
|
||
const vType i = vertByTrees[t][k];
|
||
const vType currentV = i;
|
||
for (vType k = 0; k < numVerts; ++k)
|
||
color[k] = WHITE;
|
||
|
||
findFrom = currentV;
|
||
#ifdef _WIN32
|
||
if (needPrint)
|
||
{
|
||
wstring vertexM = std::to_wstring(k + 1) + L"/" + std::to_wstring(vertByTrees[t].size());
|
||
sendMessage_2lvl(wstring(L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ") + wstring(treeM.begin(), treeM.end()) + L" <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> " + wstring(vertexM.begin(), vertexM.end()));
|
||
}
|
||
#endif
|
||
__spf_print(PRINT_TIMES && needPrint, "v (tree %d) = %d (with neighb %d) ", t, i, neighbors[i + 1] - neighbors[i]);
|
||
activeV[activeCounter++] = currentV;
|
||
FindLoop(cyclesTmp[t], currentV, currentV, numbers);
|
||
activeCounter--;
|
||
__spf_print(PRINT_TIMES && needPrint, "done with time %f\n", (duration_cast<duration<double>>(steady_clock::now() - timeFind)).count());
|
||
}
|
||
maxChainLen = wasMaxChainLen;
|
||
maxLoopDim = wasMaxLoopDim;
|
||
}
|
||
|
||
if (needPrint)
|
||
sendMessage_2lvl(L"");
|
||
}
|
||
catch (int code)
|
||
{
|
||
if (code == -2)
|
||
__spf_print(1, "OUT OF MEMORY: max avail %lld\n", maxAvailMemory);
|
||
throw code;
|
||
}
|
||
|
||
int minSize = INT_MAX;
|
||
int maxSize = 0;
|
||
|
||
map<int, int> countOfCycles;
|
||
cycles.resize(vertByTrees.size());
|
||
for (int t = 0; t < vertByTrees.size(); ++t)
|
||
{
|
||
map<int, int> countOfCyclesTree;
|
||
for (int i = 0; i < cyclesTmp[t].size(); ++i)
|
||
for (auto k = cyclesTmp[t][i].begin(); k != cyclesTmp[t][i].end(); ++k)
|
||
{
|
||
cycles[t].push_back(k->second);
|
||
const int len = k->second.GetNumArcs();
|
||
minSize = std::min(minSize, len);
|
||
maxSize = std::max(maxSize, len);
|
||
{
|
||
auto itF = countOfCycles.find(len);
|
||
if (itF == countOfCycles.end())
|
||
itF = countOfCycles.insert(itF, make_pair(len, 0));
|
||
itF->second++;
|
||
}
|
||
|
||
{
|
||
auto itF = countOfCyclesTree.find(len);
|
||
if (itF == countOfCyclesTree.end())
|
||
itF = countOfCyclesTree.insert(itF, make_pair(len, 0));
|
||
itF->second++;
|
||
}
|
||
}
|
||
|
||
|
||
__spf_print(PRINT_TIMES && needPrint, "FOR TREE %d\n", t);
|
||
for (auto it = countOfCyclesTree.begin(); it != countOfCyclesTree.end(); ++it)
|
||
__spf_print(PRINT_TIMES && needPrint, " found cycles with size %d = %d\n", it->first, it->second);
|
||
}
|
||
|
||
int allCycles = 0;
|
||
for (auto it = countOfCycles.begin(); it != countOfCycles.end(); ++it)
|
||
{
|
||
__spf_print(PRINT_TIMES && needPrint, "found cycles with size %d = %d\n", it->first, it->second);
|
||
allCycles += it->second;
|
||
}
|
||
|
||
delete []activeV;
|
||
delete []activeE;
|
||
delete []activeArcs;
|
||
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: num cycles %d, time of find %f s\n", allCycles, (duration_cast<duration<double>>(steady_clock::now() - timeFind)).count());
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: minimum cycle size %d, maximum cycle size %d\n", minSize, maxSize);
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
SortLoopsBySize(vector<Cycle<vType, wType, attrType>> &cycles, bool needPrint)
|
||
{
|
||
auto timeR = steady_clock::now();
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: SortLoopsBySize: start\n");
|
||
int err = 0;
|
||
vector<Cycle<vType, wType, attrType>> sortedLoops(cycles.size());
|
||
int currIdx = 0;
|
||
for (vType g = MIN_CYCLE_DIM; g <= numVerts; ++g)
|
||
{
|
||
for (vType i = 0; i < (vType)cycles.size(); ++i)
|
||
{
|
||
if (g == cycles[i].GetNumArcs())
|
||
{
|
||
sortedLoops[currIdx] = cycles[i];
|
||
currIdx++;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (cycles.size() != currIdx)
|
||
{
|
||
char buf[256];
|
||
sprintf(buf, "Can not sort cycles");
|
||
addToGlobalBufferAndPrint(buf);
|
||
|
||
err = -1;
|
||
}
|
||
else
|
||
cycles = sortedLoops;
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: SortLoopsBySize: end %f sec\n", (duration_cast<duration<double>>(steady_clock::now() - timeR)).count());
|
||
return err;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
SortLoopsByWeight(vector<Cycle<vType, wType, attrType>> &cycles, bool needPrint)
|
||
{
|
||
auto timeR = steady_clock::now();
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: SortLoopsByWeight: start\n");
|
||
|
||
if (cycles.size() == 0)
|
||
{
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: SortLoopsByWeight: end %f sec\n", (duration_cast<duration<double>>(steady_clock::now() - timeR)).count());
|
||
return 0;
|
||
}
|
||
|
||
int err = 0;
|
||
vector<Cycle<vType, wType, attrType>> sortedLoops;
|
||
vType start = 0, end = 1;
|
||
vType dim = MIN_CYCLE_DIM;
|
||
for (vType i = 1; i < (vType)cycles.size(); ++i, ++end)
|
||
{
|
||
if (cycles[i].GetNumArcs() != dim)
|
||
{
|
||
sort(cycles.begin() + start, cycles.begin() + end);
|
||
|
||
start = end;
|
||
dim = cycles[i].GetNumArcs();
|
||
}
|
||
}
|
||
if (start != end)
|
||
sort(cycles.begin() + start, cycles.begin() + end);
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: SortLoopsByWeight: end %f sec\n", (duration_cast<duration<double>>(steady_clock::now() - timeR)).count());
|
||
return err;
|
||
}
|
||
|
||
#define WITH_CONFLICT_1 1
|
||
#define WITH_CONFLICT_2 1
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
GetConflictCycles(const vector<Cycle<vType, wType, attrType>> &cycles,
|
||
const Arrays<vType> &allArrays,
|
||
vector<pair<int, int>> &indexOfConflict, bool needPrint)
|
||
{
|
||
auto timeR = steady_clock::now();
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: GetConflictCycles: start\n");
|
||
|
||
int countOfConflict = 0;
|
||
indexOfConflict.clear();
|
||
|
||
const set<Array*> &arrays = allArrays.GetArrays();
|
||
vector<bool> cycleMarked(cycles.size());
|
||
|
||
for (vType i = 0; i < (vType)cycles.size(); ++i)
|
||
{
|
||
cycleMarked[i] = false;
|
||
|
||
#if WITH_CONFLICT_1
|
||
const vector<pair<vType, vType>> &currArcs = cycles[i].GetArcs();
|
||
// check conflict of first type
|
||
map<Array*, set<vType>> uniqInfo;
|
||
for (int i1 = 0; i1 < (int)currArcs.size(); ++i1)
|
||
{
|
||
pair<int, Array*> info;
|
||
int ok = allArrays.GetInfoByVertex(globalIdx[currArcs[i1].first], info);
|
||
if (ok == 0)
|
||
{
|
||
auto it = uniqInfo.find(info.second);
|
||
if (it == uniqInfo.end())
|
||
uniqInfo.insert(it, make_pair(info.second, set<vType>()));
|
||
it->second.insert(info.first);
|
||
}
|
||
|
||
ok = allArrays.GetInfoByVertex(globalIdx[currArcs[i1].second], info);
|
||
if (ok == 0)
|
||
{
|
||
auto it = uniqInfo.find(info.second);
|
||
if (it == uniqInfo.end())
|
||
uniqInfo.insert(it, make_pair(info.second, set<vType>()));
|
||
it->second.insert(info.first);
|
||
}
|
||
}
|
||
|
||
for (auto tmpIt = uniqInfo.begin(); tmpIt != uniqInfo.end(); ++tmpIt)
|
||
{
|
||
if (tmpIt->second.size() > 1)
|
||
{
|
||
indexOfConflict.push_back(make_pair(i, CONFLICT_TYPE_1));
|
||
countOfConflict++;
|
||
cycleMarked[i] = true;
|
||
break;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#if WITH_CONFLICT_2
|
||
// check conflict of second type
|
||
if (!cycleMarked[i])
|
||
{
|
||
const vector<pair<vType, vType>> &currArcs = cycles[i].GetArcs();
|
||
const vector<attrType> &currAttributes = cycles[i].GetAttributesArcs();
|
||
|
||
// compare attributes on the same vertex
|
||
for (int i1 = 0; i1 < (int)currArcs.size(); ++i1)
|
||
{
|
||
const pair<vType, vType> &currArc = currArcs[i1];
|
||
const attrType &currAttrArc = currAttributes[i1];
|
||
|
||
pair<vType, vType> toFindArc;
|
||
attrType toFindAttrArc;
|
||
|
||
vType sameVertex = -1;
|
||
// find pair with same vertex
|
||
for (int i2 = 0; i2 < (int)currArcs.size(); ++i2)
|
||
{
|
||
// if not currArc
|
||
if (i2 != i1)
|
||
{
|
||
toFindArc = currArcs[i2];
|
||
toFindAttrArc = currAttributes[i2];
|
||
|
||
if (currArc.first == toFindArc.first || currArc.first == toFindArc.second)
|
||
{
|
||
sameVertex = currArc.first;
|
||
if (currArc.first == toFindArc.second)
|
||
swap(toFindAttrArc.first, toFindAttrArc.second);
|
||
}
|
||
else if (currArc.second == toFindArc.first || currArc.second == toFindArc.second)
|
||
{
|
||
sameVertex = currArc.second;
|
||
if (currArc.second == toFindArc.first)
|
||
swap(toFindAttrArc.first, toFindAttrArc.second);
|
||
}
|
||
|
||
if (sameVertex != -1)
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (sameVertex == currArc.first && toFindAttrArc.first != currAttrArc.first ||
|
||
sameVertex == currArc.second && toFindAttrArc.second != currAttrArc.second)
|
||
{
|
||
indexOfConflict.push_back(make_pair(i, CONFLICT_TYPE_2));
|
||
cycleMarked[i] = true;
|
||
countOfConflict++;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
__spf_print(PRINT_TIMES && needPrint, "PROF: GetConflictCycles: end %f sec\n", (duration_cast<duration<double>>(steady_clock::now() - timeR)).count());
|
||
return countOfConflict;
|
||
}
|
||
#undef WITH_CONFLICT_1
|
||
#undef WITH_CONFLICT_2
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
RemoveMultipleArcsByWeights()
|
||
{
|
||
for (vType v = 0; v < numVerts; ++v)
|
||
{
|
||
map<vType, pair<int, wType>> tmp;
|
||
for (vType k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType e = edges[k];
|
||
auto it = tmp.find(e);
|
||
if (it == tmp.end())
|
||
tmp.insert(make_pair(e, make_pair(0, weights[k])));
|
||
else
|
||
it->second.second = std::max(it->second.second, weights[k]);
|
||
}
|
||
|
||
for (vType k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType e = edges[k];
|
||
auto it = tmp.find(e);
|
||
if (it->second.second == weights[k])
|
||
it->second.first++;
|
||
}
|
||
|
||
int removed = 0;
|
||
for (vType k = neighbors[v], k1 = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType e = edges[k1];
|
||
auto it = tmp.find(e);
|
||
if (it->second.second != weights[k1] || (it->second.second == weights[k1] && it->second.first != 1))
|
||
{
|
||
if (it->second.second == weights[k1])
|
||
it->second.first--;
|
||
|
||
edges.erase(edges.begin() + k1);
|
||
weights.erase(weights.begin() + k1);
|
||
linkType.erase(linkType.begin() + k1);
|
||
attributes.erase(attributes.begin() + k1);
|
||
removed++;
|
||
}
|
||
else
|
||
k1++;
|
||
}
|
||
|
||
for (int t = v + 1; t < numVerts + 1; ++t)
|
||
neighbors[t] -= removed;
|
||
}
|
||
|
||
// correct graph information
|
||
numEdges = (vType)edges.size();
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
bool GraphCSR<vType, wType, attrType>::
|
||
checkFirstCoefOfNode(vType node)
|
||
{
|
||
bool ok = true;
|
||
int firstCoef = attributes[neighbors[node]].first.first;
|
||
for (vType k = neighbors[node] + 1; k < neighbors[node + 1]; ++k)
|
||
{
|
||
if (firstCoef != attributes[k].first.first)
|
||
{
|
||
ok = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return ok;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
bool GraphCSR<vType, wType, attrType>::
|
||
getOptimalBoundsForNode(vType nodeFrom, vType nodeTo, int &needBound, pair<int, int> &bounds)
|
||
{
|
||
bool canCalc = true;
|
||
|
||
bool initBound = false;
|
||
bool initBounds = false;
|
||
for (vType k = neighbors[nodeFrom]; k < neighbors[nodeFrom + 1]; ++k)
|
||
{
|
||
if (edges[k] == nodeTo)
|
||
{
|
||
if (initBound == false)
|
||
{
|
||
initBound = true;
|
||
needBound = attributes[k].first.second;
|
||
}
|
||
else
|
||
{
|
||
if (needBound != attributes[k].first.second)
|
||
{
|
||
canCalc = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (initBounds == false)
|
||
{
|
||
initBounds = true;
|
||
bounds.first = bounds.second = attributes[k].first.second;
|
||
}
|
||
else
|
||
{
|
||
bounds.first = std::min(bounds.first, attributes[k].first.second);
|
||
bounds.second = std::max(bounds.second, attributes[k].first.second);
|
||
}
|
||
|
||
}
|
||
|
||
return canCalc;
|
||
}
|
||
|
||
static int calcNewBound(int needBound, pair<int, int> &bounds)
|
||
{
|
||
if (needBound < bounds.first || needBound > bounds.second)
|
||
{
|
||
int dist1 = abs(needBound - bounds.first);
|
||
int dist2 = abs(needBound - bounds.second);
|
||
if (dist1 < dist2)
|
||
return bounds.first;
|
||
else
|
||
return bounds.second;
|
||
}
|
||
else
|
||
return needBound;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
RemoveVerticesByWeight()
|
||
{
|
||
for (vType v = 0; v < numVerts; ++v)
|
||
{
|
||
int removed = 0;
|
||
for (vType k = neighbors[v], k1 = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
if (weights[k1] == -1)
|
||
{
|
||
edges.erase(edges.begin() + k1);
|
||
weights.erase(weights.begin() + k1);
|
||
linkType.erase(linkType.begin() + k1);
|
||
attributes.erase(attributes.begin() + k1);
|
||
removed++;
|
||
}
|
||
else
|
||
k1++;
|
||
}
|
||
|
||
for (int t = v + 1; t < numVerts + 1; ++t)
|
||
neighbors[t] -= removed;
|
||
}
|
||
|
||
// correct graph information
|
||
numEdges = (vType)edges.size();
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
RemoveMultipleArcsOptimal()
|
||
{
|
||
vector<vType> toDel;
|
||
for (vType v = 0; v < numVerts; ++v)
|
||
{
|
||
map<vType, pair<int, vector<vType>>> numLinks;
|
||
|
||
for (vType k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType e = edges[k];
|
||
if (v < e)
|
||
{
|
||
auto it = numLinks.find(e);
|
||
if (it == numLinks.end())
|
||
it = numLinks.insert(it, make_pair(e, make_pair(0, vector<int>())));
|
||
it->second.first++;
|
||
it->second.second.push_back(k);
|
||
}
|
||
}
|
||
|
||
for (auto it = numLinks.begin(); it != numLinks.end(); ++it)
|
||
{
|
||
//has multiple arcs
|
||
if (it->second.first > 1)
|
||
{
|
||
const vector<vType> &idx = it->second.second;
|
||
bool hasWW = false;
|
||
int maxIdxW = -1;
|
||
double maxW = -1;
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
{
|
||
if (linkType[idx[k]] == WW_link)
|
||
hasWW = true;
|
||
if (maxW < weights[idx[k]])
|
||
maxW = weights[idx[k]];
|
||
}
|
||
|
||
//try to find non conflict arcs
|
||
if (!hasWW)
|
||
{
|
||
if (checkFirstCoefOfNode(v) && checkFirstCoefOfNode(it->first))
|
||
{
|
||
int needBoundL = 0, needBoundH = 0;
|
||
pair<int, int> boundsL, boundsH;
|
||
bool canCalcL = getOptimalBoundsForNode(v, it->first, needBoundL, boundsL);
|
||
bool canCalcH = getOptimalBoundsForNode(it->first, v, needBoundH, boundsH);
|
||
|
||
if (canCalcL && canCalcH)
|
||
{
|
||
needBoundL = calcNewBound(needBoundL, boundsL);
|
||
needBoundH = calcNewBound(needBoundH, boundsH);
|
||
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
{
|
||
int idxS = -1;
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
{
|
||
if (maxW == weights[idx[k]])
|
||
{
|
||
idxS = k;
|
||
break;
|
||
}
|
||
}
|
||
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
{
|
||
if (maxW == weights[idx[k]] && idxS == k)
|
||
{
|
||
for (vType n = neighbors[edges[idx[k]]]; n < neighbors[edges[idx[k]] + 1]; ++n)
|
||
{
|
||
if (edges[n] == v &&
|
||
attributes[n].first == attributes[idx[k]].second &&
|
||
attributes[n].second == attributes[idx[k]].first &&
|
||
linkType[n] == linkType[idx[k]])
|
||
{
|
||
attributes[n].first.second = needBoundH;
|
||
attributes[n].second.second = needBoundL;
|
||
break;
|
||
}
|
||
}
|
||
|
||
attributes[idx[k]].first.second = needBoundL;
|
||
attributes[idx[k]].second.second = needBoundH;
|
||
}
|
||
else
|
||
toDel.push_back(idx[k]);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
hasWW = true;
|
||
}
|
||
else
|
||
hasWW = true;
|
||
}
|
||
|
||
//if has W-W links, set arc with maximum weight
|
||
if (hasWW)
|
||
{
|
||
set<int> uniqMaxIds;
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
if (maxW == weights[idx[k]])
|
||
uniqMaxIds.insert(k);
|
||
int exceptIdx = -1;
|
||
if (uniqMaxIds.size() == 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
else if (uniqMaxIds.size() == 1)
|
||
exceptIdx = *uniqMaxIds.begin();
|
||
else
|
||
{
|
||
int minDistToZero = 2147483647; // INT_MAX
|
||
for (auto& elem : uniqMaxIds)
|
||
{
|
||
int sum = abs(0 - attributes[idx[elem]].second.second) + abs(0 - attributes[idx[elem]].first.second);
|
||
if (minDistToZero > sum)
|
||
{
|
||
minDistToZero = sum;
|
||
exceptIdx = elem;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (exceptIdx < 0 || exceptIdx >= idx.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
if (k != exceptIdx)
|
||
toDel.push_back(idx[k]);
|
||
|
||
//OLD ALGORITHM
|
||
/*bool eqSet = false;
|
||
for (int k = 0; k < idx.size(); ++k)
|
||
{
|
||
if (maxW == weights[idx[k]])
|
||
{
|
||
if (eqSet == false)
|
||
eqSet = true;
|
||
else
|
||
toDel.push_back(idx[k]);
|
||
}
|
||
else
|
||
toDel.push_back(idx[k]);
|
||
}*/
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (vType k = 0; k < toDel.size(); ++k)
|
||
weights[toDel[k]] = -1;
|
||
|
||
// add reverse arcs
|
||
for (vType v = 0; v < numVerts; ++v)
|
||
{
|
||
for (vType k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
if (weights[k] == -1 && v < edges[k])
|
||
{
|
||
for (vType z = neighbors[edges[k]]; z < neighbors[edges[k] + 1]; ++z)
|
||
{
|
||
if (edges[z] == v &&
|
||
attributes[z].first == attributes[k].second &&
|
||
attributes[z].second == attributes[k].first &&
|
||
linkType[z] == linkType[k])
|
||
{
|
||
weights[z] = -1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
RemoveVerticesByWeight();
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
CreateGraphWiz(const char *fileName, const vector<tuple<vType, vType, attrType>> &toDelArcs,
|
||
const Arrays<vType> &allArrays, const bool onlyTree)
|
||
{
|
||
FILE *out = fopen(fileName, "w");
|
||
if (out == NULL)
|
||
{
|
||
char buf[256];
|
||
sprintf(buf, "can not open file %s\n", fileName);
|
||
addToGlobalBufferAndPrint(buf);
|
||
return -1;
|
||
}
|
||
|
||
set<tuple<vType, vType, attrType>> dictDel;
|
||
for (int i = 0; i < (int)toDelArcs.size(); ++i)
|
||
{
|
||
vType from = std::get<0>(toDelArcs[i]);
|
||
vType to = std::get<1>(toDelArcs[i]);
|
||
attrType attr = std::get<2>(toDelArcs[i]);
|
||
attrType attrRev = make_pair(attr.second, attr.first);
|
||
dictDel.insert(make_tuple(from, to, attr));
|
||
dictDel.insert(make_tuple(to, from, attrRev));
|
||
}
|
||
|
||
fprintf(out, "graph G{\n");
|
||
|
||
const set<Array*>& arrays = allArrays.GetArrays();
|
||
set<Array*>::const_iterator it = arrays.begin();
|
||
for (; it != arrays.end(); it++)
|
||
{
|
||
const int dimSize = (*it)->GetDimSize();
|
||
const string arrayName = (*it)->GetName();
|
||
string verts = "";
|
||
bool allNotDefined = true;
|
||
for (int i = 0; i < dimSize; ++i)
|
||
{
|
||
vType retVal;
|
||
allArrays.GetVertNumber(*it, i, retVal);
|
||
char buf[32];
|
||
if (retVal < localIdx.size() && retVal >= 0)
|
||
{
|
||
sprintf(buf, "%d", localIdx[retVal]);
|
||
if (localIdx[retVal] != -1)
|
||
allNotDefined = false;
|
||
}
|
||
else
|
||
sprintf(buf, "%d", -1);
|
||
verts += buf;
|
||
verts += " ";
|
||
}
|
||
|
||
if (!allNotDefined)
|
||
{
|
||
fprintf(out, "subgraph cluster_%s {\n", arrayName.c_str());
|
||
for (int k = 0; k < dimSize; ++k)
|
||
fprintf(out, "\"%s.%d\"\n", arrayName.c_str(), k);
|
||
fprintf(out, "label = \"array %s (%s)\" \n", arrayName.c_str(), verts.c_str());
|
||
fprintf(out, "}\n");
|
||
}
|
||
}
|
||
|
||
for (vType i = 0; i < numVerts; ++i)
|
||
{
|
||
for (vType k = neighbors[i]; k < neighbors[i + 1]; ++k)
|
||
{
|
||
const vType i1 = edges[k];
|
||
const attrType attr = attributes[k];
|
||
if (i < i1)
|
||
{
|
||
const char *formatString;
|
||
bool needToPrint = true;
|
||
if (dictDel.find(make_tuple(i, i1, attr)) != dictDel.end())
|
||
{
|
||
formatString = "\"%s\" -- \"%s\" [label=\"%s\", headlabel=\"[%d,%d]\", taillabel=\"[%d,%d]\", color=\"red\", minlen=2.0];\n";
|
||
if (onlyTree)
|
||
needToPrint = false;
|
||
}
|
||
else
|
||
formatString = "\"%s\" -- \"%s\" [label=\"%s\", headlabel=\"[%d,%d]\", taillabel=\"[%d,%d]\", minlen=2.0];\n";
|
||
|
||
if (needToPrint)
|
||
{
|
||
string v1;
|
||
string v2;
|
||
allArrays.GetNameByVertex(globalIdx[i], v1);
|
||
allArrays.GetNameByVertex(globalIdx[i1], v2);
|
||
|
||
char tmpP[32];
|
||
sprintf(tmpP, "%.1f ", weights[k]);
|
||
string label = string(tmpP);
|
||
|
||
if (linkType[k] == LinkType::RR_link)
|
||
label += "RR";
|
||
else if (linkType[k] == LinkType::WR_link)
|
||
label += "WR";
|
||
else if (linkType[k] == LinkType::WW_link)
|
||
label += "WW";
|
||
else
|
||
label += "UNK";
|
||
fprintf(out, formatString, v1.c_str(), v2.c_str(), label.c_str(), attr.first.first, attr.first.second, attr.second.first, attr.second.second);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
fprintf(out, "overlap=false\n");
|
||
fprintf(out, "}\n");
|
||
fclose(out);
|
||
|
||
return 0;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
RemovedEdges(const vector<tuple<vType, vType, attrType>> &toDelArcs, const Arrays<vType> &allArrays)
|
||
{
|
||
set<tuple<vType, vType, attrType>> dictDel;
|
||
for (int i = 0; i < (int)toDelArcs.size(); ++i)
|
||
{
|
||
vType from = std::get<0>(toDelArcs[i]);
|
||
vType to = std::get<1>(toDelArcs[i]);
|
||
attrType attr = std::get<2>(toDelArcs[i]);
|
||
attrType attrRev = make_pair(attr.second, attr.first);
|
||
dictDel.insert(make_tuple(from, to, attr));
|
||
dictDel.insert(make_tuple(to, from, attrRev));
|
||
}
|
||
|
||
int totalRemoved = 0;
|
||
vector<vType> removed(numEdges);
|
||
|
||
for (vType i = 0; i < numVerts; ++i)
|
||
{
|
||
int k = neighbors[i];
|
||
int k1 = neighbors[i];
|
||
int end = neighbors[i + 1];
|
||
int removed = 0;
|
||
while (k1 != end)
|
||
{
|
||
const vType i1 = edges[k];
|
||
const attrType attr = attributes[k];
|
||
|
||
if (dictDel.find(make_tuple(i, i1, attr)) != dictDel.end())
|
||
{
|
||
edges.erase(edges.begin() + k);
|
||
weights.erase(weights.begin() + k);
|
||
linkType.erase(linkType.begin() + k);
|
||
attributes.erase(attributes.begin() + k);
|
||
removed++;
|
||
totalRemoved++;
|
||
}
|
||
else
|
||
k++;
|
||
k1++;
|
||
}
|
||
|
||
for (int t = i + 1; t < numVerts + 1; ++t)
|
||
neighbors[t] -= removed;
|
||
}
|
||
|
||
//correct graph information
|
||
numEdges = (vType)edges.size();
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
GetAlignRuleForArray(Array *inputArray, const Arrays<vType> &allArrays, vector<vector<tuple<Array*, vType, attrType>>> &assignedArrays)
|
||
{
|
||
vector<vType> arrayVerts;
|
||
int err = allArrays.GetAllVertNumber(inputArray, arrayVerts);
|
||
if (err != 0)
|
||
return err;
|
||
|
||
assignedArrays.resize(arrayVerts.size());
|
||
|
||
for (int i = 0; i < arrayVerts.size(); ++i)
|
||
{
|
||
const vType currV = localIdx[arrayVerts[i]];
|
||
int maxDimSize = 0;
|
||
for (int k = neighbors[currV]; k < neighbors[currV + 1]; ++k)
|
||
{
|
||
const vType V1 = edges[k];
|
||
if (V1 >= globalIdx.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
Array *tmp = allArrays.GetArrayByVertex(globalIdx[V1]);
|
||
if (tmp)
|
||
{
|
||
if (maxDimSize < tmp->GetDimSize())
|
||
{
|
||
maxDimSize = tmp->GetDimSize();
|
||
assignedArrays[i].clear();
|
||
assignedArrays[i].push_back(make_tuple(tmp, globalIdx[V1], attributes[k]));
|
||
}
|
||
else if (maxDimSize == tmp->GetDimSize())
|
||
assignedArrays[i].push_back(make_tuple(tmp, globalIdx[V1], attributes[k]));
|
||
}
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
GetAlignRuleWithTemplate(Array *inputArray, const Arrays<vType> &allArrays, vector<tuple<Array*, vType, pair<int, int>>> &rules, const uint64_t regionId)
|
||
{
|
||
vector<vType> arrayVerts;
|
||
int err = allArrays.GetAllVertNumber(inputArray, arrayVerts);
|
||
if (err != 0)
|
||
return err;
|
||
|
||
rules.resize(arrayVerts.size());
|
||
if (inputArray->IsTemplate())
|
||
{
|
||
std::vector<vType> vertsInGraph;
|
||
allArrays.GetAllVertNumber(inputArray, vertsInGraph);
|
||
if (vertsInGraph.size() != arrayVerts.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (int i = 0; i < arrayVerts.size(); ++i)
|
||
rules[i] = std::make_tuple(inputArray, vertsInGraph[i], make_pair(1, 0));
|
||
}
|
||
else
|
||
{
|
||
for (int i = 0; i < arrayVerts.size(); ++i)
|
||
{
|
||
const vType currV = (arrayVerts[i] < localIdx.size()) ? localIdx[arrayVerts[i]] : -1;
|
||
// if current vertex has links
|
||
if (currV != -1)
|
||
{
|
||
pair<RationalNum, RationalNum> rule = make_pair(0, 0);
|
||
pair<RationalNum, RationalNum> nul = rule;
|
||
|
||
int alignDim = -1;
|
||
Array *templ = NULL;
|
||
|
||
set<vType> wasDone;
|
||
if (hasLinkWithTempate(currV, allArrays, false))
|
||
{
|
||
rule = findLinkWithTempate2(currV, alignDim, templ, allArrays, wasDone);
|
||
if (rule != nul)
|
||
{
|
||
if ((int)rule.first.getDenominator() != 1 || rule.second.getDenominator() != 1)
|
||
{
|
||
__spf_print(1, "Can not find correct align rule for array '%s', found (%d/%d, %d/%d)\n", inputArray->GetShortName().c_str(),
|
||
(int)rule.first.getNumerator(), (int)rule.first.getDenominator(),
|
||
(int)rule.second.getNumerator(), (int)rule.second.getDenominator());
|
||
|
||
//TODO: need to correct
|
||
//const int newValue = (rule.first.getDenominator() == rule.second.getDenominator()) ? rule.first.getDenominator() : 0;
|
||
if (!hasLinkWithTempate(currV, allArrays, true))
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
return 101;
|
||
}
|
||
|
||
pair<int, int> intRule = make_pair((int)rule.first.getNumerator(), (int)rule.second.getNumerator());
|
||
|
||
rules[i] = make_tuple(templ, alignDim, intRule);
|
||
int dimNum = -1;
|
||
int err = allArrays.GetDimNumber(templ, alignDim, dimNum);
|
||
if (err == -1)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
inputArray->AddLinkWithTemplate(i, dimNum, templ, intRule, regionId);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
FindLinksBetweenArrays(const Arrays<vType> &allArrays, const Array *from, const Array *to, vector<int> &links) const
|
||
{
|
||
links.clear();
|
||
links.resize(from->GetDimSize());
|
||
|
||
vector<vType> vertNum;
|
||
int err = allArrays.GetAllVertNumber(from, vertNum);
|
||
if (err != 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (int i = 0; i < from->GetDimSize(); ++i)
|
||
{
|
||
set<vType> wasDone;
|
||
//no edges in graph
|
||
if (localIdx[vertNum[i]] == -1)
|
||
{
|
||
links[i] = -1;
|
||
continue;
|
||
}
|
||
|
||
int foundV = findDimNumLink(localIdx[vertNum[i]], to, allArrays, wasDone);
|
||
links[i] = foundV;
|
||
}
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
FindLinkWithMaxDim(const vType from, const Arrays<vType> &allArrays, pair<Array*, int> &result, set<int> &wasDone)
|
||
{
|
||
if (numVerts == 0)
|
||
return;
|
||
|
||
if (from >= localIdx.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
const vType v = localIdx[from];
|
||
if (v == -1)
|
||
return;
|
||
|
||
for (int k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
|
||
if (wasDone.find(currV) != wasDone.end())
|
||
continue;
|
||
|
||
wasDone.insert(v);
|
||
|
||
if (currV >= globalIdx.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
Array *found = allArrays.GetArrayByVertex(globalIdx[currV]);
|
||
if (found != NULL)
|
||
{
|
||
vType dimNumber = -1;
|
||
int err = allArrays.GetDimNumber(found, globalIdx[currV], dimNumber);
|
||
if (err != -1)
|
||
{
|
||
const pair<int, int> &sizesRes = result.first->GetSizes()[result.second];
|
||
const pair<int, int> &sizesFound = found->GetSizes()[dimNumber];
|
||
|
||
//calculate dimention sizes and compare
|
||
if (sizesRes.second - sizesRes.first + 1 < sizesFound.second - sizesFound.first + 1)
|
||
{
|
||
result.first = found;
|
||
result.second = dimNumber;
|
||
}
|
||
}
|
||
}
|
||
FindLinkWithMaxDim(globalIdx[currV], allArrays, result, wasDone);
|
||
}
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
FindAllArraysTrees(map<Array*, int> &trees, const Arrays<vType> &allArrays)
|
||
{
|
||
int treeCount = 1;
|
||
set<Array*> firstInit;
|
||
map<Array*, set<int>> wasDone;
|
||
|
||
color.resize(numVerts);
|
||
for (int i = 0; i < numVerts; ++i)
|
||
color[i] = WHITE;
|
||
vector<int> qNextV;
|
||
|
||
while (true)
|
||
{
|
||
int nextV = -1;
|
||
|
||
if (qNextV.size() == 0)
|
||
{
|
||
for (int i = 0; i < numVerts; ++i)
|
||
{
|
||
if (color[i] == WHITE)
|
||
{
|
||
nextV = i;
|
||
color[i] = BLACK;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
nextV = qNextV.back();
|
||
qNextV.pop_back();
|
||
if (color[nextV] == BLACK)
|
||
continue;
|
||
else
|
||
color[nextV] = BLACK;
|
||
}
|
||
|
||
if (nextV == -1)
|
||
break;
|
||
else
|
||
{
|
||
if (nextV >= globalIdx.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
Array *parentArray = allArrays.GetArrayByVertex(globalIdx[nextV]);
|
||
if (parentArray == NULL)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
if (firstInit.find(parentArray) == firstInit.end())
|
||
{
|
||
vector<vType> vertexes;
|
||
int err = allArrays.GetAllVertNumber(parentArray, vertexes);
|
||
if (err != 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (int i = 0; i < vertexes.size(); ++i)
|
||
{
|
||
if (vertexes[i] < localIdx.size())
|
||
{
|
||
const int idx = localIdx[vertexes[i]];
|
||
if (idx != nextV && idx != -1)
|
||
qNextV.push_back(idx);
|
||
}
|
||
}
|
||
firstInit.insert(parentArray);
|
||
}
|
||
|
||
for (int k = neighbors[nextV]; k < neighbors[nextV + 1]; ++k)
|
||
{
|
||
const vType currV = edges[k];
|
||
|
||
if (currV >= globalIdx.size())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
Array *currArray = allArrays.GetArrayByVertex(globalIdx[currV]);
|
||
if (currArray == NULL)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
auto itParent = trees.find(parentArray);
|
||
if (itParent == trees.end())
|
||
{
|
||
itParent = trees.insert(itParent, make_pair(parentArray, treeCount));
|
||
treeCount++;
|
||
}
|
||
|
||
auto itAdd = trees.find(currArray);
|
||
if (itAdd == trees.end())
|
||
trees.insert(itAdd, make_pair(currArray, itParent->second));
|
||
else
|
||
{
|
||
if (itParent->second != itAdd->second)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
}
|
||
|
||
auto itCurrCheck = wasDone.find(currArray);
|
||
if (itCurrCheck == wasDone.end())
|
||
itCurrCheck = wasDone.insert(itCurrCheck, make_pair(currArray, set<int>()));
|
||
if (itCurrCheck->second.find(currV) == itCurrCheck->second.end())
|
||
{
|
||
qNextV.push_back(currV);
|
||
itCurrCheck->second.insert(currV);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return treeCount - 1;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
HighlightLinks()
|
||
{
|
||
if (hardLinksWasUp)
|
||
return;
|
||
wType sum;
|
||
/*sum = 1.0;
|
||
// count all RR_link weight
|
||
for (int i = 0; i < weights.size(); ++i)
|
||
{
|
||
if (linkType[i] == RR_link)
|
||
sum += weights[i];
|
||
}
|
||
|
||
// and add it to all WR_link links
|
||
for (int i = 0; i < weights.size(); ++i)
|
||
{
|
||
if (linkType[i] == WR_link)
|
||
weights[i] += sum;
|
||
} */
|
||
|
||
sum = 1.0;
|
||
// count all RR_link and WR_link weight
|
||
for (int i = 0; i < weights.size(); ++i)
|
||
{
|
||
if (linkType[i] == RR_link || linkType[i] == WR_link)
|
||
sum += weights[i];
|
||
}
|
||
|
||
// and add it to all WW_link links
|
||
for (int i = 0; i < weights.size(); ++i)
|
||
{
|
||
if (linkType[i] == WW_link)
|
||
weights[i] += sum;
|
||
}
|
||
|
||
hardLinksWasUp = true;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
bool GraphCSR<vType, wType, attrType>::
|
||
SaveGraphToFile(FILE *file)
|
||
{
|
||
fwrite(&numVerts, sizeof(vType), 1, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fwrite(&numEdges, sizeof(vType), 1, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fwrite(&lastNumOfV, sizeof(vType), 1, file);
|
||
if (ferror(file)) return false;
|
||
|
||
auto tmpS = neighbors.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(neighbors.data(), sizeof(vType), neighbors.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
tmpS = edges.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(edges.data(), sizeof(vType), edges.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
tmpS = weights.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(weights.data(), sizeof(wType), weights.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
tmpS = linkType.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(linkType.data(), sizeof(uint8_t), linkType.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
tmpS = attributes.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(attributes.data(), sizeof(attrType), attributes.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
tmpS = localIdx.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(localIdx.data(), sizeof(vType), localIdx.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
tmpS = globalIdx.size();
|
||
fwrite(&tmpS, sizeof(size_t), 1, file);
|
||
fwrite(globalIdx.data(), sizeof(vType), globalIdx.size(), file);
|
||
if (ferror(file)) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
template<typename type>
|
||
static inline void readStdVector(vector<type> &T, const size_t size, FILE *file)
|
||
{
|
||
type *tmp = new type[size];
|
||
fread(tmp, sizeof(type), size, file);
|
||
T.resize(size);
|
||
for (int i = 0; i < size; ++i)
|
||
T[i] = tmp[i];
|
||
|
||
delete []tmp;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
bool GraphCSR<vType, wType, attrType>::
|
||
LoadGraphFromFile(FILE *file)
|
||
{
|
||
fread(&numVerts, sizeof(vType), 1, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&numEdges, sizeof(vType), 1, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&lastNumOfV, sizeof(vType), 1, file);
|
||
if (ferror(file)) return false;
|
||
|
||
size_t tmpS;
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(neighbors, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(edges, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(weights, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(linkType, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(attributes, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(localIdx, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
fread(&(tmpS), sizeof(size_t), 1, file);
|
||
readStdVector(globalIdx, tmpS, file);
|
||
if (ferror(file)) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
vector<attrType> GraphCSR<vType, wType, attrType>::
|
||
GetAllAttributes(const int vert) const
|
||
{
|
||
vector<attrType> retVal;
|
||
if (localIdx.size() == 0 || vert >= localIdx.size())
|
||
return retVal;
|
||
|
||
int locV = localIdx[vert];
|
||
if (locV < 0)
|
||
return retVal;
|
||
|
||
for (int z = neighbors[locV]; z < neighbors[locV + 1]; ++z)
|
||
retVal.push_back(attributes[z]);
|
||
|
||
return retVal;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
CountOfConnected(const vType startV) const
|
||
{
|
||
std::vector<unsigned char> inSet(numVerts);
|
||
std::fill(inSet.begin(), inSet.end(), 0);
|
||
|
||
vector<vType> next;
|
||
next.reserve(numVerts);
|
||
|
||
next.push_back(startV);
|
||
inSet[startV] = 1;
|
||
int count = 1;
|
||
|
||
while (next.size())
|
||
{
|
||
const vType V = next.back();
|
||
next.pop_back();
|
||
|
||
for (vType k = neighbors[V]; k < neighbors[V + 1]; ++k)
|
||
{
|
||
const vType toV = edges[k];
|
||
if (inSet[toV] == 0)
|
||
{
|
||
inSet[toV] = 1;
|
||
count++;
|
||
next.push_back(toV);
|
||
}
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
int GraphCSR<vType, wType, attrType>::
|
||
CountOfConnectedForArray(const vType startV) const
|
||
{
|
||
if (startV >= localIdx.size() || startV < 0)
|
||
return 0;
|
||
const int localV = localIdx[startV];
|
||
if (localV == -1)
|
||
return 0;
|
||
else
|
||
return CountOfConnected(localV) - 1;
|
||
}
|
||
template<typename vType, typename wType, typename attrType>
|
||
pair<int, int> GraphCSR<vType, wType, attrType>::
|
||
MakeConnected(const vType startV, vector<unsigned char> &inSet) const
|
||
{
|
||
int count = 0;
|
||
int countE = 0;
|
||
|
||
inSet.resize(numVerts);
|
||
std::fill(inSet.begin(), inSet.end(), 0);
|
||
|
||
vector<vType> next;
|
||
next.reserve(numVerts);
|
||
|
||
next.push_back(startV);
|
||
inSet[startV] = 1;
|
||
count = 1;
|
||
|
||
while (next.size())
|
||
{
|
||
const vType V = next.back();
|
||
next.pop_back();
|
||
|
||
for (vType k = neighbors[V]; k < neighbors[V + 1]; ++k)
|
||
{
|
||
const vType toV = edges[k];
|
||
if (inSet[toV] == 0)
|
||
{
|
||
inSet[toV] = 1;
|
||
count++;
|
||
next.push_back(toV);
|
||
}
|
||
}
|
||
}
|
||
|
||
for (int v = 0; v < numVerts; ++v)
|
||
{
|
||
for (vType k = neighbors[v]; k < neighbors[v + 1]; ++k)
|
||
{
|
||
const vType toV = edges[k];
|
||
if (inSet[toV])
|
||
countE++;
|
||
}
|
||
}
|
||
|
||
return make_pair(count, countE / 2);
|
||
}
|
||
|
||
template<typename vType, typename attrType>
|
||
static tuple<vType, vType, attrType> makeReverse(const tuple<vType, vType, attrType> &in)
|
||
{
|
||
vType from = std::get<0>(in);
|
||
vType to = std::get<1>(in);
|
||
attrType attr = std::get<2>(in);
|
||
attrType attrRev = make_pair(attr.second, attr.first);
|
||
|
||
return std::make_tuple(to, from, attrRev);
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
vector<tuple<vType, vType, attrType>> GraphCSR<vType, wType, attrType>::
|
||
CreateMaximumSpanningTree()
|
||
{
|
||
set<tuple<vType, vType, attrType>> selected;
|
||
|
||
set<vType> tmp;
|
||
for (int z = 0; z < numEdges; ++z)
|
||
tmp.insert(edges[z]);
|
||
int countOfRealV = tmp.size();
|
||
tmp.clear();
|
||
|
||
tuple<vType, vType, attrType> maxEdge;
|
||
wType startW = -1;
|
||
set<vType> vInserted;
|
||
|
||
while (vInserted.size() != countOfRealV)
|
||
{
|
||
startW = -1;
|
||
for (auto &z : vInserted)
|
||
{
|
||
for (vType k = neighbors[z]; k < neighbors[z + 1]; ++k)
|
||
{
|
||
if (vInserted.find(edges[k]) != vInserted.end())
|
||
continue;
|
||
|
||
if (startW < weights[k])
|
||
{
|
||
startW = weights[k];
|
||
maxEdge = std::make_tuple(z, edges[k], attributes[k]);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (startW != -1)
|
||
{
|
||
selected.insert(maxEdge);
|
||
selected.insert(makeReverse(maxEdge));
|
||
|
||
vInserted.insert(std::get<0>(maxEdge));
|
||
vInserted.insert(std::get<1>(maxEdge));
|
||
} // next tree
|
||
else
|
||
{
|
||
for (vType z = 0; z < numVerts; ++z)
|
||
{
|
||
for (vType k = neighbors[z]; k < neighbors[z + 1]; ++k)
|
||
{
|
||
if (vInserted.find(edges[k]) != vInserted.end())
|
||
continue;
|
||
|
||
if (startW < weights[k])
|
||
{
|
||
startW = weights[k];
|
||
maxEdge = std::make_tuple(z, edges[k], attributes[k]);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (startW == -1)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
else
|
||
{
|
||
selected.insert(maxEdge);
|
||
selected.insert(makeReverse(maxEdge));
|
||
|
||
vInserted.insert(std::get<0>(maxEdge));
|
||
vInserted.insert(std::get<1>(maxEdge));
|
||
}
|
||
}
|
||
}
|
||
|
||
vector<tuple<vType, vType, attrType>> toDel;
|
||
for (vType z = 0; z < numVerts; ++z)
|
||
{
|
||
for (vType k = neighbors[z]; k < neighbors[z + 1]; ++k)
|
||
{
|
||
if (selected.find(std::make_tuple(z, edges[k], attributes[k])) == selected.end())
|
||
toDel.push_back(std::make_tuple(z, edges[k], attributes[k]));
|
||
}
|
||
}
|
||
return toDel;
|
||
}
|
||
|
||
template<typename vType, typename wType, typename attrType>
|
||
void GraphCSR<vType, wType, attrType>::
|
||
RemoveAllEdgesFromGraph(const map<Array*, vector<pair<int, int>>> &toDel, const Arrays<vType>& allArrays)
|
||
{
|
||
for (auto& arrayP : toDel)
|
||
{
|
||
Array* array = arrayP.first;
|
||
checkNull(array, convertFileName(__FILE__).c_str(), __LINE__);
|
||
if (!array->IsArray() && !array->IsTemplate())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
vector<vType> arrayVerts;
|
||
int err = allArrays.GetAllVertNumber(array, arrayVerts);
|
||
if (err != 0)
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
for (int i = 0; i < arrayVerts.size(); ++i)
|
||
{
|
||
const vType currV = localIdx[arrayVerts[i]];
|
||
// if current vertex has links
|
||
if (currV != -1)
|
||
{
|
||
for (int k = neighbors[currV]; k < neighbors[currV + 1]; ++k)
|
||
{
|
||
const vType V2 = edges[k];
|
||
Array* arrayTo = allArrays.GetArrayByVertex(globalIdx[V2]);
|
||
checkNull(array, convertFileName(__FILE__).c_str(), __LINE__);
|
||
|
||
bool needToDel = true;
|
||
if (arrayTo->IsArray())
|
||
{
|
||
if (toDel.find(arrayTo) == toDel.end())
|
||
printInternalError(convertFileName(__FILE__).c_str(), __LINE__);
|
||
}
|
||
else // tepmlate
|
||
{
|
||
if (toDel.find(arrayTo) == toDel.end())
|
||
needToDel = false;
|
||
}
|
||
|
||
//remove
|
||
if (needToDel)
|
||
weights[k] = -1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//remove from graph
|
||
RemoveVerticesByWeight();
|
||
}
|
||
|
||
template class GraphCSR<int, double, attrType>;
|
||
}
|
||
|
||
#undef MIN_CYCLE_DIM
|
||
#undef MAX_LOOP_DIM
|
||
#undef PRINT_TIMES
|