-
Notifications
You must be signed in to change notification settings - Fork 46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
schur complementary portfolio - difference between theoretical formulation and code #36
Comments
Looking ....
…On Tue, May 7, 2024 at 12:10 PM Marzio-USI ***@***.***> wrote:
When inspecting the Shur complementary portfolio, I encountered some
issues.
In the formulation of your presentation this can be found:
1.WJUNzwuJfEXrJmD0Qkot6g.png (view on web)
<https://github.com/microprediction/precise/assets/71531645/4f1192b3-f664-4cad-913d-fd110bc3c689>
Screenshot.2024-05-07.at.18.06.19.png (view on web)
<https://github.com/microprediction/precise/assets/71531645/267db4ad-9939-429c-8f63-15ca39aad6d0>
with
$$A^{c}(\gamma)= A - \gamma B D^{-1}C$$
By following the third step of the algorithm (Augment and allocate)
starting from
precise/precise/skaters/portfoliostatic/schurportfactory.py line 122
# 3. Augment and allocate
Ag, Dg, info = schur_augmentation(A=A, B=B, C=C, D=D, gamma=gamma) <--------HERE
precise/precise/skaters/portfoliostatic/schurportutil.py , line 13
def schur_augmentation(A,B,C,D, gamma):
""" Mess with A, D to try to incorporate some off-diag info """
if gamma>0.0:
max_gamma = _maximal_gamma(A=A, B=B, C=C, D=D)
augA, bA = pseudo_schur_complement(A=A, B=B, C=C, D=D, gamma=gamma * max_gamma) # <-------------HERE
augD, bD = pseudo_schur_complement(A=D, B=C, C=B, D=A, gamma=gamma * max_gamma) # <---------HERE TOO
augmentation_fail = False
if not is_positive_def(augA):
try:
Ag = nearest_pos_def(augA)
except np.linalg.LinAlgError:
augmentation_fail=True
else:
Ag = augA
if not is_positive_def(augD):
try:
Dg = nearest_pos_def(augD)
except np.linalg.LinAlgError:
augmentation_fail=True
else:
Dg = augD
if augmentation_fail:
print('Warning: augmentation failed')
reductionA = 1.0
reductionD = 1.0
reductionRatioA = 1.0
Ag = A
Dg = D
else:
reductionD = np.linalg.norm(Dg)/np.linalg.norm(D)
reductionA = np.linalg.norm(Ag)/np.linalg.norm(A)
reductionRatioA = reductionA/reductionD
else:
reductionRatioA = 1.0
reductionA = 1.0
reductionD = 1.0
Ag = A
Dg = D
info = {'reductionA': reductionA,
'reductionD': reductionD,
'reductionRatioA': reductionRatioA}
return Ag, Dg, info
We arrive at this pseudo_schur_complement function where $A^{c}(\gamma)=
A - \gamma B D^{-1}C$ is computed:
precise/precise/skaters/portfoliostatic/schurportutil.py , line 57
def pseudo_schur_complement(A, B, C, D, gamma, lmbda=None, warn=False):
""" Augmented cov matrix for "A" inspired by the Schur complement """
if lmbda is None:
lmbda=gamma
try:
Ac_raw = schur_complement(A=A, B=B, C=C, D=D, gamma=gamma)
nA = np.shape(A)[0]
nD = np.shape(D)[0]
Ac = to_symmetric(Ac_raw)
M = symmetric_step_up_matrix(n1=nA, n2=nD)
Mt = np.transpose(M)
BDinv = multiply_by_inverse(B, D, throw=False)
BDinvMt = np.dot(BDinv, Mt)
Ra = np.eye(nA) - lmbda * BDinvMt
Ag = inverse_multiply(Ra, Ac, throw=False, warn=False)
except np.linalg.LinAlgError:
if warn:
print('Pseudo-schur failed, falling back to A')
Ag = A
n = np.shape(A)[0]
b = np.ones(shape=(n,1))
return Ag, b
However after that the following operations are performed:
$$ \begin{aligned} Ag &= Ra^{-1} \cdot Ac\\ &= (I - \lambda B
D^{-1}M^T)^{-1} \cdot Ac \\ &= (I - \lambda B D^{-1}M^T)^{-1} \cdot
\text{tosim}(Ac_raw) \\ &= (I - \lambda B D^{-1}M^T)^{-1} \cdot
\text{tosim}(A^{c}(\gamma)) \\ &= (I - \lambda B D^{-1}M^T)^{-1} \cdot
\text{tosim}(A - \gamma B D^{-1}C) \\ \end{aligned} $$
So if we assume that $Ac$ is already symmetric (to simplify the process):
$$ \begin{aligned} Ag &= (I - \lambda B D^{-1}M^T)^{-1} \cdot (A - \gamma
B D^{-1}C) \\ \end{aligned} $$
Which does not match what I expect from the presentation:
2. "Before performing inter-group allocation we make a different
modification. We multiply the precision of $A^c$ by $b_Ab_A^T$
element-wise (and similarly, multiply the precision of $D^c$ by
$b_Db_D^T$)".
Meaning:
$$ A' = (A - \gamma B D^{-1}C)^{*b_A} $$
Specifically I dont understand where $M$ the symmetric step up matrix
comes from and why $b_A$ is never computed.
And again when we perform the sub allocation:
precise/precise/skaters/portfoliostatic/schurportfactory.py lines 132 and
138
# Sub-allocatewA = hierarchical_schur_complementary_portfolio(cov=Ag, port=port, port_kwargs=port_kwargs,
alloc=alloc, alloc_kwargs=alloc_kwargs,
splitter=splitter, splitter_kwargs=splitter_kwargs,
seriator=seriator, seriator_kwargs=seriator_kwargs,
seriation_depth = seriation_depth-1,
delta=delta, gamma=gamma)wD = hierarchical_schur_complementary_portfolio(cov=Dg, port=port, port_kwargs=port_kwargs,
alloc=alloc, alloc_kwargs=alloc_kwargs,
splitter=splitter, splitter_kwargs=splitter_kwargs,
seriator=seriator, seriator_kwargs=seriator_kwargs,
seriation_depth=seriation_depth - 1,
delta=delta, gamma=gamma)
the same augmented matrix $Ag$ used to allocate in:
precise/precise/skaters/portfoliostatic/schurportfactory.py line 122
# 3. Augment and allocateAg, Dg, info = schur_augmentation(A=A, B=B, C=C, D=D, gamma=gamma)aA, aD = alloc(covs=[Ag, Dg]) #<----------HERE
is also passed to the next "iteration", while on the slides I found:
1. The intra-group allocation pertaining to block $A$ is determined by
covariance matrix $A_{/ b_A(\lambda)}^c$. In this notation the vector $b_A(\lambda)=\overrightarrow{1}-\lambda
B D^{-1} \overrightarrow{1}$. The generalized Schur complement is $A^c(\gamma)=A-\gamma
B D^{-1} C$. The notation $A_{/ b}^c$ denotes $A^c /\left(b b^T\right)$
with division performed element-wise.
$$ A'' = A^c(\gamma)/b_Ab_A^T $$
—
Reply to this email directly, view it on GitHub
<#36>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANWLINM526MLLE3YOU2YIDLZBD4HTAVCNFSM6AAAAABHLJ5UTOVHI2DSMVQWIX3LMV43ASLTON2WKOZSGI4DGNZUGE4DGMA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
My mistake; in case someone is having the same doubts, this might be helpful: Where
The minimum variance portfolio: We can view any expression of the form In particular if Schur AllocationInstead with Schur allocation we can say that: Where Thus, the global minimum variance allocation is proportional to: With Which can be transformed as follows: We can then define a matrix To simplify it to: So that we can group them together Thus following the matrix inverse property: We can do: where and In conclusion: One question that still remains is how to choose From my perspective, Let me know if something is wrong or missing, and if there is a particular motivation for which |
That's exactly right the choice of step-up matrix is a bit arbitrary here. |
When inspecting the Shur complementary portfolio, I encountered some issues.
In the formulation of your presentation this can be found:
with
$$A^{c}(\gamma)= A - \gamma B D^{-1}C$$
By following the third step of the algorithm (Augment and allocate) starting from
precise/precise/skaters/portfoliostatic/schurportfactory.py
line 122precise/precise/skaters/portfoliostatic/schurportutil.py
, line 13We arrive at this pseudo_schur_complement function where$A^{c}(\gamma)= A - \gamma B D^{-1}C$ is computed:
precise/precise/skaters/portfoliostatic/schurportutil.py
, line 57However after that the following operations are performed:
So if we assume that$Ac$ is already symmetric (to simplify the process):
Which does not match what I expect from the presentation:
Meaning:
Specifically I dont understand where$M$ the symmetric step up matrix comes from and why $b_A$ is never computed.
And again when we perform the sub allocation:
precise/precise/skaters/portfoliostatic/schurportfactory.py
lines 132 and 138the same augmented matrix$Ag$ used to allocate in:
precise/precise/skaters/portfoliostatic/schurportfactory.py
line 122is also passed to the next "iteration", while on the slides I found:
The text was updated successfully, but these errors were encountered: