Source code for magnopy._parameters._equivalent_sets

# ================================== LICENSE ===================================
# Magnopy - Python package for magnons.
#
# Copyright (C) 2023 Magnopy Team
#
# e-mail: anry@uv.es, web: magnopy.org
#
# This program is free software: you  can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the  Free Software
# Foundation,  either  version 3  of the License,  or (at your option) any later
# version.
#
# This program is distributed in the  hope  that it will be useful,  but WITHOUT
# ANY WARRANTY;  without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the  GNU General Public License  along with
# this program.  If not, see <https://www.gnu.org/licenses/>.
# ================================ END LICENSE =================================

import numpy as np

from magnopy._parameters._interaction_parameters import _get_specs
from magnopy._parameters._interaction_parameters import _InteractionParameters

# Save local scope at this moment
old_dir = set(dir())
old_dir.add("old_dir")


def _minus(nu):
    return tuple([-_ for _ in nu])


def _diff(nu1, nu2):
    return tuple([nu1[_] - nu2[_] for _ in range(3)])


def _get_equivalent_2_2(nus, alphas, parameter=None):
    """
    See S.21 of SI of paper-2026
    """
    nu_2 = nus[0]
    alpha_1 = alphas[0]
    alpha_2 = alphas[1]

    if ((0, 0, 0), alpha_1) == (nu_2, alpha_2):
        raise ValueError("Invalid indices for (1+1) case.")

    versions_nus = [
        (nu_2,),
        (_minus(nu_2),),
    ]

    versions_alphas = [
        (alpha_1, alpha_2),
        (alpha_2, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 2
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy()),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent_3_2(nus, alphas, parameter=None):
    """
    See S.22 of SI of paper-2026
    """
    r1 = ((0, 0, 0), alphas[0])
    r2 = (nus[0], alphas[1])
    r3 = (nus[1], alphas[2])
    if r1 == r2 and r1 != r3:
        nu_2 = nus[1]
        alpha_1 = alphas[0]
        alpha_2 = alphas[2]
    elif r1 == r3 and r1 != r2:
        nu_2 = nus[0]
        alpha_1 = alphas[0]
        alpha_2 = alphas[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 2, 1))
    elif r2 == r3 and r2 != r1:
        nu_2 = _minus(nus[0])
        alpha_1 = alphas[1]
        alpha_2 = alphas[0]
        if parameter is not None:
            parameter = np.transpose(parameter, (1, 2, 0))
    else:
        raise ValueError("Invalid indices for (2+1) case.")

    versions_nus = [
        ((0, 0, 0), nu_2),
        (nu_2, (0, 0, 0)),
        (_minus(nu_2), _minus(nu_2)),
    ]

    versions_alphas = [
        (alpha_1, alpha_1, alpha_2),
        (alpha_1, alpha_2, alpha_1),
        (alpha_2, alpha_1, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 3
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy(), (0, 2, 1)),
            np.transpose(parameter.copy(), (2, 0, 1)),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent_3_3(nus, alphas, parameter=None):
    """
    See S.23 of SI of paper-2026
    """

    nu_2 = nus[0]
    nu_3 = nus[1]
    alpha_1 = alphas[0]
    alpha_2 = alphas[1]
    alpha_3 = alphas[2]

    r1 = ((0, 0, 0), alpha_1)
    r2 = (nu_2, alpha_2)
    r3 = (nu_3, alpha_3)
    if r1 == r2 or r1 == r3 or r2 == r3:
        raise ValueError("Invalid indices for (1+1+1) case.")

    versions_nus = [
        (nu_2, nu_3),
        (nu_3, nu_2),
        (_minus(nu_2), _diff(nu_3, nu_2)),
        (_diff(nu_3, nu_2), _minus(nu_2)),
        (_minus(nu_3), _diff(nu_2, nu_3)),
        (_diff(nu_2, nu_3), _minus(nu_3)),
    ]

    versions_alphas = [
        (alpha_1, alpha_2, alpha_3),
        (alpha_1, alpha_3, alpha_2),
        (alpha_2, alpha_1, alpha_3),
        (alpha_2, alpha_3, alpha_1),
        (alpha_3, alpha_1, alpha_2),
        (alpha_3, alpha_2, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 6
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy(), (0, 2, 1)),
            np.transpose(parameter.copy(), (1, 0, 2)),
            np.transpose(parameter.copy(), (1, 2, 0)),
            np.transpose(parameter.copy(), (2, 0, 1)),
            np.transpose(parameter.copy(), (2, 1, 0)),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent_4_2(nus, alphas, parameter=None):
    """
    See S.24 of SI of paper-2026
    """
    r1 = ((0, 0, 0), alphas[0])
    r2 = (nus[0], alphas[1])
    r3 = (nus[1], alphas[2])
    r4 = (nus[2], alphas[3])
    if r1 == r2 and r1 == r3 and r1 != r4:
        nu_2 = r4[0]
        alpha_1 = r1[1]
        alpha_2 = r4[1]
    elif r1 == r2 and r1 == r4 and r1 != r3:
        nu_2 = r3[0]
        alpha_1 = r1[1]
        alpha_2 = r3[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 1, 3, 2))
    elif r1 == r3 and r1 == r4 and r1 != r2:
        nu_2 = r2[0]
        alpha_1 = r1[1]
        alpha_2 = r2[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 2, 3, 1))
    elif r2 == r3 and r2 == r4 and r1 != r2:
        nu_2 = _minus(r2[0])
        alpha_1 = r2[1]
        alpha_2 = r1[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (1, 2, 3, 0))
    else:
        raise ValueError("Invalid indices for (3+1+0+0) case.")

    versions_nus = [
        ((0, 0, 0), (0, 0, 0), nu_2),
        ((0, 0, 0), nu_2, (0, 0, 0)),
        (nu_2, (0, 0, 0), (0, 0, 0)),
        (_minus(nu_2), _minus(nu_2), _minus(nu_2)),
    ]

    versions_alphas = [
        (alpha_1, alpha_1, alpha_1, alpha_2),
        (alpha_1, alpha_1, alpha_2, alpha_1),
        (alpha_1, alpha_2, alpha_1, alpha_1),
        (alpha_2, alpha_1, alpha_1, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 4
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy(), (0, 1, 3, 2)),
            np.transpose(parameter.copy(), (0, 3, 1, 2)),
            np.transpose(parameter.copy(), (3, 0, 1, 2)),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent_4_3(nus, alphas, parameter=None):
    """
    See S.25 of SI of paper-2026
    """
    r1 = ((0, 0, 0), alphas[0])
    r2 = (nus[0], alphas[1])
    r3 = (nus[1], alphas[2])
    r4 = (nus[2], alphas[3])
    if r1 == r2 and r3 == r4 and r2 != r3:
        nu_2 = r3[0]
        alpha_1 = r1[1]
        alpha_2 = r3[1]
    elif r1 == r3 and r2 == r4 and r1 != r2:
        nu_2 = r2[0]
        alpha_1 = r1[1]
        alpha_2 = r2[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 2, 1, 3))
    elif r1 == r4 and r2 == r3 and r1 != r2:
        nu_2 = r2[0]
        alpha_1 = r1[1]
        alpha_2 = r2[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 3, 1, 2))
    else:
        raise ValueError("Invalid indices for (2+2+0+0) case.")

    versions_nus = [
        ((0, 0, 0), nu_2, nu_2),
        (nu_2, (0, 0, 0), nu_2),
        (nu_2, nu_2, (0, 0, 0)),
        (_minus(nu_2), _minus(nu_2), (0, 0, 0)),
        (_minus(nu_2), (0, 0, 0), _minus(nu_2)),
        ((0, 0, 0), _minus(nu_2), _minus(nu_2)),
    ]

    versions_alphas = [
        (alpha_1, alpha_1, alpha_2, alpha_2),
        (alpha_1, alpha_2, alpha_1, alpha_2),
        (alpha_1, alpha_2, alpha_2, alpha_1),
        (alpha_2, alpha_1, alpha_1, alpha_2),
        (alpha_2, alpha_1, alpha_2, alpha_1),
        (alpha_2, alpha_2, alpha_1, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 6
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy(), (0, 2, 1, 3)),
            np.transpose(parameter.copy(), (0, 2, 3, 1)),
            np.transpose(parameter.copy(), (2, 0, 1, 3)),
            np.transpose(parameter.copy(), (2, 0, 3, 1)),
            np.transpose(parameter.copy(), (2, 3, 0, 1)),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent_4_4(nus, alphas, parameter=None):
    """
    See S.26 of SI of paper-2026
    """
    r1 = ((0, 0, 0), alphas[0])
    r2 = (nus[0], alphas[1])
    r3 = (nus[1], alphas[2])
    r4 = (nus[2], alphas[3])
    if r1 == r2 and r1 != r3 and r1 != r4 and r3 != r4:
        nu_2 = r3[0]
        nu_3 = r4[0]
        alpha_1 = r1[1]
        alpha_2 = r3[1]
        alpha_3 = r4[1]
    elif r1 == r3 and r1 != r2 and r1 != r4 and r2 != r4:
        nu_2 = r2[0]
        nu_3 = r4[0]
        alpha_1 = r1[1]
        alpha_2 = r2[1]
        alpha_3 = r4[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 2, 1, 3))
    elif r1 == r4 and r1 != r2 and r1 != r3 and r2 != r3:
        nu_2 = r2[0]
        nu_3 = r3[0]
        alpha_1 = r1[1]
        alpha_2 = r2[1]
        alpha_3 = r3[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (0, 3, 1, 2))
    elif r2 == r3 and r2 != r1 and r2 != r4 and r1 != r4:
        nu_2 = _minus(r2[0])
        nu_3 = _diff(r4[0], r2[0])
        alpha_1 = r2[1]
        alpha_2 = r1[1]
        alpha_3 = r4[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (1, 2, 0, 3))
    elif r2 == r4 and r2 != r1 and r2 != r3 and r1 != r3:
        nu_2 = _minus(r2[0])
        nu_3 = _diff(r3[0], r2[0])
        alpha_1 = r2[1]
        alpha_2 = r1[1]
        alpha_3 = r3[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (1, 3, 0, 2))
    elif r3 == r4 and r3 != r1 and r3 != r2 and r1 != r2:
        nu_2 = _minus(r3[0])
        nu_3 = _diff(r2[0], r3[0])
        alpha_1 = r3[1]
        alpha_2 = r1[1]
        alpha_3 = r2[1]
        if parameter is not None:
            parameter = np.transpose(parameter, (2, 3, 0, 1))
    else:
        raise ValueError("Invalid indices for (2+1+1+0) case.")

    versions_nus = [
        ((0, 0, 0), nu_2, nu_3),
        ((0, 0, 0), nu_3, nu_2),
        (nu_2, (0, 0, 0), nu_3),
        (nu_3, (0, 0, 0), nu_2),
        (nu_2, nu_3, (0, 0, 0)),
        (nu_3, nu_2, (0, 0, 0)),
        (_minus(nu_2), _minus(nu_2), _diff(nu_3, nu_2)),
        (_minus(nu_3), _minus(nu_3), _diff(nu_2, nu_3)),
        (_minus(nu_2), _diff(nu_3, nu_2), _minus(nu_2)),
        (_minus(nu_3), _diff(nu_2, nu_3), _minus(nu_3)),
        (_diff(nu_3, nu_2), _minus(nu_2), _minus(nu_2)),
        (_diff(nu_2, nu_3), _minus(nu_3), _minus(nu_3)),
    ]

    versions_alphas = [
        (alpha_1, alpha_1, alpha_2, alpha_3),
        (alpha_1, alpha_1, alpha_3, alpha_2),
        (alpha_1, alpha_2, alpha_1, alpha_3),
        (alpha_1, alpha_3, alpha_1, alpha_2),
        (alpha_1, alpha_2, alpha_3, alpha_1),
        (alpha_1, alpha_3, alpha_2, alpha_1),
        (alpha_2, alpha_1, alpha_1, alpha_3),
        (alpha_3, alpha_1, alpha_1, alpha_2),
        (alpha_2, alpha_1, alpha_3, alpha_1),
        (alpha_3, alpha_1, alpha_2, alpha_1),
        (alpha_2, alpha_3, alpha_1, alpha_1),
        (alpha_3, alpha_2, alpha_1, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 12
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy(), (0, 1, 3, 2)),
            np.transpose(parameter.copy(), (0, 2, 1, 3)),
            np.transpose(parameter.copy(), (0, 3, 1, 2)),
            np.transpose(parameter.copy(), (0, 2, 3, 1)),
            np.transpose(parameter.copy(), (0, 3, 2, 1)),
            np.transpose(parameter.copy(), (2, 0, 1, 3)),
            np.transpose(parameter.copy(), (3, 0, 1, 2)),
            np.transpose(parameter.copy(), (2, 0, 3, 1)),
            np.transpose(parameter.copy(), (3, 0, 2, 1)),
            np.transpose(parameter.copy(), (2, 3, 0, 1)),
            np.transpose(parameter.copy(), (3, 2, 0, 1)),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent_4_5(nus, alphas, parameter=None):
    """
    See S.27 of SI of paper-2026
    """
    nu_2 = nus[0]
    nu_3 = nus[1]
    nu_4 = nus[2]
    alpha_1 = alphas[0]
    alpha_2 = alphas[1]
    alpha_3 = alphas[2]
    alpha_4 = alphas[3]

    r1 = ((0, 0, 0), alpha_1)
    r2 = (nu_2, alpha_2)
    r3 = (nu_3, alpha_3)
    r4 = (nu_4, alpha_4)
    if r1 == r2 or r1 == r3 or r1 == r4 or r2 == r3 or r2 == r4 or r3 == r4:
        raise ValueError("Invalid indices for (1+1+1+1) case.")

    versions_nus = [
        (nu_2, nu_3, nu_4),
        (nu_2, nu_4, nu_3),
        (nu_3, nu_2, nu_4),
        (nu_3, nu_4, nu_2),
        (nu_4, nu_2, nu_3),
        (nu_4, nu_3, nu_2),
        (_minus(nu_2), _diff(nu_3, nu_2), _diff(nu_4, nu_2)),
        (_minus(nu_2), _diff(nu_4, nu_2), _diff(nu_3, nu_2)),
        (_diff(nu_3, nu_2), _minus(nu_2), _diff(nu_4, nu_2)),
        (_diff(nu_3, nu_2), _diff(nu_4, nu_2), _minus(nu_2)),
        (_diff(nu_4, nu_2), _minus(nu_2), _diff(nu_3, nu_2)),
        (_diff(nu_4, nu_2), _diff(nu_3, nu_2), _minus(nu_2)),
        (_minus(nu_3), _diff(nu_2, nu_3), _diff(nu_4, nu_3)),
        (_minus(nu_3), _diff(nu_4, nu_3), _diff(nu_2, nu_3)),
        (_diff(nu_2, nu_3), _minus(nu_3), _diff(nu_4, nu_3)),
        (_diff(nu_2, nu_3), _diff(nu_4, nu_3), _minus(nu_3)),
        (_diff(nu_4, nu_3), _minus(nu_3), _diff(nu_2, nu_3)),
        (_diff(nu_4, nu_3), _diff(nu_2, nu_3), _minus(nu_3)),
        (_minus(nu_4), _diff(nu_2, nu_4), _diff(nu_3, nu_4)),
        (_minus(nu_4), _diff(nu_3, nu_4), _diff(nu_2, nu_4)),
        (_diff(nu_2, nu_4), _minus(nu_4), _diff(nu_3, nu_4)),
        (_diff(nu_2, nu_4), _diff(nu_3, nu_4), _minus(nu_4)),
        (_diff(nu_3, nu_4), _minus(nu_4), _diff(nu_2, nu_4)),
        (_diff(nu_3, nu_4), _diff(nu_2, nu_4), _minus(nu_4)),
    ]

    versions_alphas = [
        (alpha_1, alpha_2, alpha_3, alpha_4),
        (alpha_1, alpha_2, alpha_4, alpha_3),
        (alpha_1, alpha_3, alpha_2, alpha_4),
        (alpha_1, alpha_3, alpha_4, alpha_2),
        (alpha_1, alpha_4, alpha_2, alpha_3),
        (alpha_1, alpha_4, alpha_3, alpha_2),
        (alpha_2, alpha_1, alpha_3, alpha_4),
        (alpha_2, alpha_1, alpha_4, alpha_3),
        (alpha_2, alpha_3, alpha_1, alpha_4),
        (alpha_2, alpha_3, alpha_4, alpha_1),
        (alpha_2, alpha_4, alpha_1, alpha_3),
        (alpha_2, alpha_4, alpha_3, alpha_1),
        (alpha_3, alpha_1, alpha_2, alpha_4),
        (alpha_3, alpha_1, alpha_4, alpha_2),
        (alpha_3, alpha_2, alpha_1, alpha_4),
        (alpha_3, alpha_2, alpha_4, alpha_1),
        (alpha_3, alpha_4, alpha_1, alpha_2),
        (alpha_3, alpha_4, alpha_2, alpha_1),
        (alpha_4, alpha_1, alpha_2, alpha_3),
        (alpha_4, alpha_1, alpha_3, alpha_2),
        (alpha_4, alpha_2, alpha_1, alpha_3),
        (alpha_4, alpha_2, alpha_3, alpha_1),
        (alpha_4, alpha_3, alpha_1, alpha_2),
        (alpha_4, alpha_3, alpha_2, alpha_1),
    ]

    if parameter is None:
        versions_parameter = [None] * 24
    else:
        versions_parameter = [
            parameter.copy(),
            np.transpose(parameter.copy(), (0, 1, 3, 2)),
            np.transpose(parameter.copy(), (0, 2, 1, 3)),
            np.transpose(parameter.copy(), (0, 2, 3, 1)),
            np.transpose(parameter.copy(), (0, 3, 1, 2)),
            np.transpose(parameter.copy(), (0, 3, 2, 1)),
            np.transpose(parameter.copy(), (1, 0, 2, 3)),
            np.transpose(parameter.copy(), (1, 0, 3, 2)),
            np.transpose(parameter.copy(), (1, 2, 0, 3)),
            np.transpose(parameter.copy(), (1, 2, 3, 0)),
            np.transpose(parameter.copy(), (1, 3, 0, 2)),
            np.transpose(parameter.copy(), (1, 3, 2, 0)),
            np.transpose(parameter.copy(), (2, 0, 1, 3)),
            np.transpose(parameter.copy(), (2, 0, 3, 1)),
            np.transpose(parameter.copy(), (2, 1, 0, 3)),
            np.transpose(parameter.copy(), (2, 1, 3, 0)),
            np.transpose(parameter.copy(), (2, 3, 0, 1)),
            np.transpose(parameter.copy(), (2, 3, 1, 0)),
            np.transpose(parameter.copy(), (3, 0, 1, 2)),
            np.transpose(parameter.copy(), (3, 0, 2, 1)),
            np.transpose(parameter.copy(), (3, 1, 0, 2)),
            np.transpose(parameter.copy(), (3, 1, 2, 0)),
            np.transpose(parameter.copy(), (3, 2, 0, 1)),
            np.transpose(parameter.copy(), (3, 2, 1, 0)),
        ]

    parameters = list(zip(versions_nus, versions_alphas, versions_parameter))
    parameters.sort(key=lambda x: x[:-1], reverse=True)

    return parameters


def _get_equivalent(n, p_n, nus, alphas, parameter=None):

    if n == 2 and p_n == 2:
        return _get_equivalent_2_2(nus, alphas, parameter)
    elif n == 3 and p_n == 2:
        return _get_equivalent_3_2(nus, alphas, parameter)
    elif n == 3 and p_n == 3:
        return _get_equivalent_3_3(nus, alphas, parameter)
    elif n == 4 and p_n == 2:
        return _get_equivalent_4_2(nus, alphas, parameter)
    elif n == 4 and p_n == 3:
        return _get_equivalent_4_3(nus, alphas, parameter)
    elif n == 4 and p_n == 4:
        return _get_equivalent_4_4(nus, alphas, parameter)
    elif n == 4 and p_n == 5:
        return _get_equivalent_4_5(nus, alphas, parameter)
    elif p_n == 1 and 1 <= n <= 4:
        return [(nus, alphas, parameter)]
    else:
        raise ValueError("Invalid n and p_n values.")


[docs] def get_equivalent_parameters(nus, alphas, parameter=None): """ Computes equivalent parameters as described in supplementary information of |paper-2026|_ (eqs. S.21-S.27). The returned list of parameters is sorted in descending order by the indices (nus and alphas). Parameters ---------- nus : list of tuples List of ``n-1`` unit cell indices associated with the parameter. Each unit cell index is a tuple of three integers. alphas : list of tuples List of ``n`` atom indices associated with the parameter. Each atom index is an integer. parameter : (3, ..., 3) |array-like|_, optional Value of the parameter. The shape of the array should be (3, ..., 3) with ``n`` dimensions. If not provided, then the returned parameters will have ``None`` as the value. Returns ------- parameters : list of tuples List of equivalent parameters. Each parameter is a tuple of the form ``(nus, alphas, parameter)`` where ``nus`` and ``alphas`` are the unit cell and atom indices of the parameter, respectively, and ``parameter`` is the value of the parameter (or ``None`` if not provided). Notes ----- See :ref:`user-guide_theory-behind_equivalent-parameters` for more details. Examples -------- .. doctest:: >>> import magnopy >>> eq_params = magnopy.get_equivalent_parameters( ... nus=[(1, 0, 0)], ... alphas=[(0,), (1,)], ... parameter=[[0, -1, 0], [0.5, 0.3, 0], [0, 0, 0]], ... ) >>> for nus, alphas, parameter in eq_params: ... print(nus, alphas) ... print(parameter) ((1, 0, 0),) ((0,), (1,)) [[ 0. -1. 0. ] [ 0.5 0.3 0. ] [ 0. 0. 0. ]] ((-1, 0, 0),) ((1,), (0,)) [[ 0. 0.5 0. ] [-1. 0.3 0. ] [ 0. 0. 0. ]] .. doctest:: >>> import magnopy >>> eq_params = magnopy.get_equivalent_parameters( ... nus=[(1, 0, 0), (0, 1, 0)], alphas=[(0,), (1,), (2,)], parameter=None ... ) >>> for nus, alphas, parameter in eq_params: ... print(nus, alphas) ((1, 0, 0), (0, 1, 0)) ((0,), (1,), (2,)) ((1, -1, 0), (0, -1, 0)) ((2,), (1,), (0,)) ((0, 1, 0), (1, 0, 0)) ((0,), (2,), (1,)) ((0, -1, 0), (1, -1, 0)) ((2,), (0,), (1,)) ((-1, 1, 0), (-1, 0, 0)) ((1,), (2,), (0,)) ((-1, 0, 0), (-1, 1, 0)) ((1,), (0,), (2,)) """ nus_for_specs = [(0, 0, 0)] + list(nus) n, p_n = _get_specs(nus=nus_for_specs, alphas=alphas)[:2] if parameter is not None: parameter = np.array(parameter) return _get_equivalent(n=n, p_n=p_n, nus=nus, alphas=alphas, parameter=parameter)
def _get_missing_parameters(parameters, strategy="mean"): r""" Computes missing parameters of the equivalent sets. Parameters ---------- parameters : _InteractionParameters strategy : str, default="mean" Returns ------- missing_parameters : _InteractionParameters """ strategy = strategy.lower() counter = {} missing_parameters = _InteractionParameters() for (n, p_n, nus, alphas), parameter in parameters._container: equivalent_set = _get_equivalent( n=n, p_n=p_n, nus=nus, alphas=alphas, parameter=parameter ) for eq_nus, eq_alphas, eq_parameter in equivalent_set: eq_specs = (n, p_n, eq_nus, eq_alphas) if eq_specs not in parameters: if strategy == "zeros": missing_parameters.add( specs=eq_specs, parameter=np.zeros_like(parameter, dtype=float), when_present="skip", ) elif strategy == "mean": if (eq_nus, eq_alphas) not in counter: counter[(eq_nus, eq_alphas)] = 0 missing_parameters.add( specs=eq_specs, parameter=parameter, when_present="weighted average", weights=(counter[(eq_nus, eq_alphas)], 1), ) counter[(eq_nus, eq_alphas)] += 1 else: raise ValueError( f'Expected strategy to be either "zeros" or "mean", got {strategy}.' ) return missing_parameters def _set_distribution(parameters, strategy="symmetrize"): r""" Changes distribution within equivalent sets. Parameters ---------- parameters : _InteractionParameters Returns ------- new_parameters : _InteractionParameters """ strategy = strategy.lower() new_parameters = _InteractionParameters() if strategy == "symmetrize": for (n, p_n, nus, alphas), parameter in parameters._container: equivalent_parameters = _get_equivalent( n=n, p_n=p_n, nus=nus, alphas=alphas, parameter=parameter ) degeneracy = len(equivalent_parameters) for eq_nus, eq_alphas, eq_parameter in equivalent_parameters: new_parameters.add( specs=(n, p_n, eq_nus, eq_alphas), parameter=eq_parameter / degeneracy, when_present="sum", ) elif strategy == "representative": for (n, p_n, nus, alphas), parameter in parameters._container: equivalent_parameters = _get_equivalent( n=n, p_n=p_n, nus=nus, alphas=alphas, parameter=parameter ) for index, (eq_nus, eq_alphas, eq_parameter) in enumerate( equivalent_parameters ): if index == 0: new_parameters.add( specs=(n, p_n, eq_nus, eq_alphas), parameter=eq_parameter, when_present="sum", ) else: new_parameters.add( specs=(n, p_n, eq_nus, eq_alphas), parameter=np.zeros_like(eq_parameter, dtype=float), when_present="skip", ) else: raise ValueError( f'Expected strategy to be either "symmetrize" or "representative" got {strategy}.' ) return new_parameters # Populate __all__ with objects defined in this file __all__ = list(set(dir()) - old_dir) # Remove all semi-private objects __all__ = [i for i in __all__ if not i.startswith("_")] del old_dir