00001 #include "Graph.h"
00002 #include <string>
00003 #include "Node.h"
00004
00005 #include <algorithm>
00006 #include <QDebug>
00007 #include <QJsonArray>
00008 #include "utils.h"
00009
00010 namespace Elve {
00011
00012 using namespace std;
00013
00014 bool operator==(const Pin& a,const Pin& b) {
00015 return a.id == b.id && ((a.index == b.index) || a.index == -1 || b.index == -1);
00016 }
00017
00018 void Aliases::reserve(size_t size) {
00019 inputs.reserve(size);
00020 outputs.reserve(size);
00021 }
00022
00023 size_t Aliases::size() const {
00024 return inputs.size();
00025 }
00026
00027 Pin::Pin(const NodeID& id) : id(id),index(-1){}
00028 Pin::Pin(const NodeID &id,const Index& index) : id(id), index(index){}
00029
00030 Graph::Graph(const SharedData &data) : mData(data), mLastId(0)
00031 {
00032 for(const NodeData& d : data->nodeDatas()) {
00033 addNode(d);
00034 }
00035 for(const NodeData& d : data->nodeDatas()) {
00036 for(const Dependency& dep : d.dependencies()) {
00037 addEdge(dep.id,dep.from,d.id(),dep.to);
00038 }
00039 }
00040 }
00041
00042 Graph::Graph(const SharedData& data, const SparseData &extraData, const Aliases &aliases, const NodeIDSet& excluded)
00043 : mData(data), mExtraData(extraData), mAliases(aliases), mExcluded(excluded), mLastId(0)
00044 {
00045
00046 using pair_type = SparseData::value_type;
00047 for(const pair_type& p : mExtraData) {
00048 if(!mExcluded.count(p.first)) {
00049 addNode(p.second);
00050 }
00051 }
00052
00053 for(const NodeData& d : data->nodeDatas()) {
00054 if(!mExcluded.count(d.id())) {
00055 addNode(d);
00056 }
00057 }
00058
00059 for(const NodeData& d : data->nodeDatas()) {
00060 for(const Dependency& dep : d.dependencies()) {
00061 const Pin cpin = inputAlias({d.id(),dep.to});
00062 if(mExcluded.count(cpin.id)) {
00063 continue;
00064 }
00065 const Pin dpin = outputAlias({dep.id,dep.from});
00066 if(!mExcluded.count(dpin.id)) {
00067 addEdge(dpin.id,dpin.index,cpin.id,cpin.index);
00068 }
00069 }
00070 }
00071 }
00072
00073 NodeID Graph::newID() const {
00074 return ++mLastId;
00075 }
00076
00077 const QString& Graph::filename() const {
00078 return mData->mFilename;
00079 }
00080
00081 const NodesByID& Graph::nodes() const {
00082 return mNodes;
00083 }
00084
00085 size_t Graph::nodeCount() const {
00086 return mNodes.size();
00087 }
00088
00089 const Pin Graph::inputAlias(const Pin &id) const {
00090 auto it = mAliases.inputs.find(id);
00091 if(it != mAliases.inputs.end())
00092 return inputAlias(it->second);
00093 return id;
00094 }
00095
00096 const Pin Graph::outputAlias(const Pin &id) const {
00097 auto it = mAliases.outputs.find(id);
00098 if(it != mAliases.outputs.end())
00099 return outputAlias(it->second);
00100 return id;
00101 }
00102
00103 Node* Graph::addNode(const NodeData& d) {
00104 auto pi = mNodes.emplace(d.id(),d);
00105
00106 Node* n = &pi.first->second;
00107 if(d.type() == NodeType::OUTPUT or d.type() == NodeType::OUTPUT_CLUSTER) {
00108 mOutputs.push_back(n);
00109 } else if (d.type() == NodeType::INPUT or d.type() == NodeType::INPUT_CLUSTER) {
00110 mInputs.push_back(n);
00111 }
00112 if(n->id() > mLastId) mLastId = n->id();
00113 return n;
00114 }
00115
00116 void Graph::addEdge(const NodeID& from, Index fi, const NodeID& to, Index ti) {
00117 if(from != to) {
00118 mNodes.at(from).addChild(&mNodes.at(to),fi,ti);
00119 } else {
00120 qDebug() << "will not make edge from" << from << fi << "to" << to << ti;
00121 }
00122 }
00123
00124 const NodeData& Graph::data(const NodeID& id) const {
00125 if(id < mData->nodeDatas().size()) {
00126 return mData->nodeDatas().at(id);
00127 } else {
00128 return mExtraData.at(id);
00129 }
00130 }
00131
00133
00134 void _descend(const Node *n, vector<NodeIDSet> &sets, NodeIDSet &mainSet);
00135
00136 void _collectClusterables(const Node* n, NodeIDSet& set, vector<NodeIDSet>& sets, NodeIDSet& mainSet) {
00137 set.insert(n->id());
00138 mainSet.insert(n->id());
00139 vector<const Node*> collected; collected.reserve(n->ancestors().size());
00140 for(const Node* cn : n->ancestors()) {
00141 if(std::all_of(cn->children().begin(),
00142 cn->children().end(),
00143 [&set](const Node* an){return set.count(an->id());})
00144 and !cn->isInput() and !cn->isOutput() and !mainSet.count(cn->id())) {
00145 set.insert(cn->id());
00146 collected.push_back(cn);
00147 mainSet.insert(cn->id());
00148 } else {
00149 _descend(cn,sets,mainSet);
00150 }
00151 }
00152 for(const Node* cn : collected) {
00153 _collectClusterables(cn,set,sets,mainSet);
00154 }
00155 }
00156
00157 void _descend(const Node* n, vector<NodeIDSet>& sets, NodeIDSet& mainSet) {
00158 if(!mainSet.count(n->id())) {
00159 NodeIDSet collect; collect.reserve(20);
00160 _collectClusterables(n,collect,sets,mainSet);
00161 sets.push_back(collect);
00162 }
00163 }
00164
00165 SharedGraph Graph::clusterize(size_t level) {
00166 if(level == 0) {
00167 return shared_from_this();
00168 }
00169 vector<NodeIDSet> sets;
00170 NodeIDSet mainSet; mainSet.reserve(nodeCount());
00171 for(Node* out : outputs()) {
00172
00173 NodeIDSet collect;
00174 _collectClusterables(out,collect,sets,mainSet);
00175 collect.erase(out->id());
00176 sets.push_back(collect);
00177 }
00178 SharedGraph g = shared_from_this();
00179 int i = 0;
00180 g = g->fastGroup(sets,"cluster");
00181 qDebug() << "shrinked a" << nodeCount() << "nodes graph to a" << g->nodeCount() << "one";
00182 return g->clusterize(level-1);
00183 }
00184
00186
00187 NodeName Graph::uniqueName(const NodeName& base) const {
00188 NodeName current = base;
00189 unsigned suffix = 1;
00190 repeat:
00191 for(const auto& p : mNodes) {
00192 const NodeName& id = p.second.name();
00193 if(id == current) {
00194 current = base + "_" + std::to_string(suffix++);
00195 goto repeat;
00196 }
00197 }
00198 return current;
00199 }
00200
00201 const Node& Graph::node(const NodeID& id) const {
00202 return mNodes.at(id);
00203 }
00204
00205 SharedGraph Graph::ungroup(const NodeID &cluster) {
00206 if(!mExtraData.count(cluster)) {
00207 return shared_from_this();
00208 }
00209 SparseData extras(mExtraData);
00210 NodeIDSet excl = excludedWithout(extras.at(cluster).dependencies());
00211 extras.erase(cluster);
00212 return make_shared<Graph>(mData,extras,aliasesWithout(cluster),excl);
00213 }
00214
00215 SharedGraph Graph::fastGroup(const vector<NodeIDSet>& groups, const NodeName& basename) {
00216
00217 size_t contentSize = 0;
00218 for(const NodeIDSet& group : groups) {
00219 contentSize += group.size();
00220 }
00221
00222 SparseData extra; extra.reserve(mExtraData.size()+groups.size());
00223
00224 using pair_type = SparseData::value_type;
00225 for(const pair_type& p : mExtraData) {
00226 extra.emplace(p.first,p.second);
00227 }
00228
00229 Aliases aliases(mAliases); aliases.reserve(aliases.size()+contentSize);
00230 NodeIDSet excluded(mExcluded); excluded.reserve(mExcluded.size()+contentSize);
00231
00232
00233 for(const NodeIDSet& group : groups) {
00234 NodeID i = newID();
00235 if(group.size() < 2) {
00236 continue;
00237 }
00238 vector<Name> inputs;
00239 vector<Name> outputs;
00240 Dependencies deps; deps.reserve(group.size());
00241 deps.insert(deps.end(),group.begin(),group.end());
00242
00243 float av_index = 0;
00244 for(const NodeID& id : group) {
00245 const Node& n = node(id);
00246 const NodeData& nd = n.data();
00247 for(const Node::Connexion& c : n.fanIn()) {
00248 if(!group.count(c.node->id())) {
00249
00250 int inputNum = lazy_add(inputs,n.name());
00251 aliases.inputs.emplace(Pin(id,c.to),Pin(i,inputNum));
00252 }
00253 }
00254 for(const Node::Connexion& c : n.fanOut()) {
00255 if(!group.count(c.node->id())) {
00256
00257 int outputNum = lazy_add(outputs,n.name());
00258 aliases.outputs.emplace(Pin(id,c.from),Pin(i,outputNum));
00259 }
00260 }
00261
00262
00263 excluded.insert(id);
00264 av_index += data(id).ioIndex();
00265 }
00266 av_index /= group.size();
00267 Names inputNames; inputNames.reserve(inputs.size());
00268 Names outputNames; outputNames.reserve(outputs.size());
00269 inputNames.insert(inputNames.begin(),inputs.begin(),inputs.end());
00270 outputNames.insert(outputNames.begin(),outputs.begin(),outputs.end());
00271
00272 const NodeData& first = data(*group.begin());
00273 NodeType t = CLUSTER;
00274 switch (first.type()) {
00275 case INPUT:
00276 case INPUT_CLUSTER:
00277 t = INPUT_CLUSTER;
00278 break;
00279 case OUTPUT:
00280 case OUTPUT_CLUSTER:
00281 t = OUTPUT_CLUSTER;
00282 break;
00283 default:
00284 break;
00285 }
00286
00287 extra.emplace(i,NodeData(i,basename + to_string(i),deps,t,{},av_index,inputs.size(),outputs.size(),inputNames,outputNames));
00288
00289 }
00290 return make_shared<Graph>(mData,extra,aliases,excluded);
00291 }
00292
00293 SharedGraph Graph::group(const NodeIDSet &toGroup, const NodeID& i,const NodeName &groupName) {
00294 if(toGroup.size() < 2) {
00295 return shared_from_this();
00296 }
00297
00298 return fastGroup({toGroup},groupName);
00299 }
00300
00301 const NodePtrs& Graph::inputs() {
00302 return mInputs;
00303 }
00304
00305 const NodePtrs& Graph::outputs() {
00306 return mOutputs;
00307 }
00308
00309 const SharedData& Graph::datas() const {
00310 return mData;
00311 }
00312 const SparseData& Graph::extraData() const {
00313 return mExtraData;
00314 }
00315 const Aliases& Graph::aliases() const {
00316 return mAliases;
00317 }
00318
00319 const NodeIDSet Graph::excluded() const {
00320 return mExcluded;
00321 }
00322
00323 size_t Graph::inputCount() const
00324 {
00325 return mInputs.size();
00326 }
00327
00328 size_t Graph::outputCount() const
00329 {
00330 return mOutputs.size();
00331 }
00332
00333 size_t Graph::maxInputIndex() const
00334 {
00335 size_t i = 0;
00336 for(const Node* in : mInputs) {
00337 if(in->IOIndex() > i) {
00338 i = in->IOIndex();
00339 }
00340 }
00341 return i == 0 ? 1 : i;
00342 }
00343
00344 size_t Graph::maxOutputIndex() const
00345 {
00346 size_t i = 0;
00347 for(const Node* in : mOutputs) {
00348 if(in->IOIndex() > i) {
00349 i = in->IOIndex();
00350 }
00351 }
00352 return i == 0 ? 1 : i;
00353 }
00354
00355 QJsonObject Graph::json() const
00356 {
00357 QJsonObject main;
00358 main.insert("graph_data",mData->json());
00359
00360
00361
00362 {
00363 QJsonArray extra;
00364 using pair_type = SparseData::value_type;
00365 for(const pair_type& p : mExtraData) {
00366 extra.append(p.second.json());
00367 }
00368 main.insert("extra_data",extra);
00369 }
00370 {
00371 {
00372 QJsonArray als;
00373 using pair_type = AliasesMap::value_type;
00374 for(const pair_type& p : mAliases.inputs) {
00375 als.append(QJsonArray{(int)p.first.id,(int)p.first.index,(int)p.second.id,(int)p.second.index});
00376 }
00377 main.insert("inputAliases",als);
00378 }
00379 {
00380 QJsonArray als;
00381 using pair_type = AliasesMap::value_type;
00382 for(const pair_type& p : mAliases.outputs) {
00383 als.append(QJsonArray{(int)p.first.id,(int)p.first.index,(int)p.second.id,(int)p.second.index});
00384 }
00385 main.insert("outputAliases",als);
00386 }
00387
00388 }
00389 QJsonArray excl;
00390 for(const NodeID& id : mExcluded) {
00391 excl.append((int)id);
00392 }
00393 main.insert("excluded",excl);
00394 return main;
00395 }
00396
00397 NodeLevel Graph::highestLevel() const {
00398 using pair_type = NodesByID::value_type;
00399
00400 if(mNodes.empty()) return 0;
00401 return max_element(mNodes.begin(),mNodes.end(),
00402 [](const pair_type& a, const pair_type& b)->bool {
00403 return a.second.level() < b.second.level();
00404 })->second.level();
00405 }
00406
00407 SharedGraph Graph::fromJson(const QJsonObject& obj)
00408 {
00409 SharedData sdata = make_shared<GraphData>(obj.value("graph_data").toObject());
00410
00411 SparseData extra;
00412 QJsonArray jextr = obj.value("extra_data").toArray();
00413 extra.reserve(jextr.size());
00414 for(const QJsonValue& v : jextr) {
00415 QJsonObject obj = v.toObject();
00416 extra.emplace(obj.value("id").toInt(),obj);
00417 }
00418 Aliases als;
00419 {
00420 QJsonArray jals = obj.value("inputAliases").toArray();
00421 als.inputs.reserve(jals.size());
00422 for(const QJsonValue& v : jals) {
00423 QJsonArray pair = v.toArray();
00424 als.inputs.emplace(Pin(pair.at(0).toInt(-1),pair.at(1).toInt(-1)),
00425 Pin(pair.at(2).toInt(-1),pair.at(3).toInt(-1)));
00426 }
00427 }
00428 {
00429 QJsonArray jals = obj.value("outputAliases").toArray();
00430 als.outputs.reserve(jals.size());
00431 for(const QJsonValue& v : jals) {
00432 QJsonArray pair = v.toArray();
00433 als.outputs.emplace(Pin(pair.at(0).toInt(-1),pair.at(1).toInt(-1)),
00434 Pin(pair.at(2).toInt(-1),pair.at(3).toInt(-1)));
00435 }
00436 }
00437 NodeIDSet excl;
00438 QJsonArray jexcl = obj.value("excluded").toArray();
00439 excl.reserve(jexcl.size());
00440 for(const QJsonValue& v : jexcl) {
00441 excl.insert(v.toInt());
00442 }
00443 return make_shared<Graph>(sdata,extra,als,excl);
00444 }
00445
00446 Aliases Graph::aliasesWithout(const NodeID& repl) const {
00447 Aliases als;
00448 for(const auto& p : mAliases.inputs) {
00449 if(p.second.id != repl) {
00450 als.inputs.insert(p);
00451 }
00452 }
00453 for(const auto& p : mAliases.outputs) {
00454 if(p.second.id != repl) {
00455 als.outputs.insert(p);
00456 }
00457 }
00458 return als;
00459 }
00460
00461 NodeIDSet Graph::excludedWithout(const Dependencies& ids) const {
00462 NodeIDSet excl(mExcluded);
00463 for(const Dependency& dep : ids) {
00464 excl.erase(dep.id);
00465 }
00466 return excl;
00467 }
00468
00469 }