code: def permutation_flow_shop(n,m,p):
      
      model = Model("permutation flow shop")
  
      x,s,f = {},{},{}
      for j in range(1,n+1):
          for k in range(1,n+1):
              x[j,k] = model.addVar(vtype="B", name="x(%s,%s)"%(j,k))
  
      for i in range(1,m+1):
          for k in range(1,n+1):
              s[i,k] = model.addVar(vtype="C", name="start(%s,%s)"%(i,k))
              f[i,k] = model.addVar(vtype="C", name="finish(%s,%s)"%(i,k))
  
      for j in range(1,n+1):
          model.addCons(quicksum(x[j,k] for k in range(1,n+1)) == 1, "Assign1(%s)"%(j))
          model.addCons(quicksum(x[k,j] for k in range(1,n+1)) == 1, "Assign2(%s)"%(j))
  
      for i in range(1,m+1):
          for k in range(1,n+1):
              if k != n:
                  model.addCons(f[i,k] <= s[i,k+1], "FinishStart(%s,%s)"%(i,k))
              if i != m:
                  model.addCons(f[i,k] <= s[i+1,k], "Machine(%s,%s)"%(i,k))
  
              model.addCons(s[i,k] + quicksum(p[i,j]*x[j,k] for j in range(1,n+1)) <= f[i,k],
                              "StartFinish(%s,%s)"%(i,k))
  
      model.setObjective(f[m,n], "minimize")
  
      model.data = x,s,f
      return model
docs: gpp -- model for the graph partitioning problem
      Parameters:
          - n: number of jobs
          - m: number of machines
          - p[i,j]: processing time of job i on machine j
      Returns a model, ready to be solved.