非规范化单位向量

时间:2016-03-30 21:07:53

标签: python algorithm numpy

假设我有单位向量 u

from numpy import mat
u = mat([[0.9**0.5], [-(0.1)**0.5]])
# [ 0.9486833  -0.31622777]

单位向量是具有整数条目的矩阵的特征向量。我也知道特征值是整数。因此,单位向量将包含无理小数,当平方时,它们是有理数的十进制近似值。

有没有找到最小值 k 的好方法,以便 k u 的所有条目都是整数?通常, k 将是整数的平方根。

一种天真的方法是对矢量中的每个条目求平方,找到产生整数的最小 k i 。然后, k 将是所有 k i 的LCM的平方根。我希望有一种比这更好的方法。

请注意,这不是this question的重复。

4 个答案:

答案 0 :(得分:2)

你可以对这些项进行平方,找到每个项的连续分数收敛的序列,用最近的平方数替换每个收敛的分子,并寻找出现在所有收敛数中的最小分母收敛列表(作为具有可容忍精度的收敛的一部分)。您对"可容忍准确度的定义"允许算法处理一些舍入误差而不会产生非常大的结果。在你的例子中,9/10和1/10将是最初的几个收敛者之间,相对误差小于10 ^ -9,而sqrt(10)将是你的缩放因子(乘以[3, - 1]你可以直接读取会聚分子的平方根,如果你确保恢复标志)。但是,如果此算法没有找到共同点,该怎么办还不清楚。

答案 1 :(得分:2)

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

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 = matrix([[0.9486833], [-0.31622777]])
>>> get_k(u)
3.1622776601683795
>>> get_k(u) * u
matrix([[ 3.00000001],
        [-1.00000001]])

答案 2 :(得分:2)

允许u=[cos(α),sin(α)] v=[p,q]的单位向量,其中pq 整数,一起构建。然后tan(α)是理性的。

因此,有一种直截了当的方法可以从v找回ufractions.Fraction(u[1]/u[0]).limit_denominator()

示例:

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)

如果你想要knorm([f.numerator,f.denominator])给它。

p=0是一个微不足道的特例。

答案 3 :(得分:2)

我改进了Christian提供的方法,以便接受更广泛的分数。诀窍是&#34;预标准化&#34;单位矢量除以最小的非零项。这适用于指定最大分母的所有分数。

ExternalResource

测试:

以下代码用于确保给定范围内的所有分数都能正常工作。

@Rule
private static final ExternalResource embeddedAMQPBroker = new ExternalResource() {
    Broker broker;

    @Override
    protected void before() throws Throwable {
        BrokerOptions brokerOptions = new BrokerOptions();
        brokerOptions.setConfigProperty("qpid.amqp_port", "55672");
        broker = new Broker();
        broker.startup(brokerOptions);
    }

    @Override
    protected void after() {
        broker.shutdown();
    }
};

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