from itertools import product
import numpy as np
from desdeo_emo.utilities.ReferenceVectors import ReferenceVectors
[docs]class newRV(ReferenceVectors):
"""pass"""
[docs] def rotate_to_axis(self, ref_point):
self.values = rotate(ref_point, [0, 0, 1], self.values)
[docs] def revert_rotation(self, ref_point):
self.values = rotate([0, 0, 1], ref_point, self.values)
[docs] def project_to_hyperplane(self):
"""Projects the reference vectors to the hyperplane xn = 1."""
self.values[:, -1] = 1
[docs] def translate_to_hypersphere(self):
"""Reverse of preject_to_hyperplane()."""
self.values[:, -1] = np.sqrt(
1 - np.sum(np.square(self.values[:, 0:-1]), axis=1)
)
[docs] def interact_v2(self, ref_point):
"""New kind of interaction."""
self.rotate_to_axis(ref_point)
self.project_to_hyperplane()
newvals = dist_based_translation(self.values[:, 0:-1])
self.values[:, 0:-1] = newvals
self.translate_to_hypersphere()
self.revert_rotation(ref_point)
[docs] def interact_v3(self, ref_point):
"""New kind of interaction. More coverage."""
self.values = np.zeros(self.values.shape)
newvals = []
combinations = np.asarray(list(product([-1, 1], repeat=self.values.shape[1])))
combinations[:, -1] = np.unique(abs(combinations[:, -1]), axis=0)
for combination in combinations:
changedvals = np.copy(self.initial_values) * combination
if newvals == []:
newvals = changedvals
else:
newvals = np.vstack((newvals, changedvals))
newvals = dist_based_translation(newvals[:, 0:-1])
changedvals = np.ones((newvals.shape[0], newvals.shape[1] + 1))
changedvals[:, 0:-1] = newvals
self.values = changedvals
self.translate_to_hypersphere()
self.revert_rotation(ref_point)
num_rows = self.values.shape[0]
delete_rows = []
for index in range(num_rows):
if np.any(self.values[index, :] < 0):
if delete_rows == []:
delete_rows = np.asarray(index)
else:
delete_rows = np.hstack((delete_rows, index))
self.values = np.delete(self.values, delete_rows, axis=0)
[docs]def rotate(initial_vector, rotated_vector, other_vectors):
"""Calculate the rotation matrix that rotates the initial_vector to the
rotated_vector. Apply that rotation on other_vectors and return.
Uses Householder reflections twice to achieve this."""
init_vec_norm = normalize(initial_vector)
rot_vec_norm = normalize(rotated_vector)
middle_vec_norm = normalize(init_vec_norm + rot_vec_norm)
first_reflector = init_vec_norm - middle_vec_norm
second_reflector = middle_vec_norm - rot_vec_norm
Q1 = householder(first_reflector)
Q2 = householder(second_reflector)
reflection_matrix = np.matmul(Q2, Q1)
rotated_vectors = np.matmul(other_vectors, np.transpose(reflection_matrix))
return rotated_vectors
[docs]def normalize(vector):
"""Normalize and return a vector."""
return vector / np.linalg.norm(vector)
[docs]def householder(vector):
"""Return reflection matrix via householder transformation."""
identity_mat = np.eye(len(vector))
v = vector[np.newaxis]
denominator = np.matmul(v, v.T)
numerator = np.matmul(v.T, v)
rot_mat = identity_mat - (2 * numerator / denominator)
return rot_mat
[docs]def dist_based_translation(vectors):
"""Translates points towards origin based on distance."""
dist = np.sqrt(np.sum(np.square(vectors), axis=1))
max_dist = np.amax(dist)
# max_dist = 1
alpha = 5
ratio = alpha * (1 / (dist * dist) - 1 / (max_dist * max_dist))
t_factor = 1 / (1 + ratio)
return vectors * t_factor[np.newaxis].T
[docs]def main():
rv = newRV(20, 3)
rv.interact_v3([1, 1, 1])
if __name__ == '__main':
main()