Skip to content

Expand the covered use cases by allowing to specify a edge weight function #26

Open
@tvercaut

Description

Dijkstra's algorithm finds shortest paths based on weigths assigned to edges in a graph. As far as I understand it, in dijkstra3d, given a field image, a directed graph is implicitly constructed by using a voxel connectivity pattern and the edge weights are implicitly given by the value of the field image at the target of the edge (as per the readme):

For given input voxels A and B, the edge weight from A to B is B and from B to A is A.

While this covers some important use cases, it would also be interesting to allow for a more generic means of computing the edge weigths while retaining the implicit graph handling of dijkstra3d. In particular, allowing the user to specify a function taking as input the value of the field image at the edge source and edge target but also taking as input the type of edge (center->left, top-right->center, bottom->center, etc.) would be great.

I have created a simple python notebook to illustrate this concept in 2D but relying on networkx as the backend:
https://colab.research.google.com/drive/196EPtBO0BmIjYmi6RlBvLlD_JGyAE9zB?usp=sharing

I am not entirely sure how this should best be implemented in dijkstra3d but I guess one could create a functor in c++ (let's call it edgeweightfunc). edgeweightfunc would then be called instead of fetching only the edge target value (which seems to be done with delta = static_cast<float>(field[neighboridx]); in dijkstra3d:

delta = static_cast<float>(field[neighboridx]); // high cache miss

For brainstorming purposes, a basic concept of what such an edgeweightfunc could look like (in 2D) and in c++ is below:

#include <iostream>
#include <cmath>
#include <array>

int main()
{
    // Encode edge type in 2D (xf: x forward - xb: x backward)
    // There are surely better ways of doing this including using
    // boolean operations to combine x, y and z modes
    // see e.g. https://en.cppreference.com/w/cpp/named_req/BitmaskType
    enum EdgeType : int { xf, xb, yf, yb, xfyf, xfyb, xbyf, xbyb };
    
    // This is the functor we would pass to dijkstra::distance_field3d
    auto edgeweightfunc = [](auto edgesourceval, auto edgetargetval, EdgeType edgetype ) {
        constexpr std::array<double,8> edgedists2 { 1., 1., 1., 1., 2., 2., 2., 2. };
        // we could also use std::hypot
        auto squarefunc = [](auto x) {return x*x;};
        return std::sqrt( edgedists2[edgetype] + squarefunc(edgesourceval - edgetargetval) );
    };
    
    std::cout << "Edge weight: " << edgeweightfunc(5.0,3.0,EdgeType::xbyb) << std::endl;
}

I haven't looked at how such c++ functors can be bound to python but I assume a solution can be found...

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions