/// <summary> /// Fills the given array with the dynamic part of the edge-data. /// </summary> public int FillWithDynamicData(ref uint[] data) { var p = _currentEdgePointer + _graph._fixedEdgeDataSize; if (DirectedDynamicGraph.IsLastField(_graph._edges[p])) { // no dynamic data! return(0); } var i = 0; p++; do { data[i] = _graph._edges[p]; if (DirectedDynamicGraph.IsLastField(data[i])) { data[i] = DirectedDynamicGraph.RemoveFlags(data[i]); break; } i++; p++; } while (true); return(i + 1); }
/// <summary> /// Moves to the next edge and returns the pointer of that next edge. Returns NO_EDGE if no next edge was found. /// /// The given pointer is expected to be the first position of an edge. /// </summary> private uint MoveNextEdge(uint edgePointer) { // move past first fixed-data fields to the last one. var data = _edges[edgePointer]; if (data == NO_EDGE) { // just move to the first non-NO_EDGE field. while (data == NO_EDGE) { edgePointer++; data = _edges[edgePointer]; } return(edgePointer); } edgePointer += (uint)_fixedEdgeDataSize; data = _edges[edgePointer]; while (!DirectedDynamicGraph.IsLastField(data)) { // move until the last data field. edgePointer++; data = _edges[edgePointer]; } if (DirectedDynamicGraph.IsLastFieldInLastEdge(data)) { // if the last data field is the last edge then just stop. return(NO_EDGE); } edgePointer++; data = _edges[edgePointer]; while (data == NO_EDGE) { edgePointer++; data = _edges[edgePointer]; } return(edgePointer); }
/// <summary> /// Fills the given array with the fixed data. /// </summary> public int FillWithData(ref uint[] data) { for (var i = 0; i < _graph._fixedEdgeDataSize && i < data.Length; i++) { data[i] = DirectedDynamicGraph.RemoveFlags(_graph._edges[_currentEdgePointer + 1 + i]); } return(System.Math.Min(_graph._fixedEdgeDataSize, data.Length)); }
/// <summary> /// Returns enumerator for the given vertex. Throws an exception if the vertex is not in the graph. /// </summary> public static DirectedDynamicGraph.EdgeEnumerator GetEdgeEnumerator(this DirectedDynamicGraph graph, uint vertex) { var enumerator = graph.GetEdgeEnumerator(); if (!enumerator.MoveTo(vertex)) { throw new Exception("Vertex does not exist."); } return(enumerator); }
/// <summary> /// Marks the edge at the given location as the last edge. /// </summary> /// <returns>False if there is no data at the given location, true otherwise.</returns> private bool MarkAsLast(uint edgePointer) { var data = _edges[edgePointer]; if (data == NO_EDGE) { return(false); } while (!DirectedDynamicGraph.IsLastField(data)) { edgePointer++; data = _edges[edgePointer]; } data = DirectedDynamicGraph.RemoveFlags(data); _edges[edgePointer] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag( data); return(true); }
/// <summary> /// Removes an edge and moves to the next edge after the removed edge. Returns NO_EDGE if no next edge was found. /// /// The given pointer is expected to be the first position of an edge starting a the given vertex. The previous edge pointer is NO_EDGE if there is not previous edge. /// </summary> private uint RemoveEdge(uint vertex, uint previousEdgePointer, uint edgePointer, uint nextPointer) { var originalEdgePointer = edgePointer; if (previousEdgePointer == NO_EDGE && nextPointer == NO_EDGE) { // only one edge left. _vertices[vertex] = NO_EDGE; return(NO_EDGE); } var startPointer = edgePointer; // remove the fixed-data. for (var i = 0; i < _fixedEdgeDataSize - 1; i++) { _edges[edgePointer] = NO_EDGE; edgePointer++; } var data = _edges[edgePointer]; while (!DirectedDynamicGraph.IsLastField(data)) { // move until the last data field. _edges[edgePointer] = NO_EDGE; edgePointer++; data = _edges[edgePointer]; } if (DirectedDynamicGraph.IsLastFieldInLastEdge(data)) { // if the last data field is the last edge then just stop. if (!this.MarkAsLast(previousEdgePointer)) { // there is no data at the previous edge, this can only mean one thing: no more edges left. _vertices[vertex] = NO_EDGE; } return(NO_EDGE); } _edges[edgePointer] = NO_EDGE; return(edgePointer + 1); }
/// <summary> /// Gets all commonly used data fields in on go. /// </summary> public void GetData(out uint neighbour, out uint data0, out uint data1) { neighbour = _graph._edges[_currentEdgePointer]; data0 = DirectedDynamicGraph.RemoveFlags(_graph._edges[_currentEdgePointer + 0 + 1]); data1 = DirectedDynamicGraph.RemoveFlags(_graph._edges[_currentEdgePointer + 1 + 1]); }
/// <summary> /// Creates a new edge enumerator. /// </summary> public EdgeEnumerator(DirectedDynamicGraph graph) { _graph = graph; _currentEdgePointer = NO_EDGE; _startPointer = NO_EDGE; }
/// <summary> /// Compresses the data in this graph to it's smallest size. /// </summary> public void Compress(bool toReadonly, out long maxEdgeId) { // trim first. this.Trim(); // build a list of all vertices sorted by their first position. var sortedVertices = new MemoryArray <uint>(_vertices.Length); for (uint i = 0; i < sortedVertices.Length; i++) { sortedVertices[i] = i; } // sort vertices and coordinates. QuickSort.Sort((i) => _vertices[sortedVertices[i]] * sortedVertices.Length + sortedVertices[i], (i, j) => { var tempRef = sortedVertices[i]; sortedVertices[i] = sortedVertices[j]; sortedVertices[j] = tempRef; }, 0, this.VertexCount - 1); // move data down. uint pointer = 0; for (uint i = 0; i < sortedVertices.Length; i++) { var vertex = sortedVertices[i]; var vertexPointer = _vertices[vertex]; if (vertexPointer == NO_EDGE) { continue; } _vertices[vertex] = pointer; // skip removed data. var pointerBefore = pointer; while (_edges[vertexPointer] == NO_EDGE) { vertexPointer++; } do { // copy fixed-data. for (var e = 0; e < _fixedEdgeDataSize; e++) { _edges[pointer + e] = _edges[vertexPointer + e]; } pointer += (uint)_fixedEdgeDataSize; vertexPointer += (uint)_fixedEdgeDataSize; while (!DirectedDynamicGraph.IsLastField(_edges[pointer - 1])) { _edges[pointer] = _edges[vertexPointer]; pointer++; vertexPointer++; } } while (!DirectedDynamicGraph.IsLastFieldInLastEdge(_edges[pointer - 1])); var count = pointer - pointerBefore; if (!toReadonly && count > 2 && !((count & (count - 1)) == 0)) { // next power of 2, don't do this on readonly to save space. count |= count >> 1; count |= count >> 2; count |= count >> 4; count |= count >> 8; count |= count >> 16; count++; pointer += (count - (pointer - pointerBefore)); } } _nextEdgePointer = pointer; _readonly = toReadonly; // store the max edge id. _edges.Resize(_nextEdgePointer); maxEdgeId = _edges.Length; }
/// <summary> /// Adds an edge with the associated data. /// </summary> public uint AddEdge(uint vertex1, uint vertex2, params uint[] data) { if (_readonly) { throw new Exception("Graph is readonly."); } if (vertex1 == vertex2) { throw new ArgumentException("Given vertices must be different."); } if (data == null || data.Length == 0) { throw new ArgumentException("Data payload must contain at least one entry."); } for (var i = 0; i < data.Length; i++) { if (data[i] > MAX_DYNAMIC_PAYLOAD) { throw new ArgumentOutOfRangeException("data", "One of the entries in the data payload is too big."); } } while (vertex1 > _vertices.Length - 1) { this.IncreaseVertexSize(); } while (vertex2 > _vertices.Length - 1) { this.IncreaseVertexSize(); } var vertexPointer = vertex1; var edgePointer = _vertices[vertexPointer]; var edgeId = uint.MaxValue; if (edgePointer == NO_EDGE) { // no edge yet, just add the end. _vertices[vertexPointer] = _nextEdgePointer; edgeId = _nextEdgePointer; if (_nextEdgePointer + data.Length >= _edges.Length) { // make sure we can add another edge. this.IncreaseEdgeSize(); } _edges[_nextEdgePointer] = vertex2; for (var i = 0; i < data.Length - 1; i++) { _edges[_nextEdgePointer + i + 1] = data[i]; } _edges[_nextEdgePointer + data.Length - 1 + 1] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data[data.Length - 1]); _nextEdgePointer += DirectedDynamicGraph.NextPowerOfTwoOrPowerOfTwo((uint)(1 + data.Length)); } else { // there are already edges present for this vertex. var startPointer = edgePointer; edgePointer += (uint)(_fixedEdgeDataSize - 1); while (true) { var e = _edges[edgePointer]; if (e != NO_EDGE && IsLastFieldInLastEdge(e)) { break; } edgePointer++; } // check size and allocate new space or move if needed. var size = edgePointer - startPointer + 1; var totalSpace = NextPowerOfTwoOrPowerOfTwo(size); var requiredSpace = size + 1 + (uint)data.Length; if (requiredSpace > totalSpace) { // allocate enough space. var newTotalSpace = NextPowerOfTwoOrPowerOfTwo(requiredSpace); if (startPointer + totalSpace == _nextEdgePointer) { // at the end, just make sure the edges array is big enough. while (newTotalSpace + startPointer >= _edges.Length) { this.IncreaseEdgeSize(); } _nextEdgePointer += (newTotalSpace - totalSpace); } else { // move everything to the end, there isn't enough free space here. // make sure the edges array is big enough. while (newTotalSpace + _nextEdgePointer >= _edges.Length) { this.IncreaseEdgeSize(); } // move existing data to the end and update pointer. _vertices[vertexPointer] = _nextEdgePointer; for (uint i = 0; i < size; i++) { _edges[_nextEdgePointer + i] = _edges[startPointer + i]; } edgePointer = _nextEdgePointer + size - 1; _nextEdgePointer += newTotalSpace; } } // mark the current field as the non-last field. _edges[edgePointer] = RemoveLastEdgeFlag(_edges[edgePointer]); // add new data. _edges[edgePointer + 1] = vertex2; for (var i = 0; i < data.Length - 1; i++) { _edges[edgePointer + i + 2] = data[i]; } _edges[edgePointer + data.Length - 1 + 2] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data[data.Length - 1]); } _edgeCount++; return(edgeId); }
/// <summary> /// Adds an edge with the associated data. /// </summary> public uint AddEdge(uint vertex1, uint vertex2, uint data) { if (_readonly) { throw new Exception("Graph is readonly."); } if (vertex1 == vertex2) { throw new ArgumentException("Given vertices must be different."); } if (data > MAX_DYNAMIC_PAYLOAD) { throw new ArgumentOutOfRangeException("data", "Data payload too big."); } _vertices.EnsureMinimumSize(Math.Max(vertex1, vertex2) + 1, NO_EDGE); var vertexPointer = vertex1; var edgePointer = _vertices[vertexPointer]; var edgeId = uint.MaxValue; if (edgePointer == NO_EDGE) { // no edge yet, just add the end. _vertices[vertexPointer] = _nextEdgePointer; edgeId = _nextEdgePointer; // make sure we can add another edge. _edges.EnsureMinimumSize(_nextEdgePointer + 2); _edges[_nextEdgePointer] = vertex2; _edges[_nextEdgePointer + 1] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data); _nextEdgePointer += 2; } else { // there are already edges present for this vertex. var startPointer = edgePointer; edgePointer += (uint)(_fixedEdgeDataSize - 1); while (true) { var e = _edges[edgePointer]; if (e != NO_EDGE && IsLastFieldInLastEdge(e)) { break; } edgePointer++; } // check size and allocate new space or move if needed. var size = edgePointer - startPointer + 1; var totalSpace = NextPowerOfTwoOrPowerOfTwo(size); var requiredSpace = size + 2; if (requiredSpace > totalSpace) { // allocate enough space. var newTotalSpace = NextPowerOfTwoOrPowerOfTwo(requiredSpace); if (startPointer + totalSpace == _nextEdgePointer) { // at the end, just make sure the edges array is big enough. _edges.EnsureMinimumSize(newTotalSpace + startPointer + 1); _nextEdgePointer += (newTotalSpace - totalSpace); } else { // move everything to the end, there isn't enough free space here. // make sure the edges array is big enough. _edges.EnsureMinimumSize(newTotalSpace + _nextEdgePointer + 1); // move existing data to the end and update pointer. _vertices[vertexPointer] = _nextEdgePointer; for (uint i = 0; i < size; i++) { _edges[_nextEdgePointer + i] = _edges[startPointer + i]; } edgePointer = _nextEdgePointer + size - 1; _nextEdgePointer += newTotalSpace; } } // mark the current field as the non-last field. _edges[edgePointer] = RemoveLastEdgeFlag(_edges[edgePointer]); // add new data. edgeId = edgePointer + 1; _edges[edgePointer + 1] = vertex2; _edges[edgePointer + 2] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data); } _edgeCount++; return(edgeId); }