反向函数以获取原始输入值

0 投票
1 回答
185 浏览
提问于 2025-04-14 17:03

我有一个叫做 get_angles 的函数,它可以从 input_features 生成一些角度。这些函数返回的特征被用来训练一个变分量子电路。

def get_angles(x):
    beta0 = 2 * np.arcsin(np.sqrt(x[1] ** 2) / np.sqrt(x[0] ** 2 + x[1] ** 2 + 1e-12))
    beta1 = 2 * np.arcsin(np.sqrt(x[2] ** 2) / np.sqrt(x[2] ** 2 + x[2] ** 2 + 1e-12))
    beta2 = 2 * np.arcsin(np.linalg.norm(x[2:]) / np.linalg.norm(x))
    
    return np.array([beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2])

也就是说:

input_features = [10, 20, 30, 40, 50]`

# Transform the features
features = np.array(get_angles(input_features))

现在,我想把这个过程反过来,拿到最后的 features 值,然后把它们转换回最开始在 get_angles 函数中使用的 input_features 值。有没有办法可以反向操作上面定义的 get_angles 函数呢?

提前谢谢你。

我希望通过运行最终的 features 来得到 input_features,所以我尝试了多个不同版本的 get_reverse_angles 函数,比如下面这个,但都没有成功。

def get_reverse_angles(angles):
    # Extract the angles
    beta2, neg_beta1, pos_beta1, neg_beta0, pos_beta0 = angles
    
    # Solve for x using trigonometric equations
    x0 = np.sqrt(2)
    x1 = np.sin(beta2 / 2) * np.sqrt(2)
    x2 = np.sin(pos_beta1 / 2) * np.sqrt(2)
    x3 = np.sin(pos_beta0 / 2) * np.sqrt(2)
    x4 = np.sin(neg_beta0 / 2) * np.sqrt(2)
    
    # Compute x0 using the first equation
    x0 = np.sqrt(x1 ** 2 + x2 ** 2 + x3 ** 2 + x4 ** 2)
    
    # Return the values of the reversed operation
    return np.array([x0, x1 * x0, x2 * x0, x3 * x0, x4 * x0])

这个 get_reverse_angles 函数返回了 [ 1.79350156 2.41835701 0.97063605 1.33346136 -1.33346136],而我期待的结果是 [10 20 30 40 50] 的 input_features

1 个回答

1

这个回答是根据@camaya的额外评论重新写的:

  1. 重载的get_angles_or_features函数看起来很有希望,几乎可以解决问题,只需要处理更大的输入特征,也就是input_features = [22393, 22962, 22689, 21849, 20979]
  2. 考虑到input_features中只有一个样本,包含5个元素的5个数字,尝试一下可能值得。输入数据总是包含5个元素,并且是随机排序的。

那么我们有什么呢?

  1. 输入数据input_features = [22393, 22962, 22689, 21849, 20979] - 一组无序的整数。

  2. get_angles函数中声明了三个变量:

    表格“输入数据恢复的阶段”
    步骤 变量 参与计算的元素
    1 beta0 input[1] & input[0] 可以用features[4]恢复
    2 beta1 input[2] 不能用features[2]恢复,变化太多
    3 beta2 input[:] 如果保存input[2],可以用(input[3], input[4])(input[4], input[3])恢复features[0]

    (input[:] == input_features ; def get_angles(x): return features[:])

步骤 1

import numpy as np
from datetime import datetime
from typing import Union, List


def get_angles_or_features(
        input: Union[List[int], np.ndarray[float]]
        ) -> Union[np.ndarray, List, None]:
    """"""

    input_type = type(input).__name__
    # Check type input
    if not (input_type == 'ndarray' or input_type == 'list'):
        print("Input Error")
        return None
    # Processing get angles
    elif input_type == 'list':
        beta0 = (
            2 * np.arcsin((np.sqrt(input[1] ** 2))
                          / np.sqrt(input[0] ** 2 + input[1] ** 2 + 1e-12)
                          )
        )
        beta1 = (
            2 * np.arcsin(np.sqrt(input[2] ** 2)
                          / np.sqrt(input[2] ** 2 + input[2] ** 2 + 1e-12)
                          )
        )
        beta2 = (
            2 * np.arcsin(np.linalg.norm(input[2:]) / np.linalg.norm(input))
        )

        return np.array([beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2])

    # Restoring data input_features
    elif input_type == 'ndarray':
        beta0 = input[4]

        x0, x1, x2, x3, x4 = None, None, None, None, None

        start1 = datetime.now()
        for x0 in range(1, 100000):
            for x1 in range(1, 100000):
                if (check := beta0 == (
                    np.arcsin(np.sqrt(x1 ** 2)
                              / np.sqrt(x0 ** 2 + x1 ** 2 + 1e-12)))):
                    break
            if check:
                print("We spent on the selection "
                      f"of the first two elements: {datetime.now() - start1}")
                break

        return [x0, x1, x2, x3, x4]


# input_features = [10, 20, 30, 40, 50]
input_features = [35, 50, 65, 80, 90]
# input_features = [22393, 22962, 22689, 21849, 20979]
# input_features = [5, 4, 3, 2, 1]
# input_features = [99960, 99970, 99980, 99990, 99999]
# input_features = [3, 2, 1, 5, 4]


# Transform the features
features = np.array(get_angles_or_features(input_features))

print(f"input_features    >>> {input_features}")
print(f"features          >>> {features}")

# Restoring the original data input_features
restored_features = get_angles_or_features(features)

print(f"restored_features >>> {restored_features}")

输出到控制台:

input_features    >>> [35, 50, 65, 80, 90]
features          >>> [ 2.3025178  -0.78539816  0.78539816 -0.96007036  0.96007036]
We spent on the selection of the first two elements: 0:00:25.827939
restored_features >>> [35, 50, None, None, None]

我们可以确保得到前两个元素,但为此我们使用了两个嵌套的for循环,这段代码在最坏情况下的时间复杂度是O(n^2)

步骤 2

在第二步中无法确定第三个元素,只能减少第三步的迭代次数。

import numpy as np
from datetime import datetime
from typing import Union, List


def get_angles_or_features(
        input: Union[List[int], np.ndarray[float]]
        ) -> Union[np.ndarray, List, None]:
    """"""

    input_type = type(input).__name__
    # Check type input
    if not (input_type == 'ndarray' or input_type == 'list'):
        print("Input Error")
        return None
    # Processing get angles
    elif input_type == 'list':
        beta0 = (
            2 * np.arcsin((np.sqrt(input[1] ** 2))
                          / np.sqrt(input[0] ** 2 + input[1] ** 2 + 1e-12)
                          )
        )
        beta1 = (
            2 * np.arcsin(np.sqrt(input[2] ** 2)
                          / np.sqrt(input[2] ** 2 + input[2] ** 2 + 1e-12)
                          )
        )
        beta2 = (
            2 * np.arcsin(np.linalg.norm(input[2:]) / np.linalg.norm(input))
        )

        return np.array([beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2])

    # Restoring data input_features
    elif input_type == 'ndarray':
        beta0, beta1 = input[4], input[2]

        x0, x1, x2, x3, x4 = None, None, None, None, None

        # Step 1
        start1 = datetime.now()
        for x0 in range(1, 100000):
            for x1 in range(1, 100000):
                if (check := beta0 == (
                    np.arcsin(np.sqrt(x1 ** 2)
                              / np.sqrt(x0 ** 2 + x1 ** 2 + 1e-12)))):
                    break
            if check:
                print("We spent on the selection "
                      f"of the first two elements: {datetime.now() - start1}"
                      )
                break
        # Step 2
        start2 = datetime.now()
        _x2 = tuple(x for x in range(1, 100000)
                    if beta1 == np.arcsin(np.sqrt(x ** 2)
                                          / np.sqrt(x ** 2 + x ** 2 + 1e-12)
                                          )
                    )
        end2 = datetime.now()
        print("Reduced future iterations from 100000 "
              f"to {(_len := len(_x2))} and wasted time: {end2 - start2}"
              )
    return [x0, x1, (type(_x2), f"len: {_len}"), x3, x4]


# input_features = [10, 20, 30, 40, 50]
input_features = [35, 50, 65, 80, 90]
# input_features = [22393, 22962, 22689, 21849, 20979]
# input_features = [5, 4, 3, 2, 1]
# input_features = [99960, 99970, 99980, 99990, 99999]
# input_features = [3, 2, 1, 5, 4]


# Transform the features
features = np.array(get_angles_or_features(input_features))

print(f"input_features    >>> {input_features}")
print(f"features          >>> {features}")

# Restoring the original data input_features
restored_features = get_angles_or_features(features)

print(f"restored_features >>> {restored_features}")

输出到控制台:

input_features    >>> [35, 50, 65, 80, 90]
features          >>> [ 2.3025178  -0.78539816  0.78539816 -0.96007036  0.96007036]
We spent on the selection of the first two elements: 0:00:26.472476
Reduced future iterations from 100000 to 43309 and wasted time: 0:00:00.814264
restored_features >>> [35, 50, (<class 'tuple'>, 'len: 43309'), None, None]

然而,43309次的第一次for循环迭代太耗费资源了...

这是因为只有一个元素input_features被用来计算beta1——这增加了反向变化的复杂性。

beta1 = 2 * np.arcsin(np.sqrt(x[2] ** 2) / np.sqrt(x[2] ** 2 + x[2] ** 2 + 1e-12))

如果可以接受为features添加一个元素以保持向后兼容,
那么变化性可以得到平衡。

步骤 3

from typing import Union, Tuple, List
from datetime import datetime

import numpy as np


def get_angles_or_features(
        input: Union[List[int], np.ndarray[float]]
        ) -> Union[Tuple, None]:
    """"""

    input_type = type(input).__name__
    # Check type input
    if not (input_type == 'tuple' or input_type == 'list'):
        print("Input Error")
        return None

    # Processing get angles
    if input_type == 'list':
        beta0 = (
            2 * np.arcsin((np.sqrt(input[1] ** 2))
                          / np.sqrt(input[0] ** 2 + input[1] ** 2 + 1e-12)))
        beta1 = (
            2 * np.arcsin(np.sqrt(input[2] ** 2)
                          / np.sqrt(input[2] ** 2 + input[2] ** 2 + 1e-12)))
        beta2 = (
            2 * np.arcsin(np.linalg.norm(input[2:]) / np.linalg.norm(input)))

        return (np.array([beta2, -beta1 / 2, beta1 / 2,
                          -beta0 / 2, beta0 / 2]), input[2])
    # Conversion angles
    elif input_type == 'tuple':
        beta0, beta2 = input[0][4], input[0][0] / 2
        x2 = int(input[-1])
        start, end = (x2 - 3500 if x2 - 3500 >= 0 else 0,
                      x2 + 3501 if x2 + 3501 <= 43000 else 43000)
        # Defining x0 & x1
        _x0_x1 = tuple(
            (x0, x1)
            for x0 in range(start, end)
            for x1 in range(start, end)
            if (0.46 < x2 / (x0 + x1) < 0.51
                and (beta0 == np.arcsin(np.sqrt(x1 ** 2)
                     / np.sqrt(x0 ** 2 + x1 ** 2 + 1e-12)))
                )
            )[0]
        x0, x1 = _x0_x1
        # Defining x3 & x4
        regeneraite_features = (
            [x0, x1, x2, x3, x4]
            for x3 in range(start, end)
            for x4 in range(start, end)
            if (0.5 < x2 / (x3 + x4) < 0.54
                and (beta2 == np.arcsin(
                              np.linalg.norm([x2, x3, x4])
                              / np.linalg.norm([x0, x1, x2, x3, x4])))
                )
            )

        return tuple(regeneraite_features)


all_input_features = [
    [20979, 20583, 19433, 18988, 18687],
    [22689, 21849, 20979, 20583, 19433],
    [22962, 22689, 21849, 20979, 20583],
    [22393, 22962, 22689, 21849, 20979],
    [21849, 20979, 20583, 19433, 18988]
]

if __name__ == "__main__":
    for input_features in all_input_features:
        # Transform the features
        features = get_angles_or_features(input_features)

        print(f"\ninput_features     >>> {input_features}")
        print(f"features           >>> {features}")
        start_time = datetime.now()
        restored_features = get_angles_or_features(features)
        # print(f"restored_features  >>> {features}")
        print(f"restored_features  >>> {restored_features}")
        print(f"Duration of the recovery process: {datetime.now() - start_time}")

输出到控制台:

input_features     >>> [20979, 20583, 19433, 18988, 18687]
features           >>> (array([ 1.6856525 , -0.78539816,  0.78539816, -0.77587052,  0.77587052]), 19433)        
restored_features  >>> ([20979, 20583, 19433, 18687, 18988], [20979, 20583, 19433, 18988, 18687])
Duration of the recovery process: 0:08:55.662949

input_features     >>> [22689, 21849, 20979, 20583, 19433]
features           >>> (array([ 1.68262106, -0.78539816,  0.78539816, -0.7665401 ,  0.7665401 ]), 20979)        
restored_features  >>> ([22689, 21849, 20979, 19433, 20583], [22689, 21849, 20979, 20583, 19433])
Duration of the recovery process: 0:09:29.221780

input_features     >>> [22962, 22689, 21849, 20979, 20583]
features           >>> (array([ 1.69663709, -0.78539816,  0.78539816, -0.77941808,  0.77941808]), 21849)        
restored_features  >>> ([22962, 22689, 21849, 19089, 22347], [22962, 22689, 21849, 20583, 20979], [22962, 22689, 21849, 20979, 20583], [22962, 22689, 21849, 22347, 19089])
Duration of the recovery process: 0:09:36.666942

input_features     >>> [22393, 22962, 22689, 21849, 20979]
features           >>> (array([ 1.73553479, -0.78539816,  0.78539816, -0.79794298,  0.79794298]), 22689)        
restored_features  >>> ([22393, 22962, 22689, 20979, 21849], [22393, 22962, 22689, 21849, 20979])
Duration of the recovery process: 0:10:10.256594

input_features     >>> [21849, 20979, 20583, 19433, 18988]
features           >>> (array([ 1.68858074, -0.78539816,  0.78539816, -0.76508714,  0.76508714]), 20583)        
restored_features  >>> ([21849, 20979, 20583, 18988, 19433], [21849, 20979, 20583, 19433, 18988])
Duration of the recovery process: 0:09:07.385657

很好。 当你保存了input[2]时,你有机会得到一个可以接受的结果,
但它仍然不是绝对完美的。

此外,恢复过程的持续时间仍然很长。

总结

我们必须经过这三个步骤来表明这种方法的有效性不足。

在处理将来需要的数据时,保持访问这些数据的机会。

至少这样...

from typing import List, Union, Tuple, Dict
import numpy as np

def get_angles(x: List[int]
               ) -> Union[Tuple[np.ndarray, tuple], Dict[tuple, list]]:
    """"""

    beta0 = 2 * np.arcsin(np.sqrt(x[1] ** 2) / np.sqrt(x[0] ** 2 + x[1] ** 2 + 1e-12))
    beta1 = 2 * np.arcsin(np.sqrt(x[2] ** 2) / np.sqrt(x[2] ** 2 + x[2] ** 2 + 1e-12))
    beta2 = 2 * np.arcsin(np.linalg.norm(x[2:]) / np.linalg.norm(x))
    
    return (np.array([beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2]),
            (x[0], x[1], x[2], x[3], x[4])
            )

    # or this way...
    return {(x[0], x[1], x[2], x[3], x[4]):
            [beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2]
            }

你可以更进一步...

from typing import List
import numpy as np


@freeze_arguments
def get_angles(x: List[int]) -> np.ndarray:
    """"""

    beta0 = 2 * np.arcsin(np.sqrt(x[1] ** 2) / np.sqrt(x[0] ** 2 + x[1] ** 2 + 1e-12))
    beta1 = 2 * np.arcsin(np.sqrt(x[2] ** 2) / np.sqrt(x[2] ** 2 + x[2] ** 2 + 1e-12))
    beta2 = 2 * np.arcsin(np.linalg.norm(x[2:]) / np.linalg.norm(x))
    
    return np.array([beta2, -beta1 / 2, beta1 / 2, -beta0 / 2, beta0 / 2])

但那是完全不同的故事!

撰写回答