def block_Lanczos(Sigma_func,B_,n_mc_smps):
"""
block Lanczos method to approx Sigma^1/2 * B, with B matrix of N(0,1)'s.
Used to generate multiple approximate large normal draws.
"""
n = tf.shape(B_)[0] #dim of the multivariate normal
s = n_mc_smps #number of samples to draw
k = tf.div(n,500) + 3 #number of Lanczos iterations
betas = tf.zeros([1,s])
alphas = tf.zeros([0,s])
D = tf.zeros([s,n,1])
B_norms = tf.norm(B_,axis=0)
D = tf.concat([D,tf.expand_dims(tf.transpose(B_/B_norms),2)],2)
def cond(j,alphas,betas,D):
return j < k+1
#TODO: use block-CG in place of Sigma
def body(j,alphas,betas,D):
d_j = tf.squeeze(tf.slice(D,[0,0,j],[-1,-1,1]))
d = Sigma_func(tf.transpose(d_j)) - (tf.slice(betas,[j-1,0],[1,-1])*
tf.transpose(tf.squeeze(tf.slice(D,[0,0,j-1],[-1,-1,1]))))
alphas = tf.concat([alphas,[tf.diag_part(tf.matmul(d_j,d))]],0)
d = d - tf.slice(alphas,[j-1,0],[1,-1])*tf.transpose(d_j)
betas = tf.concat([betas,[tf.norm(d,axis=0)]],0)
D = tf.concat([D,tf.expand_dims(tf.transpose(d/tf.slice(betas,[j,0],[1,-1])),2)],2)
return j+1,alphas,betas,D
j = tf.constant(1)
j,alphas,betas,D = tf.while_loop(cond,body,loop_vars=[j,alphas,betas,D],
shape_invariants=[j.get_shape(),tf.TensorShape([None,None]),
tf.TensorShape([None,None]),tf.TensorShape([None,None,None])])
D_ = tf.slice(D,[0,0,1],[-1,-1,k])
##TODO: replace loop
H = tf.zeros([0,k,k])
for ss in range(s):
this_beta = tf.diag(tf.squeeze(tf.slice(betas,[1,ss],[k-1,1])))
#build out tridiagonal H: alphas_1:k on main, betas_2:k on off
this_H = (tf.diag(tf.squeeze(tf.slice(alphas,[0,ss],[-1,1]))) +
tf.pad(this_beta,[[1,0],[0,1]]) +
tf.pad(this_beta,[[0,1],[1,0]]))
H = tf.concat([H,tf.expand_dims(this_H,0)],0)
E,V = tf.self_adjoint_eig(H)
E_sqrt = tf.zeros([0,k,k])
#TODO: replace loop
for ss in range(s):
#ensure positive definite
E_sqrt = tf.concat([E_sqrt,tf.expand_dims(tf.diag(tf.squeeze(tf.sqrt(tf.maximum(tf.slice(E,[ss,0],[1,-1]),1e-6)))),0)],0)
sq_H = tf.matmul(V,tf.matmul(E_sqrt,tf.transpose(V,perm=[0,2,1])))
e1 = tf.expand_dims(tf.transpose(tf.tile(tf.slice(tf.eye(k),[0,0],[-1,1]),[1,s])),2)
out = B_norms*tf.transpose(tf.squeeze(tf.matmul(D_,tf.matmul(sq_H,e1))))
return out
评论列表
文章目录