import numpy as np
from moead_framework.problem.problem import Problem
[docs]class Mubqp(Problem):
"""
Implementation of the Multiobjective Unconstrained Binary Quadratic Programming problem.
The problem is compatible with files generated
by the mocobench generator http://mocobench.sourceforge.net/index.php?n=Problem.MUBQP
Example:
>>> from moead_framework.problem.combinatorial import Mubqp
>>>
>>> instance_file = "moead_framework/test/data/instances/mubqp_0_2_25_0.8_0.dat"
>>> mubqp = Mubqp(instance_file=instance_file)
>>>
>>> # Generate a new solution
>>> solution = mubqp.generate_random_solution()
>>>
>>> # Print all decision variables of the solution
>>> print(solution.decision_vector)
>>>
>>> # Print all objectives values of the solution
>>> print(solution.F)
"""
dtype = float
[docs] def __init__(self, instance_file=None, rho=None, m=None, n=None, qs=None):
f"""
Constructor of the problem.
You can initialize the problem directly by using an instance file or by setting parameters : rho, m, n and qs.
:param instance_file: {str} text file generated by the mubqp generator : http://mocobench.sourceforge.net/index.php?n=Problem.MUBQP#Code
:param rho: {float} the objective correlation coefficient
:param m: {int} the number of objective functions
:param n: {int} the length of solutions
:param qs: {list} the matrix coefficients of each matrix: one matrix for each objective.
"""
self.instance_file = None
self.rho = None
self.m = None
self.n = None
self.d = None
self.qs = None
if instance_file is not None:
if not isinstance(instance_file, str):
raise TypeError("The expected type of `instance_file` is `str`")
self.init_with_instance_file(instance_file=instance_file)
elif (rho is not None) & (m is not None) & (n is not None) & (qs is not None):
self.init_with_data(rho=rho, m=m, n=n, qs=qs)
else:
msg = "The constructor needs either the instance_file parameter or the following parameters : " \
"rho, m, n and qs."
raise ValueError(msg)
super().__init__(objective_number=self.m)
def init_with_instance_file(self, instance_file):
if isinstance(instance_file, str):
self.instance_file = instance_file
else:
raise TypeError("The instance_file parameter must be a string.")
file = open(instance_file, 'r')
file_content = list(map(str.strip, file.readlines()))
file.close()
file_content = file_content[6:]
definition = file_content[0].split(" ")
self.rho = float(definition[2])
self.m = int(definition[3])
self.n = int(definition[4])
self.d = float(definition[5])
file_content = file_content[2:]
self.qs = np.zeros((self.m, self.n, self.n))
self.load_qs(file_content)
def init_with_data(self, rho, m, n, qs):
if isinstance(qs, list):
self.qs = qs
else:
raise TypeError("The parameter qs must be a list.")
if isinstance(m, int) & isinstance(n, int):
self.m = m
self.n = n
else:
raise TypeError("The parameters m and n must be positive integers.")
if isinstance(rho, float):
self.rho = rho
else:
raise TypeError("The parameter m rho must be a float.")
[docs] def f(self, function_id: int, decision_vector:np.ndarray):
"""
Evaluate the decision_vector for the objective function_id
:param function_id: {integer} index of the objective
:param decision_vector: {:class:`~moead_framework.solution.one_dimension_solution.OneDimensionSolution`} solution to evaluate
:return: {float} fitness value
"""
if not isinstance(function_id, int):
raise TypeError("The expected type of `function_id` is `int`")
if not isinstance(decision_vector, np.ndarray):
raise TypeError("The expected type of `decision_vector` is `np.ndarray`")
fit = 0
for i in range(self.n):
if decision_vector[i] == 1:
for j in range(i+1):
if decision_vector[j] == 1:
fit += self.qs[function_id][i][j]
return - fit
[docs] def generate_random_solution(self):
"""
Generate a random solution for the current problem
:return: {:class:`~moead_framework.solution.one_dimension_solution.OneDimensionSolution`}
"""
return self.evaluate(x=np.random.randint(0, 2, self.n).tolist()[:])
[docs] def load_qs(self, file_content):
"""
Load values of the instance file
:param file_content: {list<float>} content of the instance file
:return:
"""
line = 0
for i in range(self.n):
for j in range(self.n):
s = file_content[line].split(" ")
line += 1
for n in range(self.m):
self.qs[n][i][j] = int(s[n])
pass