LdDl / ch

Contraction Hierarchies (with bidirectional version of Dijkstra's algorithm) technique for computing shortest path in graph.
Apache License 2.0
46 stars 5 forks source link

Receive -1 Always on .ShortestRoute #10

Closed daniel-aaron782 closed 3 years ago

daniel-aaron782 commented 3 years ago

I utilize the osm2ch command to generate the .csv file for Arizona roads. Then I exported the contracted graph with the following:

package main

import (
    "github.com/LdDl/ch"
    "fmt"
    "os"
    "bufio"
    "io"
    "strconv"
    "encoding/csv"
)

func main() {
    g := ch.Graph{} // Prepare variable for storing graph
    fmt.Println("Preparing Graph")
    graphFromCSV(&g, "data/graph.csv") // Import CSV-file file into programm
    fmt.Println("Preparing Contracted")
    g.PrepareContracts() // Compute contraction hierarchies
    fmt.Println("writing to file")
    err := g.ExportToFile("data/export_pgrouting.csv")
    if err != nil {
        fmt.Println(err)
        return
    }

}

func graphFromCSV(graph *ch.Graph, fname string) error {
    file, err := os.Open(fname)
    if err != nil {
        return err
    }
    defer file.Close()
    reader := csv.NewReader(bufio.NewReader(file))

    reader.Comma = ';'

    _, err = reader.Read()
    if err != nil {
        return err
    }

    for {
        record, err := reader.Read()
        if err == io.EOF {
            break
        }
        source, err := strconv.ParseInt(record[0], 10, 64)
        if err != nil {
            return err
        }

        target, err := strconv.ParseInt(record[1], 10, 64)
        if err != nil {
            return err
        }

        oneway := record[2]
        weight, err := strconv.ParseFloat(record[3], 64)
        if err != nil {
            return err
        }

        err = graph.CreateVertex(source)
        if err != nil {
            return err
            fmt.Println("This is the Source")
            fmt.Println(err)
        }
        err = graph.CreateVertex(target)
        if err != nil {
            return err
            fmt.Println("This is the Target")
            fmt.Println(err)
        }

        err = graph.AddEdge(source, target, weight)
        if err != nil {
            return err
        }
        if oneway == "B" {
            err = graph.AddEdge(target, source, weight)
            if err != nil {
                return err
            }
        }
    }
    return nil
}

This seemed to work and produced a new file. But whenever I execute the .Shortest Route command it will always give me -1 for the ans. Here is what my code looks like:

package main

import (
    "github.com/LdDl/ch"
    "fmt"
    "os"
    "bufio"
    "io"
    "strconv"
    "encoding/csv"
    // "github.com/gin-gonic/gin"
)

func main() {
    g := ch.Graph{} // Prepare variable for storing graph
    fmt.Println("Preparing Graph")
    graphFromCSV(&g, "data/export_pgrouting.csv") // Import CSV-file file into program
    u := int64(1794303) // Define source vertex
    v := int64(1787974) // Define target vertex
    fmt.Println("Preparing Shortest Path")
    ans, path := g.ShortestPath(u, v) // Get shortest path and it's cost between source and target vertex
    fmt.Println(ans)
    fmt.Println(path)
}

func graphFromCSV(graph *ch.Graph, fname string) error {
    file, err := os.Open(fname)
    if err != nil {
        return err
    }
    defer file.Close()
    reader := csv.NewReader(bufio.NewReader(file))

    reader.Comma = ';'
    // reader.LazyQuotes = true

    // Read header
    _, err = reader.Read()
    if err != nil {
        return err
    }

    for {
        record, err := reader.Read()
        if err == io.EOF {
            break
        }
        source, err := strconv.ParseInt(record[0], 10, 64)
        if err != nil {
            return err
        }
    //  fmt.Println("This is the Source")
    //  fmt.Println(source)

        target, err := strconv.ParseInt(record[1], 10, 64)
        if err != nil {
            return err
        }

    //  fmt.Println("This is the Target")
    //  fmt.Println(target)

        // if intinslice(source, []int{5606, 5607, 255077, 238618}) == false && intinslice(target, []int{5606, 5607, 255077, 238618}) == false {
        //  continue
        // }

        oneway := record[2]
        weight, err := strconv.ParseFloat(record[3], 64)
        if err != nil {
            return err
        }

        err = graph.CreateVertex(source)
        if err != nil {
            return err
            fmt.Println("This is the Source")
            fmt.Println(err)
        }
        err = graph.CreateVertex(target)
        if err != nil {
            return err
            fmt.Println("This is the Target")
            fmt.Println(err)
        }

        err = graph.AddEdge(source, target, weight)
        if err != nil {
            return err
        }
        if oneway == "B" {
            err = graph.AddEdge(target, source, weight)
            if err != nil {
                return err
            }
        }
    }
    return nil
}

Do you have any ideas what could be causing this?

LdDl commented 3 years ago

Hello, @daniel-aaron782 !

  1. Can you provide link to *.osm file for further usage in osm2ch? (may be https://overpass-api.de/api/map?bbox=YOURS_BBOX_COORDINATES)
  2. Can you can provide *.csv file which used for graphFromCSV(...) call also? <--- This would be even better, because we can investigate what happens with both bidirectional search and vanilla implementation.

Without it we have only 3 options why this happens:

  1. Source vertex is not represented in graph
  2. Target vertex is not represented in graph
  3. Path not found (graph is not connected or it does have isolated vertices/edges)
LdDl commented 3 years ago

By the way, for further usage it's better to call PrepareContracts() for vertices contraction:

...
graphFromCSV(&g, "data/export_pgrouting.csv")
/* GRAPH PREPARATION */
g.PrepareContracts()
/* */
u := int64(1794303)
....
LdDl commented 3 years ago

Closing due inactivity.