假设我有单位向量 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的重复。
答案 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]
的单位向量,其中p
和q
小整数,一起构建。然后tan(α)
是理性的。
因此,有一种直截了当的方法可以从v
找回u
:fractions.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)
如果你想要k
,norm([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秒钟来测试。我不确定时间是否可以改善。