30 inline bool IsInRange(
int nnz,
int num_rows,
int parent) {
31 bool out_of_range = (nnz <= 0 || num_rows <= parent);
45 const Map<const SparseMatrix<float, 1>> m(
46 static_cast<int>(g.rows()),
47 static_cast<int>(g.cols()),
48 static_cast<int>(g.nonZeros()),
49 static_cast<const int*
>(g.outerIndexPtr()),
50 static_cast<const int*
>(g.innerIndexPtr()),
52 static_cast<const float*
>(ca.GetPtr()),
53 static_cast<const int*
>(g.innerNonZeroPtr())
82 inline bool is_floating_type(
const std::string & value) {
86 std::strtof(
value.c_str(), &ptr);
90 std::strtof(
value.c_str(), &next);
91 result = *next ==
'\0';
97 template<
typename csr>
98 inline int IMPL_GetCost(
const csr & c,
int parent,
int child) {
101 const auto outer_index_ptr = c.outerIndexPtr();
102 const auto inner_index_ptr = c.innerIndexPtr();
104 return IMPL_ValueArrayIndex(parent, child, outer_index_ptr, inner_index_ptr);
108 float Graph::GetCost(
int parent_id,
int child_id,
const std::string & cost_type)
const{
110 throw std::logic_error(
"Graph must be compressed to read costs using getcost");
113 const int index = IMPL_GetCost(this->
edge_matrix, parent_id, child_id);
114 if (index < 0 )
return NAN;
127 throw NoCost(
"Tried to delete a cost that doesn't already exist!");
136 inline float StringToFloat(
const std::string& str_to_convert) {
142 return std::stof(str_to_convert);
144 catch (std::invalid_argument) {
151 inline std::vector<float> ConvertStringsToFloat(
const std::vector<string>& strings) {
153 std::vector<float> out_floats(strings.size());
156 for (
int i = 0; i < out_floats.size(); i++)
157 out_floats[i] = StringToFloat(strings[i]);
164 const std::string& node_attribute,
165 const std::string & out_attribute,
170 throw std::out_of_range(
"Node Attribute" + node_attribute +
" doesn't exist in the graph!");
179 throw std::out_of_range(
"Cost Set" + out_attribute +
" is the default cost of the graph and can't be overwritten!");
184 const auto& scores = ConvertStringsToFloat(this->
GetNodeAttributes(node_attribute));
190 if (scores[parent.id] == -1)
continue;
193 const auto subgraph = this->
GetIntEdges(parent.id);
195 for (
const IntEdge& edge : subgraph)
198 if (scores[edge.child] == -1)
continue;
206 cost= scores[edge.child];
212 cost= scores[edge.child] + scores[parent.id];
218 cost = scores[parent.id];
223 this->
addEdge(parent.id, edge.child, cost, out_attribute);
234 return this->ordered_nodes.empty() ? 0 :
ordered_nodes.back().id;
241 max_id = std::max(node.id, max_id);
253 return idmap.at(node);
267 throw NoCost(
"Tried to access a key that doesn't exist in the cost_arrays");
281 throw std::logic_error(
"Tried to create cost array with the graph's default name");
298 if (this->
size() < 1)
299 throw std::logic_error(
"Tried to add a cost to a graph with 0 nodes");
328 return (name.empty() || (name == this->default_cost));
331 int IMPL_ValueArrayIndex(
334 const int* outer_index_ptr,
335 const int* inner_index_ptr
338 const int search_start_index = outer_index_ptr[parent_id];
339 const int search_end_index = outer_index_ptr[parent_id + 1];
342 const int* search_start_ptr = inner_index_ptr + search_start_index;
343 const int* search_end_ptr = inner_index_ptr + search_end_index;
346 auto itr = std::find(search_start_ptr, search_end_ptr, child_id);
351 if (itr == search_end_ptr) {
357 int index = std::distance(inner_index_ptr, itr);
369 const auto outer_index_ptr =
edge_matrix.outerIndexPtr();
370 const auto inner_index_ptr =
edge_matrix.innerIndexPtr();
373 int index = IMPL_ValueArrayIndex(parent_id, child_id, outer_index_ptr, inner_index_ptr);
385 if (value_index < 0) {
386 throw std::out_of_range(
"Tried to insert into edge that doesn't exist in default graph. ");
390 cost_set[value_index] = cost;
396 for (
const auto& edge_set : es)
399 const int parent_id = edge_set.parent;
402 for (
const auto& edge : edge_set.children) {
405 const int child_id = edge.child;
406 const float cost = edge.weight;
438 out_csr.data = cost_set.GetPtr();
467 template<
typename csr>
468 inline vector<Edge> IMPL_UndirectedEdges(
const csr& edge_matrix,
const int parent_id,
const Graph * g) {
471 const int node_id = parent_id;
472 if (node_id < 0)
return vector<Edge>();
475 vector<Edge> out_edges;
478 for (
int i = 0; i < edge_matrix.rows(); i++) {
481 if (i == node_id)
continue;
484 if (edge_matrix.coeff(i, node_id) != 0) {
487 float cost = edge_matrix.coeff(i, node_id);
490 Node child_node = g->NodeFromID(i);
493 Edge edge{ child_node, cost };
494 out_edges.push_back(edge);
511 throw std::exception(
"The graph must be compressed!");
514 vector<EdgeSet> out_edges(this->
size());
517 for (
int node_index = 0; node_index < this->
size(); ++node_index) {
518 const int node_id = node_index;
520 auto& edgeset = out_edges[node_id];
521 edgeset.parent = node_id;
524 for (SparseMatrix<float, 1>::InnerIterator it(
edge_matrix, node_index); it; ++it)
527 float cost = it.value();
529 edgeset.children.push_back(IntEdge{ child, cost });
539 if (parent > this->
MaxID())
return std::vector<IntEdge>();
542 std::vector<IntEdge> intedges;
543 for (SparseMatrix<float, 1>::InnerIterator it(
edge_matrix, parent); it; ++it)
546 float cost = it.value();
547 int child = it.col();
550 intedges.push_back(IntEdge{ child, cost });
581 if (new_value > 0 && !(out_total == 0 && count > 0))
586 out_total += new_value;
590 if (count == 0) count = 1;
592 out_total = out_total + (new_value - out_total) /
static_cast<float>(count);
597 throw std::out_of_range(
"Unimplemented aggregation type");
600 assert((out_total == 0 || isnormal(out_total)));
626 template<
typename csr>
627 std::vector<float> Impl_AggregateGraph(
COST_AGGREGATE agg_type,
int num_nodes,
bool directed,
const csr & edge_matrix) {
630 vector<float> out_costs(num_nodes, 0);
634 for (
int k = 0; k < num_nodes; ++k) {
637 const float sum = edge_matrix.row(k).sum();
640 int count = edge_matrix.row(k).nonZeros();
643 Aggregate(out_costs[k], sum, agg_type, count);
653 vector<int> count(num_nodes, 0);
656 for (
int k = 0; k < num_nodes; ++k) {
659 for (csr::InnerIterator it(edge_matrix, k); it; ++it)
662 float cost = it.value();
663 int child = it.col();
664 int parent = it.row();
667 Aggregate(out_costs[parent], cost, agg_type, count[parent]);
668 Aggregate(out_costs[child], cost, agg_type, count[child]);
678 if (this->
needs_compression)
throw std::exception(
"The graph must be compressed!");
687 const EdgeCostSet & cost_array = this->
GetCostArray(cost_type);
688 const TempMatrix cost_matrix= CreateMappedCSR(this->edge_matrix, cost_array);
691 return Impl_AggregateGraph(agg_type, this->
size(), directed, cost_matrix);
695 return (Impl_AggregateGraph(agg_type, this->
size(), directed, this->edge_matrix));
715 throw std::logic_error(
"Tried to add an edge to an alternate cost type while uncompressed!");
731 catch(
const std::out_of_range & e){
763 const int row = parent_id;
766 std::vector<Edge> outgoing_edges;
770 for (SparseMatrix<float, 1>::InnerIterator it(
edge_matrix, row); it; ++it) {
771 const auto col = it.col();
772 float value = it.value();
774 outgoing_edges.emplace_back(Edge(
NodeFromID(col), value));
780 std::vector<Edge> out_edges;
781 for (SparseMatrix<float, 1>::InnerIterator it(
edge_matrix, row); it; ++it) {
782 const auto col = it.col();
785 outgoing_edges.emplace_back(Edge(
NodeFromID(col), value));
791 vector<Edge> incoming_edges;
795 incoming_edges = IMPL_UndirectedEdges(this->edge_matrix, parent_id,
this);
799 incoming_edges = IMPL_UndirectedEdges(this->
MapCostMatrix(cost_type), parent_id,
this);
802 vector<Edge> incoming_and_outgoing(incoming_edges.size() + outgoing_edges.size());
805 std::move(outgoing_edges.begin(), outgoing_edges.end(), incoming_and_outgoing.begin());
806 std::move(incoming_edges.begin(), incoming_edges.end(), incoming_and_outgoing.begin() + outgoing_edges.size());
808 return incoming_and_outgoing;
811 return outgoing_edges;
817 const EdgeCostSet& cost_array = this->
GetCostArray(cost_type);
818 const TempMatrix cost_matrix = CreateMappedCSR(this->edge_matrix, cost_array);
827 void Graph::addEdge(
const Node& parent,
const Node& child,
float score,
const string & cost_type)
840 void Graph::addEdge(
int parent_id,
int child_id,
float score,
const string & cost_type)
857 const int parent_index = parent;
858 const int child_index = child;
866 for (EdgeMatrix::InnerIterator it(
edge_matrix, parent_index); it; ++it) {
867 if (it.col() == child_index)
return true;
877 const int parent_index = parent_id;
878 const int child_index = child_id;
881 if (
HasEdge(parent_index, child_index))
882 edge_matrix.coeffRef(parent_index, child_index) = cost;
886 edge_matrix.insert(parent_index, child_index) = cost;
893 triplets.emplace_back(Eigen::Triplet<float>(parent_id, child_id, cost));
913 edge_matrix.conservativeResize(num_nodes, num_nodes);
923 return (id <= this->
MaxID());
933 bool Graph::HasEdge(
int parent,
int child,
bool undirected,
const string & cost_type)
const {
935 if (!this->
hasKey(parent) || !this->
hasKey(child))
return false;
953 bool check_undirected = undirected ?
HasEdge(child, parent,
false, cost_type) : false;
955 return (!isnan(cost) || check_undirected);
959 bool Graph::HasEdge(
const Node& parent,
const Node& child,
const bool undirected,
const string cost_type)
const {
963 throw std::exception(
"Can't get this for uncompressed matrix!");
969 int parent_id =
getID(parent);
970 int child_id =
getID(child);
973 return HasEdge(parent_id, child_id, undirected);
980 return getID(input_node);
1008 ordered_nodes.push_back(Node());
1020 const vector<vector<int>>& edges,
1021 const vector<vector<float>> & distances,
1022 const vector<Node> & Nodes,
1023 const std::string & default_cost
1029 assert(edges.size() == distances.size());
1030 vector<int> sizes(edges.size());
1031 for (
int i = 0; i < edges.size(); i++)
1032 sizes[i] = edges[i].
size();
1039 for (
int row_num = 0; row_num < edges.size(); row_num++)
1045 const auto & row = edges[row_num];
1046 for (
int i = 0; i < row.size(); i++) {
1049 float dist = distances[row_num][i];
1050 int col_num = row[i];
1066 this->default_cost = default_cost_name;
1069 bool Graph::HasEdge(
const std::array<float, 3>& parent,
const std::array<float, 3>& child,
bool undirected)
const {
1071 const Node p(parent);
1072 const Node c(child);
1073 return HasEdge(p, c, undirected);
1085 std::vector <std::array<float, 3> > out_nodes(n);
1088 for (
int i = 0; i < n; i++) {
1089 out_nodes[i][0] = N[i].x;
1090 out_nodes[i][1] = N[i].y;
1091 out_nodes[i][2] = N[i].z;
1106 int array_size = this->
size() + 1;
1132 cost_map.second.Clear();
1135 void Graph::AddEdges(
const vector<EdgeSet>& edges,
const string& cost_name)
1137 for (
const auto& set : edges)
1142 void Graph::AddEdges(
const vector<vector<IntEdge>> & edges,
const std::string & cost_type) {
1144 for (
int parent = 0; parent < edges.size(); parent++)
1146 const auto& outgoing_edges = edges[parent];
1147 for (
const auto& edge : outgoing_edges)
1148 this->
addEdge(parent, edge.child, edge.weight, cost_type);
1152 void Graph::AddEdges(
const EdgeSet & edges,
const string& cost_name) {
1153 const auto parent = edges.parent;
1156 for (
const auto& edge : edges.children)
1157 this->
addEdge(parent, edge.child, edge.weight);
1159 for (
const auto& edge : edges.children)
1160 this->
addEdge(parent, edge.child, edge.weight, cost_name);
1171 vector<EdgeSet> out_edges(this->
size());
1177 for (
int parent_index = 0; parent_index < this->
size(); ++parent_index) {
1179 auto& edgeset = out_edges[parent_index];
1180 edgeset.parent = parent_index;
1183 for (SparseMatrix<float, 1>::InnerIterator it(
edge_matrix, parent_index); it; ++it)
1186 int child_index = it.col();
1189 float cost = cost_set[cost_index];
1191 edgeset.children.push_back(IntEdge{ child_index, cost });
1199 vector<string> cost_types;
1203 for (
const auto & it : this->edge_cost_maps)
1204 cost_types.push_back(it.first);
1210 std::vector<Node> children;
1212 auto edges = (*this)[n];
1214 for (
auto e : edges) {
1215 children.push_back(e.child);
1225 Subgraph
Graph::GetSubgraph(
const Node & parent_node,
const string & cost_type)
const {
1231 return Subgraph{ parent_node, this->
GetEdgesForNode(parent_id,
false, cost_type) };
1236 if (
id > this->
MaxID())
return;
1244 std::string lower_cased = attribute;
1265 auto node_attr_value_map_it = node_attr_value_map.find(
id);
1267 if (node_attr_value_map_it == node_attr_value_map.end()) {
1269 node_attr_value_map[id] = score;
1272 node_attr_value_map_it = node_attr_value_map.find(
id);
1276 std::string found_attr_value = node_attr_value_map_it->second;
1279 bool score_is_floating_pt = is_floating_type(score);
1282 bool attr_is_floating_pt = is_floating_type(found_attr_value);
1291 if (attr_is_floating_pt) {
1293 if (score_is_floating_pt) {
1295 node_attr_value_map_it->second = score;
1303 if (score_is_floating_pt) {
1308 node_attr_value_map_it->second = score;
1314 const vector<int> &
id,
1315 const string & name,
1316 const vector<string> & scores
1320 if (
id.
size() != scores.size())
1321 throw std::logic_error(
"Tried to pass id and string arrays that are different lengths");
1323 auto scores_iterator = scores.begin();
1325 for (
int node_id :
id) {
1337 if (
node_attr_map.count(attribute) < 1)
return vector<string>();
1350 for (
const auto& it : attr_map)
1353 const int id = it.first;
1354 const string& score = it.second;
1357 out_attributes[id] = score;
1361 return out_attributes;
1387 j[
"nodes"] = json::array();
1390 j[
"nodes"].
push_back(json::array({node[0], node[1], node[2] }));
1392 std::ofstream out_file;
1394 std::string json_str = j.
dump();
1395 out_file.open(path);
1396 out_file.write(json_str.c_str(), json_str.size());
Contains definitions for the Exceptions namespace.
Contains definitions for the HF::SpatialStructures namespace.
Contains definitions for the Graph class.
Contains standard fundamental data structures for representing space used throughout DHARTAPI.
Eigen::SparseMatrix< float, 1 > EdgeMatrix
The type of matrix the graph uses internally.
COST_AGGREGATE
Methods of aggregating the costs for edges for each node in the graph.
@ AVERAGE
Average the cost of all edges.
@ COUNT
Count how many edges this node has.
@ SUM
Add the cost of all edges.
Eigen::Map< const EdgeMatrix > TempMatrix
A mapped matrix of EdgeMatrix. Only owns pointers to memory.
Direction
Node to use for calculating the cost of an edge when converting node attributes to edge costs.
void Aggregate(float &out_total, float new_value, const AGGREGATE_TYPE agg_type, int count=0)
Custom exceptions and error codes used interally by DHARTAPI.
Eigen a C++ template library for linear algebra: matrices, vectors, numerical solvers,...
namespace for Niels Lohmann
@ value
the parser finished reading a JSON value
Thrown when a dependency is missing such as Embree.
void InsertEdgesIntoCostSet(EdgeCostSet &cost_set, const std::vector< EdgeSet > &es)
Insert edges for a specific cost type into a cost set.
void ClearNodeAttributes(std::string name)
Clears the attribute at name and all of its contents from the internal hashmap
bool DumpToJson(const std::string &path)
EdgeMatrix edge_matrix
The underlying CSR containing edge information.
float GetCostForSet(const EdgeCostSet &set, int parent_id, int child_id) const
Get the cost of traversing the edge between parent and child using set.
void ResizeIfNeeded()
Resize the CSR to fit all the nodes in ordered_nodes if needed.
void InsertOrUpdateEdge(int parent_id, int child_id, float score, const std::string &cost_type)
Insert an edge into the default cost array or a new cost array.
std::vector< EdgeSet > GetEdges() const
Get every in the given graph as IDs.
void TripletsAddOrUpdateEdge(int parent_id, int child_id, float cost)
Add a new edge to the triplets list.
bool IsDefaultName(const std::string &name) const
Check if this name belongs to the default graph.
bool needs_compression
If true, the CSR is inaccurate and requires compression.
std::vector< Eigen::Triplet< float > > triplets
Edges to be converted to a CSR when Graph::Compress() is called.
int size() const
Determine how many nodes are in the graph.
float GetCost(int parent_id, int child_id, const std::string &cost_type="") const
get the cost from parent_id to child_id in the given cost_type.
void AddNodeAttributes(const std::vector< int > &id, const std::string &name, const std::vector< std::string > &scores)
Add an attribute to the node at id. If the node at id already has a score for the attribute at name,...
void addEdge(const Node &parent, const Node &child, float score=1.0f, const std::string &cost_type="")
Add a new edge to the graph from parent to child.
TempMatrix MapCostMatrix(const std::string &cost_type) const
Construct a temp matrix for the specific cost type.
void Compress()
Compress the graph to a CSR and enable the usage of several functions.
bool HasCostArray(const std::string &key) const
Check if we have this edge matrix already defined.
bool HasNodeAttribute(const std::string &key) const
Check if this graph has a specific node attribute.
bool nodes_out_of_order
Determines whether or not the graph is using integer nodes.
std::vector< float > AggregateGraph(COST_AGGREGATE agg_type, bool directed=true, const std::string &cost_type="") const
Summarize the costs of every outgoing edge for every node in the graph.
robin_hood::unordered_map< Node, int > idmap
Maps a list of X,Y,Z positions to positions in ordered_nodes.
std::unordered_map< std::string, EdgeCostSet > edge_cost_maps
< The default cost type of the graph.
int MaxID() const
Calculate the maximum ID of any node in the graph.
void AddEdges(const EdgeSet &edges, const std::string &cost_name="")
Add multiple edges to the graph.
Graph(const std::vector< std::vector< int > > &edges, const std::vector< std::vector< float > > &distances, const std::vector< Node > &Nodes, const std::string &default_cost="Distance")
Construct a graph from a list of nodes, edges, and distances.
Node NodeFromID(int id) const
Retrieve the node that corresponds to id.
const std::vector< Edge > operator[](const Node &n) const
CSRPtrs GetCSRPointers(const std::string &cost_type="")
Obtain the size of and pointers to the 3 arrays that comprise this graph's CSR. graph if it isn't com...
void AddNodeAttribute(int id, const std::string &attribute, const std::string &score)
Add an attribute to the node at id
EdgeCostSet & GetOrCreateCostType(const std::string &name)
Get a reference to the edge matrix, or create a new one if it doesn't exist.
std::vector< std::string > GetCostTypes() const
Get an array of all cost names within this graph.
Subgraph GetSubgraph(const Node &parent_node, const std::string &cost_type="") const
Retrieves a Subgraph using a Node.
void ClearCostArrays(const std::string &cost_name="")
Clear one or more cost arrays from the graph.
bool checkForEdge(int parent, int child) const
Determine if an edge between parent and child exists in the graph.
void Clear()
Clear all nodes and edges from the graph.
bool has_cost_arrays
Indicates that the graph has cost arrays.
std::vector< Edge > GetEdgesForNode(int parent_id, bool undirected=false, const std::string &cost_type="") const
Get the edges for the given node.
std::vector< Node > Nodes() const
Get a list of nodes from the graph sorted by ID.
int FindValueArrayIndex(int parent_id, int child_id) const
Get the index of the cost at parent/child.
int next_id
The id for the next unique node.
void CSRAddOrUpdateEdge(int parent_id, int child_id, float cost)
Add a new edge cost to the CSR or update if if a cost already exists.
EdgeCostSet & CreateCostArray(const std::string &name)
Create a new edge matrix.
EdgeCostSet & GetCostArray(const std::string &key)
Get a reference to the edge matrix at the given key.
std::vector< Edge > GetUndirectedEdges(const Node &N, const std::string &cost_type="") const
Get a list of all edges to and from node N.
void AttrToCost(const std::string &node_attribute, const std::string &cost_to_store_as, Direction consider=Direction::INCOMING)
Generate edge costs from a set of node attributes.
robin_hood::unordered_map< int, std::string > NodeAttributeValueMap
std::vector< IntEdge > GetIntEdges(int parent) const
Get children of a specific node as integers.
std::vector< Node > ordered_nodes
A list of nodes contained by the graph.
void InsertEdgeIntoCostSet(int parent_id, int child_id, float score, EdgeCostSet &cost_set)
Add an edge to a cost set between parent_id and child_id.
std::vector< Node > GetChildren(const Node &n) const
Retrieve n's child nodes - n is a parent node
std::vector< std::string > GetNodeAttributes(std::string attribute) const
Get the score for the given attribute of every node in the graph. Nodes that do not have a score for ...
std::vector< std::array< float, 3 > > NodesAsFloat3() const
Get a list of nodes as float arrays.
robin_hood::unordered_map< std::string, NodeAttributeValueMap > node_attr_map
Node attribute type : Map of node id to node attribute.
bool HasEdge(const std::array< float, 3 > &parent, const std::array< float, 3 > &child, bool undirected=false) const
Determine if the graph has an edge from parent to child.
int getID(const Node &node) const
Retrieve the ID for node in this graph.
bool hasKey(int id) const
Check if this ID has already been assigned.
int getOrAssignID(const Node &input_node)
Get the unique ID for this x, y, z position and assign it an new one if it doesn't already exist.
a class to store JSON values
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
void push_back(basic_json &&val)
add an object to an array