3

I have the following python code:

import networkx as nx 

def cost(i, j, d, value1, value2):
    # some operation involving all these values
    return cost


# graph is a networkx graph
# src, dst are integers
# cost is a callable that is passed 3 values automatically i.e. src, dst and d 
# d is a dictionary of edge weights
path = nx.dijkstra_path(graph, src, dst, weight=cost)

Now I want to pass two values value1 and value2 to the cost function.

The networkx documentation says the weight can be a callable that accepts exactly 3 arguments. But i need value1 and value2 for calculations. How can this be done?

Edit The solution using functools works well. However, my function is in a class as follows:

import networkx as nx 
import functools
class Myclass:
    def cost(self, i, j, d, value2):
        # some operation involving all these values
        # also need self


    # graph is a networkx graph
    # src, dst are integers
    # cost is a callable that is passed 3 values automatically i.e. src, dst and d 
    # d is a dictionary of edge weights
    # path = nx.dijkstra_path(graph, src, dst, cost)
    cost_partial = functools.partial(cost, self=self, value2=5)
    path = nx.dijkstra_path(graph, src, dst, cost_partial)

Using this approach, nx.dijkstra_path insists upon assigning src to self. Thus the interpreter complains that self is assigned multiple values. I need self for calculating the cost.

Niloy Saha
  • 444
  • 2
  • 4
  • 14

2 Answers2

12

You just need a function that wraps cost. A quick way is to use functools.partial.

import functools

def cost(i, j, d, value1, value2):
    'Example function'
    return i, j, d, value1, value2

# This makes a new function which takes all parameters of `cost` except those 
# you've already passed. Here I'm going to set value1 and value2 to 1 and 2 
# respectively.
cost_partial = functools.partial(cost, value1=1, value2=2)

# A new function that only accepts the 3 args i, j, d
cost_partial('i', 'j', 'd')  # --> ('i', 'j', 'd', 1, 2)

# use as
path = nx.dijkstra_path(graph, src, dst, weight=cost_partial)
FHTMitchell
  • 11,793
  • 2
  • 35
  • 47
  • Just to confirm that this solution worked like a charm for me in a similar case, trying to pass a fourth parameter to the filter_edge callable of the networkx.classes.function.subgraph_view(G, filter_node, filter_edge) function in networkx. Many thanks! – whydoesntwork Jul 04 '21 at 14:14
3

This depends largely on the meaning on the meaning of value1 and value2. I would suggest adding a wrapper callable by networkx:

def cost_wrapper(i, j, d):
    value1 = 0  # set values as needed
    value2 = 1
    return cost(i, j, d, value1, value2)

And provide it to networkx:

path = nx.dijkstra_path(graph, src, dst, weight=cost_wrapper)

Or simply make them global variables, not arguments.

Sianur
  • 639
  • 6
  • 13