github.com/LdDl/ch@v1.7.8/export.go (about) 1 package ch 2 3 import ( 4 "encoding/csv" 5 "fmt" 6 "os" 7 "strconv" 8 "strings" 9 10 "github.com/pkg/errors" 11 ) 12 13 // ExportToFile Exports graph to file of CSV-format 14 // Header of edges CSV-file: 15 // from_vertex_id - int64, ID of source vertex 16 // to_vertex_id - int64, ID of target vertex 17 // weight - float64, Weight of an edge 18 // Header of vertices CSV-file: 19 // vertex_id - int64, ID of vertex 20 // order_pos - int, Position of vertex in hierarchies (evaluted by library) 21 // importance - int, Importance of vertex in graph (evaluted by library) 22 // Header of shortcuts CSV-file: 23 // from_vertex_id - int64, ID of source vertex 24 // to_vertex_id - int64, ID of target vertex 25 // weight - float64, Weight of an shortcut 26 // via_vertex_id - int64, ID of vertex through which the shortcut exists 27 func (graph *Graph) ExportToFile(fname string) error { 28 29 fnamePart := strings.Split(fname, ".csv") // to guarantee proper filename and its extension 30 31 err := graph.ExportEdgesToFile(fnamePart[0] + ".csv") 32 if err != nil { 33 return errors.Wrap(err, "Can't export edges") 34 } 35 36 // Write reference information about vertices 37 err = graph.ExportVerticesToFile(fnamePart[0] + "_vertices.csv") 38 if err != nil { 39 return errors.Wrap(err, "Can't export shortcuts") 40 } 41 42 // Write reference information about contractions 43 err = graph.ExportShortcutsToFile(fnamePart[0] + "_shortcuts.csv") 44 if err != nil { 45 return errors.Wrap(err, "Can't export shortcuts") 46 } 47 48 return nil 49 } 50 51 // ExportVerticesToFile Exports edges information to CSV-file with header: 52 // from_vertex_id - int64, ID of source vertex 53 // to_vertex_id - int64, ID of target vertex 54 // weight - float64, Weight of an edge 55 func (graph *Graph) ExportEdgesToFile(fname string) error { 56 file, err := os.Create(fname) 57 if err != nil { 58 return errors.Wrap(err, "Can't create edges file") 59 } 60 defer file.Close() 61 62 writer := csv.NewWriter(file) 63 defer writer.Flush() 64 writer.Comma = ';' 65 err = writer.Write([]string{"from_vertex_id", "to_vertex_id", "weight"}) 66 if err != nil { 67 return errors.Wrap(err, "Can't write header to edges file") 68 } 69 70 for i := range graph.Vertices { 71 currentVertexExternal := graph.Vertices[i].Label 72 currentVertexInternal := graph.Vertices[i].vertexNum 73 // Write reference information about "outcoming" adjacent vertices 74 // Why don't write info about "incoming" adjacent vertices also? Because all edges will be covered due the loop iteration mechanism 75 outcomingNeighbors := graph.Vertices[i].outIncidentEdges 76 for j := range outcomingNeighbors { 77 toVertexExternal := graph.Vertices[outcomingNeighbors[j].vertexID].Label 78 toVertexInternal := outcomingNeighbors[j].vertexID 79 cost := outcomingNeighbors[j].weight 80 if _, ok := graph.shortcuts[currentVertexInternal][toVertexInternal]; !ok { 81 err = writer.Write([]string{ 82 fmt.Sprintf("%d", currentVertexExternal), 83 fmt.Sprintf("%d", toVertexExternal), 84 strconv.FormatFloat(cost, 'f', -1, 64), 85 }) 86 if err != nil { 87 return errors.Wrap(err, "Can't write edge information") 88 } 89 } 90 } 91 } 92 93 return nil 94 } 95 96 // ExportVerticesToFile Exports vertices information to CSV-file with header: 97 // vertex_id - int64, ID of vertex 98 // order_pos - int, Position of vertex in hierarchies (evaluted by library) 99 // importance - int, Importance of vertex in graph (evaluted by library) 100 func (graph *Graph) ExportVerticesToFile(fname string) error { 101 fileVertices, err := os.Create(fname) 102 if err != nil { 103 return errors.Wrap(err, "Can't create vertices file") 104 } 105 defer fileVertices.Close() 106 writerVertices := csv.NewWriter(fileVertices) 107 defer writerVertices.Flush() 108 writerVertices.Comma = ';' 109 err = writerVertices.Write([]string{"vertex_id", "order_pos", "importance"}) 110 if err != nil { 111 return errors.Wrap(err, "Can't write header to vertices file") 112 } 113 for i := range graph.Vertices { 114 currentVertexExternal := graph.Vertices[i].Label 115 err = writerVertices.Write([]string{ 116 fmt.Sprintf("%d", currentVertexExternal), 117 fmt.Sprintf("%d", graph.Vertices[i].orderPos), 118 fmt.Sprintf("%d", graph.Vertices[i].importance), 119 }) 120 if err != nil { 121 return errors.Wrap(err, "Can't write vertex information") 122 } 123 } 124 return nil 125 } 126 127 // ExportShortcutsToFile Exports shortcuts information to CSV-file with header: 128 // from_vertex_id - int64, ID of source vertex 129 // to_vertex_id - int64, ID of target vertex 130 // weight - float64, Weight of an shortcut 131 // via_vertex_id - int64, ID of vertex through which the shortcut exists 132 func (graph *Graph) ExportShortcutsToFile(fname string) error { 133 fileShortcuts, err := os.Create(fname) 134 if err != nil { 135 return errors.Wrap(err, "Can't create shortcuts file") 136 } 137 defer fileShortcuts.Close() 138 writerShortcuts := csv.NewWriter(fileShortcuts) 139 defer writerShortcuts.Flush() 140 writerShortcuts.Comma = ';' 141 err = writerShortcuts.Write([]string{"from_vertex_id", "to_vertex_id", "weight", "via_vertex_id"}) 142 if err != nil { 143 return errors.Wrap(err, "Can't write header to shortucts file") 144 } 145 for sourceVertexInternal, to := range graph.shortcuts { 146 sourceVertexExternal := graph.Vertices[sourceVertexInternal].Label 147 for targetVertexInternal, viaNodeInternal := range to { 148 targetVertexExternal := graph.Vertices[targetVertexInternal].Label 149 viaNodeExternal := graph.Vertices[viaNodeInternal.Via].Label 150 err = writerShortcuts.Write([]string{ 151 fmt.Sprintf("%d", sourceVertexExternal), 152 fmt.Sprintf("%d", targetVertexExternal), 153 strconv.FormatFloat(viaNodeInternal.Cost, 'f', -1, 64), 154 fmt.Sprintf("%d", viaNodeExternal), 155 }) 156 if err != nil { 157 return errors.Wrap(err, "Can't write shortcut information") 158 } 159 } 160 } 161 return nil 162 }