3

I have a weighted directed graph where there are no cycles, and I wish to define the constraints so that I can solve a maximization of the weights of a path with linear programming. However, I can't wrap my head around how to do that.

For this I wish to use the LPSolve tool. I thought about making an adjacency matrix, but I don't know how I could make that work with LPSolve.

How can I define the possible paths from each node using constraints and make it generic enough that it would be simple to adapt to other graphs?

josliber
  • 43,891
  • 12
  • 98
  • 133
sharp_c-tudent
  • 463
  • 5
  • 17

1 Answers1

1

Since you have a weighted directed graph, it is sufficient to define a binary variable x_e for each edge e and to add constraints specifying that the source node has flow balance 1 (there is one more outgoing edge selected than incoming edge), the destination node has flow balance -1 (there is one more incoming edge than outgoing edge selected), and every other node has flow balance 0 (there are the same number of outgoing and incoming edges selected). Since your graph has no cycles, this will result in a path from the source to the destination (assuming one exists). You can maximize the weights of the selected edges.

I'll continue the exposition in R using the lpSolve package. Consider a graph with the following edges:

(edges <- data.frame(source=c(1, 1, 2, 3), dest=c(2, 3, 4, 4), weight=c(2, 7, 3, -4)))
#   source dest weight
# 1      1    2      2
# 2      1    3      7
# 3      2    4      3
# 4      3    4     -4

The shortest path from 1 to 4 is 1 -> 2 -> 4, with weight 5 (1 -> 3 -> 4 has weight 3).

We need the flow balance constraints for each of our four nodes:

source <- 1
dest <- 4
(nodes <- unique(c(edges$source, edges$dest)))
# [1] 1 2 3 4
(constr <- t(sapply(nodes, function(n) (edges$source == n) - (edges$dest == n))))
#      [,1] [,2] [,3] [,4]
# [1,]    1    1    0    0
# [2,]   -1    0    1    0
# [3,]    0   -1    0    1
# [4,]    0    0   -1   -1
(rhs <- ifelse(nodes == source, 1, ifelse(nodes == dest, -1, 0)))
# [1]  1  0  0 -1

Now we can put everything together into our model and solve:

library(lpSolve)
mod <- lp(direction = "max", 
          objective.in = edges$weight,
          const.mat = constr,
          const.dir = rep("=", length(nodes)),
          const.rhs = rhs,
          all.bin = TRUE)
edges[mod$solution > 0.999,]
#   source dest weight
# 1      1    2      2
# 3      2    4      3
mod$objval
# [1] 5
josliber
  • 43,891
  • 12
  • 98
  • 133