Gurobi unable to find the most optimal Link Utilization

28 views Asked by At
from gurobipy import Model, GRB, quicksum, Env
def calcMLU(trafficMatrix, adjNodes, OSPFflowPaths, SDNNodes):
  params = {
  "WLSACCESSID": '',
  "WLSSECRET": '',
  "LICENSEID": 123,
  }

  env = Env(params=params)

  # Create a new model
  m = Model("network_utilization", env=env)

  # Hide Output
  m.setParam('OutputFlag', 0)

  links = generateLinks(adjNodes)
  demands = generateDemands(trafficMatrix)
  SDNNodes = SDNNodes
  nonSDNNodes = [n for n in adjNodes.keys() if n not in SDNNodes]
  nextHop = generateNextHop(OSPFflowPaths)
  nodes = list(adjNodes.keys())

  # Capacity for each link in the network
  capacities = {link:1000000000 for link in links}

  # Variables representing the flow on each link for each demand
  flow_vars = m.addVars([(demand, link) for demand in demands for link in links], vtype=GRB.CONTINUOUS, name="flow")

  # Utilization variable for each link
  util_vars = m.addVars(links, vtype=GRB.CONTINUOUS, name="util")

  # Auxiliary variable to represent the maximum utilization
  max_util = m.addVar(vtype=GRB.CONTINUOUS, name="max_util")

  # Objective: Minimize the maximum utilization
  m.setObjective(max_util, GRB.MINIMIZE)

  for demand in demands:
    for node in SDNNodes:  # SDNNodes
      inflow = quicksum(flow_vars[demand, (i, j)] for i, j in links if j == node and (demand, (i, j)) in flow_vars)
      outflow = quicksum(flow_vars[demand, (i, j)] for i, j in links if i == node and (demand, (i, j)) in flow_vars)
      # Source node
      if node == demand[0]:
        m.addConstr(outflow - inflow == demands[demand], f'flow_conservation_source_{demand}_{node}')
        #m.addConstr(inflow == 0, f'flow_conservation_source2_{demand}_{node}')
      # Destination node
      elif node == demand[1]:
        m.addConstr(inflow - outflow == demands[demand], f'flow_conservation_sink_{demand}_{node}')
        #m.addConstr(outflow == 0, f'flow_conservation_sink2_{demand}_{node}')
      # Intermediate nodes
      else:
        m.addConstr(inflow == outflow, f'flow_conservation_transit_{demand}_{node}')


  for demand in demands:
    for node in nonSDNNodes:  # nonSDNNodes
      inflow = quicksum(flow_vars[demand, (i, j)] for i, j in links if j == node and (demand, (i, j)) in flow_vars)
      # If Destination node, outflow must be 0, inflow must be demands
      if node == demand[1]:
        outflow = quicksum(flow_vars[demand, (i, j)] for i, j in links if i == node and (demand, (i, j)) in flow_vars)
        m.addConstr(inflow == demands[demand], f'flow_conservation_sink_{demand}_{node}')
        m.addConstr(outflow == 0, f'flow_conservation_sink2_{demand}_{node}')
        continue

      dest = demand[1]
      next = nextHop[node][dest]
      outflow = flow_vars[demand, (node, next)]
      notOutflow = quicksum(flow_vars[demand, (i, j)] for i, j in links if i == node and (demand, (i, j)) in flow_vars and j != next)

      # Source node
      if node == demand[0]:
        m.addConstr(outflow == demands[demand], f'flow_conservation_source_{demand}_{node}')
        m.addConstr(notOutflow == 0, f'flow_conservation_not_source_{demand}_{node}')
        m.addConstr(inflow == 0, f'flow_conservation_source2_{demand}_{node}')
      # Intermediate nodes
      else:
        m.addConstr(inflow == outflow, f'flow_conservation_transit_{demand}_{node}')
        m.addConstr(notOutflow == 0, f'flow_conservation_not_transit_{demand}_{node}')


  # Capacity and utilization constraints for each link
  for link in links:
      link_flow = quicksum(flow_vars[demand, link] for demand in demands if (demand, link) in flow_vars)
      m.addConstr(link_flow <= capacities[link], f'capacity_{link}')
      m.addConstr(util_vars[link] == link_flow / capacities[link], f'utilization_{link}')

  # Constraints to ensure max_util is at least as large as any utilization
  for link in links:
      m.addConstr(max_util >= util_vars[link], f'max_util_constraint_{link}')


  # Solve the model
  m.optimize()

  # Check the number of constraints
  num_constraints = m.NumConstrs
  print(f"Number of constraints: {num_constraints}")

  # Output the results
  if m.status == GRB.OPTIMAL:
      print("Optimal link utilization:")
      for link in links:
          print(f"{link}: {util_vars[link].X:.2%}")
      print(f"Maximum utilization among all links: {max_util.X:.2%}")
  else:
      print("No optimal solution found.")

  # Transpose into Python Dictionary
  LU = generateLU(links, util_vars)
  MLU = max_util.X

  return MLU

A beginner coder here. Need help on Gurobi, may I know why this optimization produced worse result when more nodes are migrating to SDN. Is there any problem with my formulation, sincerely appreciate for all helps. The flow conservation rules seems got issues but I have no idea which part of it went wrong. The MLU gradually getting worse despite more nodes migrated to SDN.

A fix for the code especially in the flow constraints

0

There are 0 answers