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  }