The Quadratic Assignment Problem (QAP) is an optimization problem that deals with assigning a set of facilities to a set of locations, considering the pairwise distances and flows between them.
The problem is to find the assignment that minimizes the total cost or distance, taking into account both the distances and the flows.
The distance matrix and flow matrix, as well as restrictions to ensure each facility is assigned to exactly one location and each location is assigned to exactly one facility, can be used to formulate the QAP as a quadratic objective function.
The QAP is a well-known example of an NP-hard problem, which means that for larger cases, computing the best solution might be difficult. As a result, many algorithms and heuristics have been created to quickly identify approximations of answers.
There are various types of algorithms for different problem structures, such as:
- Precise algorithms
- Approximation algorithms
- Metaheuristics like genetic algorithms and simulated annealing
- Specialized algorithms
Example: Given four facilities (F1, F2, F3, F4) and four locations (L1, L2, L3, L4). We have a cost matrix that represents the pairwise distances or costs between facilities. Additionally, we have a flow matrix that represents the interaction or flow between locations. Find the assignment that minimizes the total cost based on the interactions between facilities and locations. Each facility must be assigned to exactly one location, and each location can only accommodate one facility.
Facilities cost matrix:
0
|
2
|
3
|
1
|
2
|
0
|
1
|
4
|
3
|
1
|
0
|
2
|
1
|
4
|
2
|
0
|
Flow matrix:
0
|
1
|
2
|
3
|
1
|
0
|
4
|
2
|
2
|
4
|
0
|
1
|
3
|
2
|
1
|
0
|
To solve the QAP, various optimization techniques can be used, such as mathematical programming, heuristics, or metaheuristics. These techniques aim to explore the search space and find the optimal or near-optimal solution.
The solution to the QAP will provide an assignment of facilities to locations that minimizes the overall cost.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int calculateTotalCost( const vector<vector< int >>& facilities, const vector<vector< int >>& locations, const vector< int >& assignment) {
int totalCost = 0;
int n = facilities.size();
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < n; j++) {
int facility1 = assignment[i];
int facility2 = assignment[j];
int location1 = i;
int location2 = j;
totalCost += facilities[facility1][facility2] * locations[location1][location2];
}
}
return totalCost;
}
int main() {
vector<vector< int >> facilities = {
{0, 2, 3, 1},
{2, 0, 1, 4},
{3, 1, 0, 2},
{1, 4, 2, 0}
};
vector<vector< int >> locations = {
{0, 1, 2, 3},
{1, 0, 4, 2},
{2, 4, 0, 1},
{3, 2, 1, 0}
};
int n = facilities.size();
vector< int > assignment(n);
for ( int i = 0; i < n; i++) {
assignment[i] = i;
}
int minCost = calculateTotalCost(facilities, locations, assignment);
vector< int > minAssignment = assignment;
while (next_permutation(assignment.begin(), assignment.end())) {
int cost = calculateTotalCost(facilities, locations, assignment);
if (cost < minCost) {
minCost = cost;
minAssignment = assignment;
}
}
cout << "Optimal Assignment: " ;
for ( int i = 0; i < n; i++) {
cout << "F" << (minAssignment[i] + 1) << "->L" << (i + 1) << " " ;
}
cout << endl;
cout << "Total Cost: " << minCost << endl;
return 0;
}
|
Java
import java.util.*;
class GFG {
static void swap(List<Integer> assignment, int left, int right)
{
int temp = assignment.get(left);
assignment.set(left, assignment.get(right));
assignment.set(right, temp);
}
static void reverse(List<Integer> assignment, int left, int right)
{
while (left < right) {
swap(assignment, left, right);
left++;
right--;
}
}
static boolean next_permutation(List<Integer> assignment)
{
int size = assignment.size();
if (size <= 1 )
return false ;
int last = size - 2 ;
while (last >= 0 ) {
if (assignment.get(last) < assignment.get(last + 1 )) {
break ;
}
last--;
}
if (last < 0 )
return false ;
int nextGreater = size - 1 ;
for ( int i = size - 1 ; i > last; i--) {
if (assignment.get(i) > assignment.get(last)) {
nextGreater = i;
break ;
}
}
swap(assignment, nextGreater, last);
reverse(assignment, last + 1 , size - 1 );
return true ;
}
static int calculateTotalCost(List<List<Integer> > facilities,
List<List<Integer> > locations,
List<Integer> assignment)
{
int totalCost = 0 ;
int n = facilities.size();
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j < n; j++) {
int facility1 = assignment.get(i);
int facility2 = assignment.get(j);
int location1 = i;
int location2 = j;
totalCost += facilities.get(facility1).get(facility2)
*locations.get(location1).get(location2);
}
}
return totalCost;
}
public static void main(String[] args)
{
List<List<Integer> > facilities
= Arrays.asList(Arrays.asList( 0 , 2 , 3 , 1 ),
Arrays.asList( 2 , 0 , 1 , 4 ),
Arrays.asList( 3 , 1 , 0 , 2 ),
Arrays.asList( 1 , 4 , 2 , 0 ));
List<List<Integer> > locations
= Arrays.asList(Arrays.asList( 0 , 1 , 2 , 3 ),
Arrays.asList( 1 , 0 , 4 , 2 ),
Arrays.asList( 2 , 4 , 0 , 1 ),
Arrays.asList( 3 , 2 , 1 , 0 ));
int n = facilities.size();
List<Integer> assignment = new ArrayList<>();
for ( int i = 0 ; i < n; i++) {
assignment.add(i);
}
int minCost = calculateTotalCost(facilities, locations, assignment);
List<Integer> minAssignment = assignment;
while (next_permutation(assignment)) {
int cost = calculateTotalCost(facilities, locations, assignment);
if (cost < minCost) {
minCost = cost;
minAssignment = assignment;
}
}
System.out.print( "Optimal Assignment: " );
for ( int i = 0 ; i < n; i++) {
System.out.print( "F" + (minAssignment.get(i) + 1 ) + "->L" + (i + 1 ) + " " );
}
System.out.print( "\nTotal Cost: " + minCost);
}
}
|
Python3
def calculateTotalCost(facilities, locations, assignment):
totalCost = 0
n = len (facilities)
for i in range (n):
for j in range (n):
facility1 = assignment[i]
facility2 = assignment[j]
location1 = i
location2 = j
totalCost + = facilities[facility1][facility2] * locations[location1][location2]
return totalCost
if __name__ = = "__main__" :
facilities = [
[ 0 , 2 , 3 , 1 ],
[ 2 , 0 , 1 , 4 ],
[ 3 , 1 , 0 , 2 ],
[ 1 , 4 , 2 , 0 ]
]
locations = [
[ 0 , 1 , 2 , 3 ],
[ 1 , 0 , 4 , 2 ],
[ 2 , 4 , 0 , 1 ],
[ 3 , 2 , 1 , 0 ]
]
n = len (facilities)
assignment = list ( range (n))
minCost = calculateTotalCost(facilities, locations, assignment)
minAssignment = assignment.copy()
import itertools
for assignment in itertools.permutations(assignment):
cost = calculateTotalCost(facilities, locations, list (assignment))
if cost < minCost:
minCost = cost
minAssignment = list (assignment)
print ( "Optimal Assignment: " , end = "")
for i in range (n):
print (f "F{minAssignment[i] + 1}->L{i + 1} " , end = "")
print ()
print (f "Total Cost: {minCost}" )
|
C#
using System;
using System.Collections.Generic;
using System.Linq;
class FacilityLocation
{
static int CalculateTotalCost(List<List< int >> facilities, List<List< int >> locations, List< int > assignment)
{
int totalCost = 0;
int n = facilities.Count;
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < n; j++)
{
int facility1 = assignment[i];
int facility2 = assignment[j];
int location1 = i;
int location2 = j;
totalCost += facilities[facility1][facility2] * locations[location1][location2];
}
}
return totalCost;
}
static void Main()
{
List<List< int >> facilities = new List<List< int >>
{
new List< int > { 0, 2, 3, 1 },
new List< int > { 2, 0, 1, 4 },
new List< int > { 3, 1, 0, 2 },
new List< int > { 1, 4, 2, 0 }
};
List<List< int >> locations = new List<List< int >>
{
new List< int > { 0, 1, 2, 3 },
new List< int > { 1, 0, 4, 2 },
new List< int > { 2, 4, 0, 1 },
new List< int > { 3, 2, 1, 0 }
};
int n = facilities.Count;
List< int > assignment = Enumerable.Range(0, n).ToList();
int minCost = CalculateTotalCost(facilities, locations, assignment);
List< int > minAssignment = assignment;
while (NextPermutation(assignment))
{
int cost = CalculateTotalCost(facilities, locations, assignment);
if (cost < minCost)
{
minCost = cost;
minAssignment = assignment.ToList();
}
}
Console.Write( "Optimal Assignment: " );
for ( int i = 0; i < n; i++)
{
Console.Write($ "F{minAssignment[i] + 1}->L{i + 1} " );
}
Console.WriteLine();
Console.WriteLine($ "Total Cost: {minCost}" );
}
static bool NextPermutation(List< int > list)
{
int i = list.Count - 2;
while (i >= 0 && list[i] >= list[i + 1])
{
i--;
}
if (i < 0)
{
return false ;
}
int j = list.Count - 1;
while (list[j] <= list[i])
{
j--;
}
int temp = list[i];
list[i] = list[j];
list[j] = temp;
Reverse(list, i + 1, list.Count - 1);
return true ;
}
static void Reverse(List< int > list, int start, int end)
{
while (start < end)
{
int temp = list[start];
list[start] = list[end];
list[end] = temp;
start++;
end--;
}
}
}
|
Javascript
function calculateTotalCost(facilities, locations, assignment) {
let totalCost = 0;
const n = facilities.length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
const facility1 = assignment[i];
const facility2 = assignment[j];
const location1 = i;
const location2 = j;
totalCost += facilities[facility1][facility2] * locations[location1][location2];
}
}
return totalCost;
}
function generateInitialAssignment(n) {
const assignment = [];
for (let i = 0; i < n; i++) {
assignment[i] = i;
}
return assignment;
}
function findOptimalAssignment(facilities, locations) {
const n = facilities.length;
const initialAssignment = generateInitialAssignment(n);
let minCost = calculateTotalCost(facilities, locations, initialAssignment);
let minAssignment = [...initialAssignment];
const factorial = (n) => {
let result = 1;
for (let i = 1; i <= n; i++) {
result *= i;
}
return result;
};
const numberOfPermutations = factorial(n);
for (let i = 0; i < numberOfPermutations; i++) {
const assignment = generateInitialAssignment(n);
if (i > 0) {
let j = n - 1;
while (j > 0 && assignment[j - 1] >= assignment[j]) {
j--;
}
let k = n - 1;
while (assignment[j - 1] >= assignment[k]) {
k--;
}
[assignment[j - 1], assignment[k]] = [assignment[k], assignment[j - 1]];
k = n - 1;
while (j < k) {
[assignment[j], assignment[k]] = [assignment[k], assignment[j]];
j++;
k--;
}
}
const cost = calculateTotalCost(facilities, locations, assignment);
if (cost < minCost) {
minCost = cost;
minAssignment = [...assignment];
}
}
return { minAssignment, minCost };
}
const facilities = [
[0, 2, 3, 1],
[2, 0, 1, 4],
[3, 1, 0, 2],
[1, 4, 2, 0]
];
const locations = [
[0, 1, 2, 3],
[1, 0, 4, 2],
[2, 4, 0, 1],
[3, 2, 1, 0]
];
const n = facilities.length;
const { minAssignment, minCost } = findOptimalAssignment(facilities, locations);
console.log( "Optimal Assignment: " + minAssignment.map((facility, location) => `F${facility + 1}->L${location + 1}`).join( " " ));
console.log( "Total Cost: " + minCost);
|
Output
Optimal Assignment: F1->L1 F3->L2 F2->L3 F4->L4
Total Cost: 44
The solution generates all possible permutations of the assignment and calculates the total cost for each assignment. The optimal assignment is the one that results in the minimum total cost.
To calculate the total cost, we look at each pair of facilities in (i, j) and their respective locations (location1, location2). We then multiply the cost of assigning facility1 to facility2 (facilities[facility1][facility2]) with the flow from location1 to location2 (locations[location1][location2]). This process is done for all pairs of facilities in the assignment, and the costs are summed up.
Overall, the output tells us that assigning facilities to locations as F1->L1, F3->L2, F2->L3, and F4->L4 results in the minimum total cost of 44. This means that Facility 1 is assigned to Location 1, Facility 3 is assigned to Location 2, Facility 2 is assigned to Location 3, and Facility 4 is assigned to Location 4, yielding the lowest cost based on the given cost and flow matrices.This example demonstrates the process of finding the optimal assignment by considering the costs and flows associated with each facility and location. The objective is to find the assignment that minimizes the total cost, taking into account the interactions between facilities and locations.
Applications of the QAP include facility location, logistics, scheduling, and network architecture, all of which require effective resource allocation and arrangement.
|