diff --git a/dwave/plugins/sklearn/transformers.py b/dwave/plugins/sklearn/transformers.py index aa186be..74aa070 100644 --- a/dwave/plugins/sklearn/transformers.py +++ b/dwave/plugins/sklearn/transformers.py @@ -198,22 +198,18 @@ def correlation_cqm( dtype=np.result_type(X, y), mode="w+", shape=(X_copy.shape[1], X_copy.shape[1]), - ) - + ) # main calculation. It modifies X_copy in-place corrcoef(X_copy, out=correlations, rowvar=False, copy=False) - # we don't care about the direction of correlation in terms of # the penalty/quality np.absolute(correlations, out=correlations) - + # multiplying all but last columns and rows with (1 - alpha) + np.multiply(correlations[:-1, :-1], (1 - alpha), out=correlations[:-1, :-1]) # our objective - # we multiply by 2 because the matrix is symmetric - np.fill_diagonal(correlations, correlations[:, -1] * (-2 * alpha * num_features)) - - # Note: the full symmetric matrix (with both upper- and lower-diagonal - # entries for each correlation coefficient) is retained for consistency with - # the original formulation from Milne et al. + # we multiply by num_features to have consistent performance + # with the increase of the number of features + np.fill_diagonal(correlations, correlations[:, -1] * (- alpha * num_features)) it = np.nditer(correlations[:-1, :-1], flags=['multi_index'], op_flags=[['readonly']]) cqm.set_objective((*it.multi_index, x) for x in it if x) diff --git a/releasenotes/notes/algorithm-update-d73cd4f7c854a8b3.yaml b/releasenotes/notes/algorithm-update-d73cd4f7c854a8b3.yaml new file mode 100644 index 0000000..dc85f5f --- /dev/null +++ b/releasenotes/notes/algorithm-update-d73cd4f7c854a8b3.yaml @@ -0,0 +1,3 @@ +--- +fixes: + - Multiply off-diagonal terms of the correlation matrix with 1-alpha. \ No newline at end of file diff --git a/tests/test_transformer.py b/tests/test_transformer.py index 14214cc..6e0ef3e 100644 --- a/tests/test_transformer.py +++ b/tests/test_transformer.py @@ -126,6 +126,10 @@ def test_alpha_0(self): cqm = SelectFromQuadraticModel.correlation_cqm(self.X, self.y, num_features=3, alpha=0) self.assertTrue(not any(cqm.objective.linear.values())) + def test_alpha_1_no_quadratic(self): + cqm = SelectFromQuadraticModel.correlation_cqm(self.X, self.y, num_features=3, alpha=1) + self.assertTrue(not any(cqm.objective.quadratic.values())) + def test_alpha_1(self): rng = np.random.default_rng(42)