Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 单位向量反规范化_Python_Algorithm_Numpy - Fatal编程技术网

Python 单位向量反规范化

Python 单位向量反规范化,python,algorithm,numpy,Python,Algorithm,Numpy,假设我有单位向量,u from numpy import mat u = mat([[0.9**0.5], [-(0.1)**0.5]]) # [ 0.9486833 -0.31622777] 单位向量是具有整数项的矩阵的特征向量。我也知道特征值是整数。因此,单位向量将包含无理小数,当平方时,是有理数的十进制近似值 有没有什么好方法可以找到最小值k,使得ku的所有条目都是整数?通常,k是整数的平方根 一种简单的方法是将向量中的每个条目平方,然后找到生成整数的最小ki。那么,k将是所有ki的L

假设我有单位向量,u

from numpy import mat
u = mat([[0.9**0.5], [-(0.1)**0.5]])
# [ 0.9486833  -0.31622777]
单位向量是具有整数项的矩阵的特征向量。我也知道特征值是整数。因此,单位向量将包含无理小数,当平方时,是有理数的十进制近似值

有没有什么好方法可以找到最小值k,使得ku的所有条目都是整数?通常,k是整数的平方根

一种简单的方法是将向量中的每个条目平方,然后找到生成整数的最小ki。那么,k将是所有ki的LCM的平方根。我希望有比这更好的方法



请注意,这不是重复项。

您可以对这些项进行平方运算,找到每个项的连分数收敛序列,用最近的平方数替换每个收敛项的分子,并查找所有收敛项列表中出现的最小分母(作为收敛项的一部分,精度可以接受)。您对“可容忍精度”的定义允许算法处理一点舍入误差,而不会产生非常大的结果。在您的示例中,9/10和1/10将是前几个收敛点之一,相对误差小于10^-9,sqrt(10)将是您的比例因子(乘以[3,-1],如果确保恢复符号,您可以直接从收敛点分子的平方根中读取)。但是,如果这个算法找不到公分母,我们还不清楚该怎么办。

好的,这是我的最佳尝试。这个算法似乎有效,但我不能保证它会比您最初提出的更快:

import numpy as np
from fractions import Fraction, gcd

# need some finesse and knowledge of problem domain to fine tune this parameter
# otherwise you'll end up with extremely large k due to precision problems
MAX_DENOMINATOR = 1000

# least common multiple
def lcm(a, b):
    return a * b / gcd(a, b)

# returns the denominator of the square of a number
def get_square_denominator(x):
    return Fraction(x ** 2).limit_denominator(MAX_DENOMINATOR).denominator

# returns the smallest multiplier, k, that can be used to scale a vector to
# have integer coefficients. Assumes vector has the property that it can be 
# expressed as [x**0.5, y**0.5, ...] where x, y, ... are rational with 
# denominators <= MAX_DENOMINATOR
def get_k(v):
    denominators = [get_square_denominator(i.item()) for i in v]
    return reduce(lcm, denominators) ** 0.5
u=[cos(α),sin(α)]
v=[p,q]的单位向量,其中
p
q
是小整数,一起素数。然后,
tan(α)
是一个有理数

因此,有一种简单的方法可以从
u
中找到
v
分数。分数(u[1]/u[0])。限制分母()

例如:

v=array([-1,3])
u=v/np.linalg.norm(v)
# array([-0.31622777,  0.9486833 ])
f=Fraction(u[1]/u[0]).limit_denominator()
# Fraction(-1, 3)
如果你想要
k
范数([f.分子,f.分母])
给出它


p=0
是一个微不足道的特殊情况。

我改进了Christian提供的方法,以便接受范围更广的分数。诀窍是通过将单位向量除以最小的非零项来“预规范化”单位向量。这对于指定最大分母的所有分数都可靠

from fractions import Fraction, gcd

def recover_integer_vector(u, denom=50):
    '''
    For a given vector u, return the smallest vector with all integer entries.
    '''

    # make smallest non-zero entry 1
    u /= min(abs(x) for x in u if x)

    # get the denominators of the fractions
    denoms = (Fraction(x).limit_denominator(denom).denominator for x in u)

    # multiply the scaled u by LCM(denominators)
    lcm = lambda a, b: a * b / gcd(a, b)
    return u * reduce(lcm, denoms)

测试: 以下代码用于确保给定范围内的所有分数正常工作

import numpy as np

from numpy import array
from itertools import combinations_with_replacement


for t in combinations_with_replacement(range(1, 50), 3):
    if reduce(gcd, t) != 1: continue

    v = array(map(float, t))
    u = v / np.linalg.norm(v)

    w = recover_integer_vector(u)

    assert np.allclose(w, v) or np.allclose(w, -v)


从测试时间可以看出,此代码不是很快。我的电脑花了大约6秒钟来测试。我不确定是否可以改进计时。

对于任意单位向量,不一定可以对其进行缩放,使两个条目都是整数。你只关心具有这个性质的单位向量子集吗?@Christian我知道单位向量是一个具有整数项的矩阵的特征向量,并且特征值也是整数。因此,在标准化之前,向量肯定具有有理值。我会把这一点补充到问题中。你只可以访问特征值和特征向量,还是可以访问这些特征值和特征向量的原始矩阵?@Christian我可以访问,但我不想重新计算矩阵的对角线。我主要是寻找不依赖特征值或矩阵的解决方案,因为这不适用于其他情况。目前,这里有一个解决方案。我回家后会尝试实现它。向量的长度和公分母都是相对有界的(即没有疯狂的情况)。据推测,这将有助于“可容忍的准确性”和准确识别除数的LCM?这似乎是一个有趣的方法,但这不会具有与原始“天真方法”相同的算法复杂性吗?@Christian我的直觉让我认为这种方法将是O(logn)而不是O(n)其中n是分母,但我需要重新研究连分数来验证这个说法。就复杂性而言,“最近的平方数部分”显然是恒定时间。你对这个问题非常好奇,你有什么见解吗?(我不想让这听起来好斗,任何想法都是受欢迎的。)我非常愿意承认数字的东西不是我的强项,所以我很高兴在这里看到更多的答案。我不确定这种方法是否比其他方法更快或更好,只是把它作为一个建议扔出去:)@Jared没有感觉到战斗力。我对这个问题很感兴趣,整天都在思考这个问题,但还没有想出比你最初提出的算法更好的方法。希望不久我会有一个想法:)这工作做得很好,很好。为了对复杂性产生任何影响,我们必须深入研究分数的内部工作机制,这本身可能是另一个冒险。要详细说明,
float.as_integer_ratio
启动该过程,但会产生10^15的分母。剩下的工作是在
极限分母
中完成的,其中一部分类似于欧几里得算法。从docstring中,“那么可以证明有理数是x的最佳上下近似,当且仅当它是(唯一最短)连分式的收敛或半收敛。”很高兴你喜欢它!是的,我想知道
分数
模块是否在幕后使用了@Hobbs的一些聚合思想。至于复杂性,我有点不知所措,但如果有什么问题的话,在大多数情况下,它可能会比你最初的建议运行得更快,因为
分数
是(希望)高度优化的。经过进一步的测试,这仅限于非常小的分母。例如,[-50,1]将不起作用
import numpy as np

from numpy import array
from itertools import combinations_with_replacement


for t in combinations_with_replacement(range(1, 50), 3):
    if reduce(gcd, t) != 1: continue

    v = array(map(float, t))
    u = v / np.linalg.norm(v)

    w = recover_integer_vector(u)

    assert np.allclose(w, v) or np.allclose(w, -v)