14 #include <boost/algorithm/string.hpp>
17 #include <boost/graph/graph_traits.hpp>
18 #include <boost/graph/depth_first_search.hpp>
19 #include <boost/graph/reverse_graph.hpp>
20 #include <boost/graph/iteration_macros.hpp>
21 #include <boost/property_map/property_map.hpp>
22 #include <boost/graph/copy.hpp>
23 #include <boost/graph/graphviz.hpp>
33 SameInputDim(
unsigned int const dim,
Graph const& graph) : dim(dim), graph(graph) {}
39 bool operator()(boost::graph_traits<Graph>::edge_descriptor edge) {
40 return graph[edge]->inputDim == dim;
56 std::shared_ptr<WorkGraph> newGraph = std::make_shared<WorkGraph>();
57 copy_graph(
graph, newGraph->graph);
65 clear_vertex(*nodeDesc,
graph);
66 remove_vertex(*nodeDesc,
graph);
69 std::vector<std::pair<int,int>>
WorkGraph::GetEdges(std::string
const& srcName, std::string
const& tgtName)
73 std::vector<std::pair<int,int>> edges;
75 boost::graph_traits<Graph>::out_edge_iterator
e, e_end;
76 for( boost::tie(
e, e_end)=out_edges(*nodeDesc,
graph);
e!=e_end; ++
e ) {
77 auto vTarget = target(*
e,
graph);
78 if(tgtName ==
graph[vTarget]->name)
79 edges.push_back( std::make_pair(
graph[*
e]->outputDim,
graph[*
e]->inputDim ) );
89 return boost::num_vertices(
graph);
94 return boost::num_edges(
graph);
102 std::vector<std::pair<int, std::string> > temp;
104 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
105 for( boost::tie(
e, e_end)=in_edges(*
v,
graph);
e!=e_end; ++
e ) {
106 auto vSource = source(*
e,
graph);
107 temp.push_back(std::make_pair(
graph[*
e]->outputDim,
graph[vSource]->name));
111 std::sort(temp.begin(), temp.end());
113 std::vector<std::string> output(temp.size());
114 for(
int i=0; i<temp.size(); ++i)
115 output.at(i) = temp.at(i).second;
124 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
125 for( boost::tie(
e, e_end)=in_edges(*
v,
graph);
e!=e_end; ++
e ) {
126 if(
graph[*
e]->inputDim == inputIndex){
127 auto vSource = source(*
e,
graph);
128 return graph[vSource]->name;
141 std::vector<std::string> output;
143 boost::graph_traits<Graph>::out_edge_iterator
e, e_end;
144 for( boost::tie(
e, e_end)=out_edges(*
v,
graph);
e!=e_end; ++
e ) {
145 auto vSource = target(*
e,
graph);
146 output.push_back(
graph[vSource]->name);
157 std::vector<std::pair<std::string,int>> names(inputs.size());
158 for(
int i=0; i<inputs.size(); ++i)
159 names.at(i) = std::make_pair(
graph[inputs.at(i).first]->name, inputs.at(i).second);
168 std::vector<std::pair<std::string,int>> names(outputs.size());
169 for(
int i=0; i<outputs.size(); ++i)
170 names.at(i) = std::make_pair(
graph[outputs.at(i).first]->name, outputs.at(i).second);
180 boost::graph_traits<Graph>::vertex_iterator iter;
186 bool WorkGraph::HasNode(boost::graph_traits<Graph>::vertex_iterator& iter, std::string
const& name)
const {
192 return iter!=vertices(
graph).second;
198 throw std::logic_error(
"Could not add node \"" + name +
"\" to graph. A node with that name already exists." );
201 auto node = add_vertex(
graph);
203 graph[node] = std::make_shared<WorkGraphNode>(input, name);
206 void WorkGraph::AddEdge(std::string
const& nameFrom,
unsigned int const outputDim, std::string
const& nameTo,
unsigned int const inputDim) {
209 if(itFrom==vertices(
graph).second)
210 throw std::logic_error(
"Could not add an edge from \"" + nameFrom +
"\" to \"" + nameTo +
"\" because the source node \"" + nameFrom +
"\" does not exist in the graph.");
213 if(itTo==vertices(
graph).second)
214 throw std::logic_error(
"Could not add an edge from \"" + nameFrom +
"\" to \"" + nameTo +
"\" because the target node \"" + nameTo +
"\" does not exist in the graph.");
217 const int numOutputs =
graph[*itFrom]->piece->numOutputs;
218 const int numInputs =
graph[*itTo]->piece->numInputs;
221 if( numOutputs>=0 && outputDim>=numOutputs )
222 throw std::logic_error(
"Could not add an edge from output " +
std::to_string(outputDim) +
"\" of \"" + nameFrom +
"\" to input " +
std::to_string(inputDim) +
" of \"" + nameTo +
"\" because node \"" + nameFrom +
"\" only has " +
std::to_string(numOutputs) +
" outputs.");
225 if( numInputs>=0 && inputDim>=numInputs )
226 throw std::logic_error(
"Could not add an edge from output " +
std::to_string(outputDim) +
"\" of \"" + nameFrom +
"\" to input " +
std::to_string(inputDim) +
" of \"" + nameTo +
"\" because node \"" + nameTo +
"\" only has " +
std::to_string(numInputs) +
" inputs.");
229 const std::string inType =
graph[*itTo]->piece->InputType(inputDim);
230 const std::string outType =
graph[*itFrom]->piece->OutputType(outputDim);
233 if(inType.compare(
"")!=0 &&
234 outType.compare(
"")!=0 &&
235 inType.compare(outType)!=0 ) {
236 std::cerr << std::endl <<
"ERROR: Types do not match in 'WorkGraph::AddEdge'. The input type node '" << nameTo <<
"' is " <<
graph[*itTo]->piece->InputType(inputDim) <<
" but the output type for node '" << nameFrom <<
"' is " <<
graph[*itFrom]->piece->OutputType(outputDim) << std::endl << std::endl;
237 assert(inType.compare(outType)==0);
242 auto modPieceTo = std::dynamic_pointer_cast<ModPiece>(
graph[*itTo]->piece);
243 auto modPieceFrom = std::dynamic_pointer_cast<ModPiece>(
graph[*itFrom]->piece);
244 if((modPieceTo) && (modPieceFrom)){
245 if(modPieceFrom->outputSizes(outputDim) != modPieceTo->inputSizes(inputDim))
246 throw std::logic_error(
"Could not add an edge from output " +
std::to_string(outputDim) +
"\" of \"" + nameFrom +
"\" to input " +
std::to_string(inputDim) +
" of \"" + nameTo +
"\". The output of \"" + nameFrom +
"\" has size " +
std::to_string(modPieceFrom->outputSizes(outputDim)) +
" but the input of \"" + nameTo +
"\" has size " +
std::to_string(modPieceTo->inputSizes(inputDim)) +
".");
249 boost::remove_in_edge_if(*itTo, SameInputDim(inputDim,
graph),
graph);
252 auto temp = boost::add_edge(*itFrom, *itTo,
graph);
255 graph[temp.first] = std::make_shared<WorkGraphEdge>(outputDim, inputDim);
261 boost::graph_traits<Graph>::vertex_iterator
v, v_end;
262 boost::tie(
v, v_end) = vertices(
graph);
272 boost::graph_traits<Graph>::vertex_iterator
v, v_end;
273 boost::tie(
v, v_end) = vertices(
graph);
276 auto res = std::find_if(
v, v_end, [
this,piece](boost::graph_traits<Graph>::vertex_descriptor vertex)->
bool {
return piece==this->
graph[vertex]->piece; } );
284 std::vector<std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int> > outputs;
287 boost::graph_traits<Graph>::vertex_iterator
v, v_end;
288 for( std::tie(
v, v_end)=vertices(
graph);
v!=v_end; ++
v ) {
290 std::vector<int> isSet;
293 const int numOutputs =
graph[*
v]->piece->numOutputs;
296 isSet.reserve(std::max((
int)isSet.capacity(), numOutputs));
299 boost::graph_traits<Graph>::out_edge_iterator
e, e_end;
300 for( tie(
e, e_end)=out_edges(*
v,
graph);
e!=e_end; ++
e ) {
302 isSet.push_back(
graph[*
e]->outputDim);
306 for(
int i=0; i<numOutputs; ++i ) {
307 if( std::find(isSet.begin(), isSet.end(), i)==isSet.end() ) {
309 outputs.push_back(std::make_pair(*
v, i));
315 outputs.push_back(std::make_pair(*
v, -1));
317 if( isSet.size()>0 ) {
319 const unsigned int maxOut = *std::max_element(isSet.begin(), isSet.end());
322 for(
unsigned int i=0; i<maxOut; ++i ) {
323 if( std::find(isSet.begin(), isSet.end(), i)==isSet.end() ) {
325 outputs.push_back(std::make_pair(*
v, i));
337 std::vector<std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int> > inputs;
340 boost::graph_traits<Graph>::vertex_iterator
v, v_end;
341 for( std::tie(
v, v_end)=vertices(
graph);
v!=v_end; ++
v ) {
343 std::vector<int> isSet;
346 const int numInputs =
graph[*
v]->piece->numInputs;
349 isSet.reserve(std::max((
int)isSet.capacity(), numInputs));
352 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
353 for( tie(
e, e_end)=in_edges(*
v,
graph);
e!=e_end; ++
e ) {
355 isSet.push_back(
graph[*
e]->inputDim);
359 for(
int i=0; i<numInputs; ++i ) {
360 if( std::find(std::begin(isSet), std::end(isSet), i)==isSet.end() ) {
362 inputs.push_back(std::make_pair(*
v, i));
368 inputs.push_back(std::make_pair(*
v, -1));
370 if( isSet.size()>0 ) {
372 const unsigned int maxIn = *std::max_element(isSet.begin(), isSet.end());
375 for(
unsigned int i=0; i<maxIn; ++i ) {
376 if( std::find(isSet.begin(), isSet.end(), i)==isSet.end() ) {
378 inputs.push_back(std::make_pair(*
v, i));
388 bool WorkGraph::HasEdge(boost::graph_traits<Graph>::vertex_descriptor
const& vOut, boost::graph_traits<Graph>::vertex_descriptor
const& vIn,
int const inputDim)
const {
390 boost::graph_traits<Graph>::out_edge_iterator ei, ei_end;
391 boost::tie(ei, ei_end) = boost::out_edges(vOut,
graph);
393 for( ; ei!=ei_end ; ++ei ) {
394 if( target(*ei,
graph)==vIn &&
graph[*ei]->inputDim==inputDim ) {
402 void WorkGraph::RecursiveCut(
const boost::graph_traits<Graph>::vertex_descriptor& vOld,
const boost::graph_traits<Graph>::vertex_descriptor& vNew, std::shared_ptr<WorkGraph>& newGraph)
const {
404 std::map<unsigned int, std::pair<boost::graph_traits<Graph>::vertex_descriptor, std::vector<boost::graph_traits<Graph>::in_edge_iterator> > > sources;
407 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
409 for( tie(
e, e_end)=in_edges(vOld,
graph);
e!=e_end; ++
e ) {
411 const unsigned int id =
graph[
v]->piece->ID();
413 auto it = sources.find(
id);
414 if( it==sources.end() ){
415 sources[id] = std::pair<boost::graph_traits<Graph>::vertex_descriptor, std::vector<boost::graph_traits<Graph>::in_edge_iterator> >(
v, std::vector<boost::graph_traits<Graph>::in_edge_iterator>(1,
e));
417 sources[id].second.push_back(
e);
422 for(
auto it : sources ) {
425 auto v = it.second.first;
428 bool isConstantPiece = (std::dynamic_pointer_cast<ConstantVector>(
graph[
v]->piece)!=
nullptr)||(std::dynamic_pointer_cast<ConstantPiece>(
graph[
v]->piece)!=
nullptr);
429 if(
Constant(
v) && (!isConstantPiece) ) {
435 auto nextV = boost::add_vertex(newGraph->graph);
436 newGraph->graph[nextV] = std::make_shared<WorkGraphNode>(std::make_shared<ConstantPiece>(outputs),
graph[
v]->name+
"_fixed");
439 for(
auto e : it.second.second ) {
440 if( !newGraph->HasEdge(nextV, vNew,
graph[*
e]->inputDim) ) {
442 auto nextE = boost::add_edge(nextV, vNew, newGraph->graph);
443 newGraph->graph[nextE.first] = std::make_shared<WorkGraphEdge>(
graph[*
e]->outputDim,
graph[*
e]->inputDim);
452 for(
auto e : it.second.second ) {
453 boost::graph_traits<Graph>::vertex_descriptor nextV;
454 boost::graph_traits<Graph>::vertex_iterator ind;
456 if( newGraph->HasNode(ind,
graph[
v]->name) ) {
461 nextV = boost::add_vertex(newGraph->graph);
462 newGraph->graph[nextV] =
graph[
v];
465 if( !newGraph->HasEdge(nextV, vNew,
graph[*
e]->inputDim ) ) {
467 auto nextE = boost::add_edge(nextV, vNew, newGraph->graph);
468 newGraph->graph[nextE.first] = std::make_shared<WorkGraphEdge>(
graph[*
e]->outputDim,
graph[*
e]->inputDim);
479 auto newGraph = std::make_shared<WorkGraph>();
491 bool isModPiece =
true;
492 for(
const auto& out : outputs ) {
493 if(
typeid(Eigen::VectorXd)!=out.type() ) {
500 auto nextV = boost::add_vertex(newGraph->graph);
502 newGraph->graph[nextV] = std::make_shared<WorkGraphNode>(std::make_shared<ConstantVector>(outputs),
graph[*oldV]->name+
"_fixed");
504 newGraph->graph[nextV] = std::make_shared<WorkGraphNode>(std::make_shared<ConstantPiece>(outputs),
graph[*oldV]->name+
"_fixed");
512 auto newV = boost::add_vertex(newGraph->graph);
515 newGraph->graph[newV] =
graph[*oldV];
533 std::vector<std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int> > inputs = newGraph->GraphInputs();
536 std::vector<std::string> inputNames;
537 inputNames.reserve(inputs.size());
540 for(
auto it=inputs.begin(); it!=inputs.end(); ++it ) {
542 if( newGraph->graph[it->first]->piece->numInputs<0 ) {
543 std::cerr << std::endl <<
"ERROR: Cannot create WorkGraphPiece if one of the nodes has an unknown number of inputs. Node \"" << newGraph->graph[it->first]->name<<
"\" does not specify the number of inputs. " << std::endl << std::endl;
545 assert(newGraph->graph[it->first]->piece->numInputs>=0);
548 std::stringstream temp;
549 temp << newGraph->graph[it->first]->name <<
"_";
552 inputNames.push_back(temp.str());
556 std::vector<std::shared_ptr<ConstantPiece> > constantPieces(inputs.size());
559 std::map<unsigned int, std::string> inTypes;
561 assert(inputNames.size()==inputs.size());
562 assert(constantPieces.size()==inputs.size());
563 for(
unsigned int i=0; i<inputs.size(); ++i ) {
564 const std::string inType = newGraph->graph[inputs.at(i).first]->piece->InputType(inputs.at(i).second,
false);
565 if( inType.compare(
"")!=0 ) {
570 constantPieces[i] = std::make_shared<ConstantPiece>();
571 newGraph->AddNode(constantPieces[i], inputNames[i]);
572 newGraph->AddEdge(inputNames[i], 0, newGraph->graph[inputs[i].first]->name, inputs[i].second);
576 auto outNode = newGraph->GetNodeIterator(node);
579 if(outNode == vertices(newGraph->graph).second){
580 std::string node_fixed = node +
"_fixed";
581 outNode = newGraph->GetNodeIterator(node_fixed);
582 assert(outNode != vertices(newGraph->graph).second);
586 return std::make_shared<WorkGraphPiece>(newGraph, constantPieces, inputNames, inTypes, newGraph->graph[*outNode]->piece);
601 std::vector<std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int> > inputs;
603 if( inNames.size()>0 ) {
604 for(
unsigned int i=0; i<inNames.size(); ++i ) {
605 boost::graph_traits<Graph>::vertex_iterator it;
606 const bool has = newGraph->HasNode(it, inNames[i]);
610 const int numInputs = newGraph->graph[*it]->piece->numInputs;
611 std::vector<int> isSet;
612 isSet.reserve(numInputs);
615 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
616 for( tie(
e, e_end)=in_edges(*it, newGraph->graph);
e!=e_end; ++
e ) {
618 isSet.push_back(
graph[*
e]->inputDim);
622 for(
int j=0; j<numInputs; ++j ) {
623 if( std::find(std::begin(isSet), std::end(isSet), j)==isSet.end() ) {
624 inputs.push_back(std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int>(*it, j));
629 inputs = newGraph->GraphInputs();
633 std::vector<std::string> inputNames;
634 inputNames.reserve(inputs.size());
637 for(
auto it=inputs.begin(); it!=inputs.end(); ++it ) {
639 if( newGraph->graph[it->first]->piece->numInputs<0 ) {
640 std::cerr << std::endl <<
"ERROR: Cannot create WorkGraphPiece if one of the nodes has an unknown number of inputs. Node \"" << newGraph->graph[it->first]->name<<
"\" does not specify the number of inputs. " << std::endl << std::endl;
642 assert(newGraph->graph[it->first]->piece->numInputs>=0);
645 std::stringstream temp;
646 temp << newGraph->graph[it->first]->name <<
"_";
649 inputNames.push_back(temp.str());
653 std::vector<std::shared_ptr<ConstantVector> > constantPieces(inputs.size());
655 assert(inputNames.size()==inputs.size());
656 assert(constantPieces.size()==inputs.size());
658 for(
unsigned int i=0; i<inputs.size(); ++i ) {
660 assert(newGraph->graph[inputs.at(i).first]->piece);
661 auto modIn = std::dynamic_pointer_cast<ModPiece>(newGraph->graph[inputs.at(i).first]->piece);
663 std::cerr <<
"\nERROR: Could not cast node \"" << newGraph->graph[inputs.at(i).first]->name <<
"\" to a ModPiece." << std::endl << std::endl;
668 constantPieces.at(i) = std::make_shared<ConstantVector>(Eigen::VectorXd::Zero(modIn->inputSizes(inputs.at(i).second)));
669 newGraph->AddNode(constantPieces.at(i), inputNames.at(i));
670 newGraph->AddEdge(inputNames.at(i), 0,
671 newGraph->graph[inputs.at(i).first]->name, inputs.at(i).second);
675 auto outNode = newGraph->GetNodeIterator(node);
678 if(outNode == vertices(newGraph->graph).second){
679 std::string node_fixed = node +
"_fixed";
680 outNode = newGraph->GetNodeIterator(node_fixed);
681 assert(outNode != vertices(newGraph->graph).second);
684 assert(newGraph->graph[*outNode]->piece);
687 auto outmod = std::dynamic_pointer_cast<ModPiece>(newGraph->graph[*outNode]->piece);
689 std::cerr << std::endl <<
"ERROR: Cannot cast output node " << node <<
" into a ModPiece" << std::endl << std::endl;
693 return std::make_shared<ModGraphPiece>(newGraph, constantPieces, inputNames, outmod);
700 fout <<
"\nNodes:\n";
701 boost::graph_traits<Graph>::vertex_iterator
v, v_end;
703 for (std::tie(
v, v_end) = vertices(
graph);
v != v_end;
v++) {
704 fout <<
"\t" <<
graph[*
v]->name << std::endl;
709 boost::graph_traits<Graph>::edge_iterator
e, e_end;
710 for (std::tie(
e, e_end) = edges(
graph);
e != e_end;
e++) {
722 boost::graph_traits<Graph>::vertex_iterator
v, v_end;
723 boost::tie(
v, v_end) = vertices(
graph);
729 auto ptr =
graph[*iter];
738 return graph[it]->piece;
743 bool operator()(
const T& in)
760 boost::remove_in_edge_if(*nodeDesc, TrueOp(),
graph);
763 auto mod = std::dynamic_pointer_cast<ModPiece>((
graph)[*nodeDesc]->piece);
766 std::vector<Eigen::VectorXd> vec(x.size());
767 for(
unsigned int i=0; i<x.size(); ++i ) {
768 vec[i] = boost::any_cast<Eigen::VectorXd const>(x[i]);
770 (
graph)[*nodeDesc]->piece = std::make_shared<ConstantVector>(vec);
773 (
graph)[*nodeDesc]->piece = std::make_shared<ConstantPiece>(x);
778 unsigned int inputDim,
784 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
786 for (std::tie(
e, e_end) = boost::in_edges(*nodeDesc,
graph);
e != e_end;
e++) {
787 if ((
graph)[*
e]->inputDim == inputDim) {
788 boost::remove_edge(*
e,
graph);
793 std::string newName = nodeName +
"_FixedInput" +
std::to_string(inputDim);
794 auto newPiece = std::make_shared<ConstantPiece>(std::vector<boost::any>(1,x));
796 AddEdge(newName, 0, nodeName, inputDim);
799 class MyVertexWriter {
802 MyVertexWriter(
Graph const& graph) : graph(graph) {}
804 void operator()(std::ostream& out,
const boost::graph_traits<Graph>::vertex_descriptor&
v)
const {
808 auto workPtr = graph[
v]->piece;
811 const std::string nodeName = workPtr->Name();
814 const std::string style =
"colorscheme=pastel16,color=2, style=filled";
817 out <<
"[label=\"" << graph[
v]->name <<
" : " << nodeName <<
"\", " << style <<
"]";
828 MyEdgeWriter(
Graph const& graph) : graph(graph) {}
830 void operator()(std::ostream& out,
const boost::graph_traits<Graph>::edge_descriptor&
e)
const {
831 const unsigned int inputDim = graph[
e]->inputDim;
833 const unsigned int outputDim = graph[
e]->outputDim;
836 out <<
"[label=\" [out, in]: [" << outputDim <<
", " << inputDim <<
"]\"]";
844 class MyGraphWriter {
847 MyGraphWriter(
Graph const& graph) : graph(graph) {}
849 void operator()(std::ostream& out)
const {
850 out <<
"splines = true;" << std::endl;
859 std::vector<std::string> strs;
860 boost::split(strs, filename, boost::is_any_of(
"."));
863 const bool knownExtension = (strs.end()-1)->compare(
"png") || (strs.end()-1)->compare(
"jpg") || (strs.end()-1)->compare(
"tif") || (strs.end()-1)->compare(
"eps") || (strs.end()-1)->compare(
"pdf") || (strs.end()-1)->compare(
"svg");
868 const std::string tempname = *strs.begin() +
"_temp.dot";
869 if( knownExtension ) {
874 fout.open(filename.c_str());
877 typedef std::map<boost::graph_traits<Graph>::vertex_descriptor,
size_t> IndexMap;
879 boost::associative_property_map<IndexMap> propmapIndex(mapIndex);
883 put(propmapIndex,
v, vertexNum++);
886 boost::write_graphviz(fout,
graph, MyVertexWriter(
graph), MyEdgeWriter(
graph), MyGraphWriter(
graph), propmapIndex);
888 fout.seekp(-2, std::ios_base::cur);
891 std::vector<std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int> > graphInputs =
GraphInputs();
894 for(
auto aPair : graphInputs ) {
896 if( aPair.second<0 ) {
897 fout << vertexNum <<
"[label=\"Unfixed input\", shape=invhouse,colorscheme=pastel13,color=1, style=filled];" << std::endl;
898 fout << vertexNum <<
"->" << propmapIndex[aPair.first] << std::endl;
900 fout << vertexNum <<
"[label=\"Input #" << in <<
"\", shape=invhouse,colorscheme=pastel13,color=1, style=filled];" << std::endl;
901 fout << vertexNum <<
"->" << propmapIndex[aPair.first] <<
"[label=\" in: " << aPair.second <<
"\"];" << std::endl;
907 std::vector<std::pair<boost::graph_traits<Graph>::vertex_descriptor,
int> > graphOutputs =
GraphOutputs();
910 for(
auto aPair : graphOutputs ) {
912 if( aPair.second<0 ) {
913 fout << vertexNum <<
"[label=\"Unfixed output\", shape=box,colorscheme=pastel16,color=1, style=filled];" << std::endl;
914 fout << propmapIndex[aPair.first] <<
"->" << vertexNum << std::endl;
916 fout << vertexNum <<
"[label=\"Output #" << out <<
"\", shape=box,colorscheme=pastel16,color=1, style=filled];" << std::endl;
917 fout << propmapIndex[aPair.first] <<
"->" << vertexNum <<
"[label=\" out: " << aPair.second <<
"\"];" << std::endl;
922 fout <<
"}" << std::endl;
927 if( knownExtension ) {
929 std::system((
"dot -T" + *(strs.end() - 1) +
" " + tempname +
" -o " + filename).c_str());
932 std::system((
"rm "+tempname).c_str());
948 auto work =
graph[node]->piece;
951 assert(work->numInputs>=0);
954 if( work->numInputs==0 ) {
956 return work->outputs;
960 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
963 std::map<unsigned int, std::pair<boost::graph_traits<Graph>::vertex_descriptor, std::vector<std::pair<unsigned int, unsigned int> > > > inMap;
966 for( tie(
e, e_end)=in_edges(node,
graph);
e!=e_end; ++
e ) {
968 const unsigned int id =
graph[source(*
e,
graph)]->piece->ID();
969 const unsigned int inNum =
graph[*
e]->inputDim;
970 const unsigned int outNum =
graph[*
e]->outputDim;
973 auto it = inMap.find(
id);
974 if( it==inMap.end() ) {
975 inMap[id] = std::pair<boost::graph_traits<Graph>::vertex_descriptor, std::vector<std::pair<unsigned int, unsigned int> > >(boost::source(*
e,
graph), std::vector<std::pair<unsigned int, unsigned int> >(1, std::pair<unsigned int, unsigned int>(outNum, inNum)));
977 inMap[id].second.push_back(std::pair<unsigned int, unsigned int>(outNum, inNum));
982 boost::any empty(
nullptr);
986 for(
auto it : inMap ) {
991 for(
auto out_in : it.second.second ) {
993 ins.at(out_in.second) = upstreamOutputs.at(out_in.first);
999 return work->outputs;
1008 auto work =
graph[node]->piece;
1011 if( work->numInputs==0 ) {
return true; }
1014 if( in_degree(node,
graph)!=work->numInputs ) {
return false; }
1017 bool constant =
true;
1020 boost::graph_traits<Graph>::in_edge_iterator
e, e_end;
1023 for( tie(
e, e_end)=in_edges(node,
graph);
e!=e_end; ++
e ) {
std::vector< std::pair< std::string, int > > GetOutputNames() const
Find the outputs to the graph.
void AddNode(std::shared_ptr< WorkPiece > input, std::string const &name)
Add a new node to the graph.
void AddEdge(std::string const &nameFrom, unsigned int const outputDim, std::string const &nameTo, unsigned int const inputDim)
Add a new edge to the graph.
unsigned int NumEdges() const
Get the number of edgess in the graph.
std::shared_ptr< WorkGraph > DependentCut(std::string const &nameOut) const
Create a new graph cutting any of the nodes that do not affect the output node.
virtual std::shared_ptr< WorkGraph > Clone() const
Graph graph
The directed graph that represents this muq::Modeling::Core::WorkGraph.
std::shared_ptr< ModGraphPiece > CreateModPiece(std::string const &node, std::vector< std::string > const &inNames=std::vector< std::string >()) const
Create a muq::Modeling::ModPiece whose output matches a given node.
std::shared_ptr< WorkPiece > GetPiece(std::string const &name)
void RemoveNode(std::string const &name)
void BindEdge(std::string const &nodeName, unsigned int inputDim, boost::any const &x)
std::string GetParent(std::string const &name, int inputIndex) const
std::vector< std::pair< std::string, int > > GetInputNames() const
Find the inputs to the graph.
std::string GetName(std::shared_ptr< WorkPiece > piece) const
bool HasEdge(boost::graph_traits< Graph >::vertex_descriptor const &vOut, boost::graph_traits< Graph >::vertex_descriptor const &vIn, int const inputDim) const
Is there an edge between two vertices?
void Print(std::ostream &fout=std::cout) const
void Visualize(std::string const &filename) const
Visualize the graph.
boost::graph_traits< Graph >::vertex_iterator GetNodeIterator(std::string const &name) const
Get a vertex_iterator to the node with name "name".
void RecursiveCut(const boost::graph_traits< Graph >::vertex_descriptor &vOld, const boost::graph_traits< Graph >::vertex_descriptor &vNew, std::shared_ptr< WorkGraph > &newGraph) const
Recursively go upstream from a node, copying nodes.
std::shared_ptr< WorkGraphPiece > CreateWorkPiece(std::string const &node) const
Create a muq::Modeling::WorkPiece whose output matches a given node.
std::vector< std::string > GetChildren(std::string const &name) const
std::vector< std::pair< int, int > > GetEdges(std::string const &srcName, std::string const &tgtName)
Returns all edges going from node name1 to node name2.
std::vector< boost::any > const & GetConstantOutputs(std::string const &node) const
Get the output values for a constant node.
std::vector< std::pair< boost::graph_traits< Graph >::vertex_descriptor, int > > GraphInputs() const
Find the inputs to the graph.
std::vector< std::pair< boost::graph_traits< Graph >::vertex_descriptor, int > > GraphOutputs() const
Find the outputs to the graph.
std::vector< std::string > GetParents(std::string const &name) const
void BindNode(std::string const &nodeName, std::vector< boost::any > const &x)
unsigned int NumNodes() const
Get the number of nodes in the graph.
bool Constant(std::string const &node) const
Check to see if a node is constant?
bool HasNode(std::string const &name) const
Is the given node in the graph?
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...
boost::adjacency_list< boost::vecS, boost::vecS, boost::bidirectionalS, std::shared_ptr< WorkGraphNode >, std::shared_ptr< WorkGraphEdge > > Graph
Define a directed graph type.
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
A helper struct that determines if a node in the graph has a given name.