first commit with current lessons
This commit is contained in:
111
10-04/genQf.jl
Normal file
111
10-04/genQf.jl
Normal file
@ -0,0 +1,111 @@
|
||||
using Random
|
||||
using LinearAlgebra
|
||||
|
||||
function genQf(n::Integer; fseed::Integer=0, rank::Real=1.1, conv::Real=1, ecc::Real=0.99, dom::Real=1, box::Real=1, q::Union{Vector, Nothing}=nothing, v::Union{Real, Nothing}=nothing)::Tuple{Matrix, Union{Vector, Nothing}, Union{Real, Nothing}}
|
||||
if n <= 0
|
||||
throw(ArgumentError(n, "n must be > 0"))
|
||||
end
|
||||
if rank <= 0
|
||||
throw(ArgumentError(rank, "rank must be > 0"))
|
||||
end
|
||||
if !(0 <= conv <= 1)
|
||||
throw(ArgumentError(conv, "conv must be in [0, 1]"))
|
||||
end
|
||||
if !(0 <= ecc < 1)
|
||||
throw(ArgumentError(ecc, "ecc must be in [0, 1)"))
|
||||
end
|
||||
if dom < 0
|
||||
throw(ArgumentError(dom, "dom must be >= 0"))
|
||||
end
|
||||
if box == 0
|
||||
throw(ArgumentError(box, "box must not be 0"))
|
||||
end
|
||||
|
||||
Random.seed!(fseed)
|
||||
|
||||
# generate Q- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# first step: generate the appropriate rank and positive / negative
|
||||
# definiteness
|
||||
|
||||
r = round(Int, rank * n)
|
||||
p = round(Int, r * conv)
|
||||
|
||||
if p > 0
|
||||
G = rand(p, n)
|
||||
Q = G' * G
|
||||
else
|
||||
Q = zeros(n, n)
|
||||
end
|
||||
|
||||
if r > p
|
||||
G = rand(r - p, n)
|
||||
Q = Q - (G' * G)
|
||||
end
|
||||
|
||||
# second step: if dom ~= 1, modify the diagonal
|
||||
# increase or decrease randomly each element by [ - 1/3 , 1/3 ] of its
|
||||
# initial value, then multiply it by dom
|
||||
|
||||
if dom != 1
|
||||
D = diag(Q)
|
||||
D = D .* (1 .+ (2 .* rand(n, 1) .- 1) ./ 3)
|
||||
D = dom * D
|
||||
@view(Q[diagind(Q)]) .= D
|
||||
end
|
||||
|
||||
# compute eigenvalue decomposition
|
||||
F = eigen(Q); # V * D * V' = Q , D( 1 , 1 ) = \lambda_n
|
||||
V = F.vectors
|
||||
D = F.values
|
||||
|
||||
if D[1] > 1e-14
|
||||
# modify eccentricity only if \lambda_n > 0, for when \lambda_n = 0 the
|
||||
# eccentricity is 1 by default
|
||||
#
|
||||
# the formula is:
|
||||
#
|
||||
# \lambda_i - \lambda_n 2 * ecc
|
||||
# \lambda_i = \lambda_n + --------------------- * \lambda_n -------
|
||||
# \lambda_1 - \lambda_n 1 - ecc
|
||||
#
|
||||
# This leaves \lambda_n unchanged, and modifies all the other ones
|
||||
# proportionally so that
|
||||
#
|
||||
# \lambda_1 - \lambda_n
|
||||
# --------------------- = ecc (exercise: check)
|
||||
# \lambda_1 - \lambda_n
|
||||
l = D[1] .* ones(n) + ((D[1] / (D[n] - D[1])) * (2 * ecc / (1 - ecc))) .* (D - D[1] .* ones(n))
|
||||
Q = V * diagm(l) * V';
|
||||
end
|
||||
|
||||
if q != nothing || v != nothing
|
||||
# if so required generate q- - - - - - - - - - - - - - - - - - - - - - -
|
||||
#
|
||||
# we first generate the unconstrained minimum x_* of the problem in the
|
||||
# box [ - abs( box ) , abs( box ) ] and then we set q = - Q * x_*
|
||||
|
||||
x = 2 * abs(box) .* rand(n) .- abs(box)
|
||||
q = -Q * x
|
||||
|
||||
# if so required, we now randomly destroy the alignment between q and
|
||||
# the image of Q so as to make it hard to solve Q x = q
|
||||
|
||||
if ( box < 0 ) && (D[1] <= 1e-14 )
|
||||
q = q .* ((4/3) .* rand(n) .- (2/3))
|
||||
end
|
||||
end
|
||||
|
||||
if v != nothing
|
||||
# if so required compute v. - - - - - - - - - - - - - - - - - - - - -
|
||||
# v is finite-valued only if either Q is strictly positive definite
|
||||
# or it is positive semidefinite but q has been constructed in such
|
||||
# a was that Q * x + q = 0 has a solution (that is the x we have)
|
||||
if (D[1] > 1e-14) || ((D[1] > -1e-14) && (box > 0))
|
||||
v = dot(q', x) / 2
|
||||
else
|
||||
v = -Inf
|
||||
end
|
||||
end
|
||||
|
||||
return (Q, q, v)
|
||||
end
|
||||
Reference in New Issue
Block a user