Skip to content

Commit ef7cde5

Browse files
Switch lambda to eigenvalue of L (graph Laplacian), not W
Previously lambda was the eigenvalue of the mixing matrix W. Now lambda is the eigenvalue of the graph Laplacian L, with W = I - L. Parser: - L → lam (was L → 1-lam) - W → 1-lam (was W → lam) Library: - All distributed TFs updated: substitute lam → (1-lam) and regenerate - Cross-category check uses lambda=0 (trivial one-node graph) instead of lambda=1 (which was the old fully-connected-graph edge case) - Notes updated to reference L instead of W Display: - "Linear oracle: L (eigenvalue λ)" instead of W - About section: add L and W to supported oracles table Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 441c730 commit ef7cde5

5 files changed

Lines changed: 38 additions & 36 deletions

File tree

webapp/data/algorithms.json

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@
613613
"citation": "Li et al. 2019",
614614
"doi": "https://doi.org/10.1109/TSP.2019.2926022",
615615
"bibtex": "@article{li2019decentralized,\n title={A decentralized proximal-gradient method with network independent step-sizes and separated convergence rates},\n author={Li, Zhi and Shi, Wei and Yan, Ming},\n journal={IEEE Transactions on Signal Processing},\n volume={67},\n number={17},\n pages={4494--4506},\n year={2019},\n publisher={IEEE}\n}",
616-
"notes": "Decentralized algorithm. The transfer function characterizes behavior per spectral mode of the mixing matrix W (eigenvalue λ).",
616+
"notes": "Decentralized algorithm. The transfer function characterizes behavior per spectral mode of the graph Laplacian L (eigenvalue λ).",
617617
"oracles": [
618618
"grad_f"
619619
],
@@ -625,7 +625,7 @@
625625
"parameters": [
626626
"alpha"
627627
],
628-
"transferFunction": "-alpha*lam*(z - 1)/(z**2 - 2*lam*z + lam)",
628+
"transferFunction": "(alpha*lam*z - alpha*lam - alpha*z + alpha)/(2*lam*z - lam + z**2 - 2*z + 1)",
629629
"tfIsMatrix": false,
630630
"equivalences": {
631631
"oracle": [
@@ -635,7 +635,7 @@
635635
"lft": []
636636
},
637637
"catalogOnly": false,
638-
"tf_latex": "\\frac{- \\alpha \\lambda z + \\alpha \\lambda}{z^{2} - 2 \\lambda z + \\lambda}"
638+
"tf_latex": "\\frac{\\alpha \\left(\\lambda - 1\\right) z - \\alpha \\left(\\lambda - 1\\right)}{z^{2} + 2 \\left(\\lambda - 1\\right) z -\\left(\\lambda - 1\\right)}"
639639
},
640640
{
641641
"id": "exact_diffusion",
@@ -644,7 +644,7 @@
644644
"citation": "Yuan et al. 2018",
645645
"doi": "https://doi.org/10.1109/TSP.2018.2875898",
646646
"bibtex": "@article{yuan2018exact,\n title={Exact diffusion for distributed optimization and learning---{P}art {I}: Algorithm development},\n author={Yuan, Kun and Ying, Bicheng and Zhao, Xiaochuan and Sayed, Ali H},\n journal={IEEE Transactions on Signal Processing},\n volume={67},\n number={3},\n pages={708--723},\n year={2018},\n publisher={IEEE}\n}",
647-
"notes": "Decentralized algorithm using adapt-correct-combine steps. The transfer function characterizes behavior per spectral mode of the mixing matrix W (eigenvalue λ). Oracle-equivalent to NIDS.",
647+
"notes": "Decentralized algorithm using adapt-correct-combine steps. The transfer function characterizes behavior per spectral mode of the graph Laplacian L (eigenvalue λ). Oracle-equivalent to NIDS.",
648648
"oracles": [
649649
"grad_f"
650650
],
@@ -658,7 +658,7 @@
658658
"parameters": [
659659
"alpha"
660660
],
661-
"transferFunction": "-alpha*lam*(z - 1)/(z**2 - 2*lam*z + lam)",
661+
"transferFunction": "(alpha*lam*z - alpha*lam - alpha*z + alpha)/(2*lam*z - lam + z**2 - 2*z + 1)",
662662
"tfIsMatrix": false,
663663
"equivalences": {
664664
"oracle": [
@@ -668,7 +668,7 @@
668668
"lft": []
669669
},
670670
"catalogOnly": false,
671-
"tf_latex": "\\frac{- \\alpha \\lambda z + \\alpha \\lambda}{z^{2} - 2 \\lambda z + \\lambda}"
671+
"tf_latex": "\\frac{\\alpha \\left(\\lambda - 1\\right) z - \\alpha \\left(\\lambda - 1\\right)}{z^{2} + 2 \\left(\\lambda - 1\\right) z -\\left(\\lambda - 1\\right)}"
672672
},
673673
{
674674
"id": "extra_distributed",
@@ -691,15 +691,15 @@
691691
"parameters": [
692692
"alpha"
693693
],
694-
"transferFunction": "(-2*alpha*z + 2*alpha)/(-2*lam*z + lam + 2*z**2 - 2*z + 1)",
694+
"transferFunction": "(-2*alpha*z + 2*alpha)/(2*lam*z - lam + 2*z**2 - 4*z + 2)",
695695
"tfIsMatrix": false,
696696
"equivalences": {
697697
"oracle": [],
698698
"shift": [],
699699
"lft": []
700700
},
701701
"catalogOnly": false,
702-
"tf_latex": "\\frac{- 2 \\alpha z + 2 \\alpha}{2 z^{2} - 2 \\left(\\lambda + 1\\right) z + \\lambda + 1}"
702+
"tf_latex": "\\frac{- 2 \\alpha z + 2 \\alpha}{2 z^{2} + 2 \\left(\\lambda - 2\\right) z -\\left(\\lambda - 2\\right)}"
703703
},
704704
{
705705
"id": "diging",
@@ -723,15 +723,15 @@
723723
"parameters": [
724724
"alpha"
725725
],
726-
"transferFunction": "(-alpha*z + alpha)/(lam**2 - 2*lam*z + z**2)",
726+
"transferFunction": "(-alpha*z + alpha)/(lam**2 + 2*lam*z - 2*lam + z**2 - 2*z + 1)",
727727
"tfIsMatrix": false,
728728
"equivalences": {
729729
"oracle": [],
730730
"shift": [],
731731
"lft": []
732732
},
733733
"catalogOnly": false,
734-
"tf_latex": "\\frac{- \\alpha z + \\alpha}{z^{2} - 2 \\lambda z + \\lambda^{2}}"
734+
"tf_latex": "\\frac{- \\alpha z + \\alpha}{z^{2} + 2 \\left(\\lambda - 1\\right) z + \\left(\\lambda - 1\\right)^{2}}"
735735
},
736736
{
737737
"id": "augdgm",
@@ -755,15 +755,15 @@
755755
"parameters": [
756756
"alpha"
757757
],
758-
"transferFunction": "(-alpha*lam*z + alpha*lam)/(lam**2 - 2*lam*z + z**2)",
758+
"transferFunction": "(alpha*lam*z - alpha*lam - alpha*z + alpha)/(lam**2 + 2*lam*z - 2*lam + z**2 - 2*z + 1)",
759759
"tfIsMatrix": false,
760760
"equivalences": {
761761
"oracle": [],
762762
"shift": [],
763763
"lft": []
764764
},
765765
"catalogOnly": false,
766-
"tf_latex": "\\frac{- \\alpha \\lambda z + \\alpha \\lambda}{z^{2} - 2 \\lambda z + \\lambda^{2}}"
766+
"tf_latex": "\\frac{\\alpha \\left(\\lambda - 1\\right) z - \\alpha \\left(\\lambda - 1\\right)}{z^{2} + 2 \\left(\\lambda - 1\\right) z + \\left(\\lambda - 1\\right)^{2}}"
767767
},
768768
{
769769
"id": "svl",
@@ -790,15 +790,15 @@
790790
"gamma",
791791
"delta"
792792
],
793-
"transferFunction": "(-alpha*delta*lam*z + alpha*delta*lam + alpha*delta*z - alpha*delta - alpha*z + alpha)/(-beta*lam + beta - gamma*lam*z + gamma*lam + gamma*z - gamma + z**2 - 2*z + 1)",
793+
"transferFunction": "(alpha*delta*lam*z - alpha*delta*lam - alpha*z + alpha)/(beta*lam + gamma*lam*z - gamma*lam + z**2 - 2*z + 1)",
794794
"tfIsMatrix": false,
795795
"equivalences": {
796796
"oracle": [],
797797
"shift": [],
798798
"lft": []
799799
},
800800
"catalogOnly": false,
801-
"tf_latex": "\\frac{- \\alpha \\left(\\delta \\lambda - \\delta + 1\\right) z + \\alpha \\left(\\delta \\lambda - \\delta + 1\\right)}{z^{2} -\\left(\\gamma \\lambda - \\gamma + 2\\right) z - \\beta \\lambda + \\beta + \\gamma \\lambda - \\gamma + 1}"
801+
"tf_latex": "\\frac{\\alpha \\left(\\delta \\lambda - 1\\right) z - \\alpha \\left(\\delta \\lambda - 1\\right)}{z^{2} + \\left(\\gamma \\lambda - 2\\right) z + \\beta \\lambda - \\gamma \\lambda + 1}"
802802
},
803803
{
804804
"id": "unified_extra",
@@ -824,15 +824,15 @@
824824
"l",
825825
"mu"
826826
],
827-
"transferFunction": "(-alpha*z + alpha)/(-alpha*l*lam**2*mu**2 + 2*alpha*l*lam*mu**2 - alpha*l*lam*mu - alpha*l*mu**2 + alpha*l*mu + lam**2*mu**2 - 2*lam*mu**2 - 2*lam*mu*z + 2*lam*mu + mu**2 + 2*mu*z - 2*mu + z**2 - 2*z + 1)",
827+
"transferFunction": "(-alpha*z + alpha)/(-alpha*l*lam**2*mu**2 + alpha*l*lam*mu + lam**2*mu**2 + 2*lam*mu*z - 2*lam*mu + z**2 - 2*z + 1)",
828828
"tfIsMatrix": false,
829829
"equivalences": {
830830
"oracle": [],
831831
"shift": [],
832832
"lft": []
833833
},
834834
"catalogOnly": false,
835-
"tf_latex": "\\frac{- \\alpha z + \\alpha}{z^{2} - 2 \\left(\\lambda \\mu - \\mu + 1\\right) z - \\left(\\lambda \\mu - \\mu + 1\\right) \\left(\\alpha l \\lambda \\mu - \\alpha l \\mu - \\lambda \\mu + \\mu - 1\\right)}"
835+
"tf_latex": "\\frac{- \\alpha z + \\alpha}{z^{2} + 2 \\left(\\lambda \\mu - 1\\right) z - \\left(\\lambda \\mu - 1\\right) \\left(\\alpha l \\lambda \\mu - \\lambda \\mu + 1\\right)}"
836836
},
837837
{
838838
"id": "unified_diging",
@@ -858,14 +858,14 @@
858858
"l",
859859
"mu"
860860
],
861-
"transferFunction": "(-alpha*z + alpha)/(-alpha*l*lam*mu + alpha*l*mu + lam**2*mu**2 - 2*lam*mu**2 - 2*lam*mu*z + 2*lam*mu + mu**2 + 2*mu*z - 2*mu + z**2 - 2*z + 1)",
861+
"transferFunction": "(-alpha*z + alpha)/(alpha*l*lam*mu + lam**2*mu**2 + 2*lam*mu*z - 2*lam*mu + z**2 - 2*z + 1)",
862862
"tfIsMatrix": false,
863863
"equivalences": {
864864
"oracle": [],
865865
"shift": [],
866866
"lft": []
867867
},
868868
"catalogOnly": false,
869-
"tf_latex": "\\frac{- \\alpha z + \\alpha}{z^{2} - 2 \\left(\\lambda \\mu - \\mu + 1\\right) z - \\alpha l \\lambda \\mu + \\alpha l \\mu + \\lambda^{2} \\mu^{2} - 2 \\lambda \\mu^{2} + 2 \\lambda \\mu + \\mu^{2} - 2 \\mu + 1}"
869+
"tf_latex": "\\frac{- \\alpha z + \\alpha}{z^{2} + 2 \\left(\\lambda \\mu - 1\\right) z + \\alpha l \\lambda \\mu + \\lambda^{2} \\mu^{2} - 2 \\lambda \\mu + 1}"
870870
}
871871
]

webapp/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ <h3>Supported Oracles</h3>
130130
<tr><td><code>prox_f(x)</code>, <code>prox_g(x)</code></td><td>Proximal operator</td></tr>
131131
<tr><td><code>prox_fstar(x)</code>, <code>prox_gstar(x)</code></td><td>Proximal operator of the conjugate</td></tr>
132132
<tr><td><code>subgrad_f(x)</code></td><td>Subdifferential</td></tr>
133+
<tr><td><code>L</code></td><td>Graph Laplacian (linear oracle, eigenvalue &lambda;)</td></tr>
134+
<tr><td><code>W</code></td><td>Mixing matrix (linear oracle, W = I &minus; L)</td></tr>
133135
</tbody>
134136
</table>
135137

webapp/js/katex-helpers.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function oracleToLatex(name) {
2121

2222
/**
2323
* Build the composition LaTeX: [matrix] \diamond \begin{bmatrix} oracles \end{bmatrix}
24-
* For distributed algorithms, appends: Linear oracle: W (eigenvalue λ)
24+
* For distributed algorithms, appends: Linear oracle: L (eigenvalue λ)
2525
* @param {string} tfLatex - LaTeX for the transfer function matrix
2626
* @param {string[]} oracles - oracle name strings, e.g. ["prox_f", "prox_g"]
2727
* @param {boolean} [distributed] - whether this is a distributed algorithm
@@ -37,7 +37,7 @@ function compositionLatex(tfLatex, oracles, distributed) {
3737
}
3838

3939
/**
40-
* Render a "Linear oracle: W (eigenvalue λ)" line as a separate KaTeX element.
40+
* Render a "Linear oracle: L (eigenvalue λ)" line as a separate KaTeX element.
4141
* @returns {HTMLElement|null} A div with the rendered line, or null if not distributed.
4242
*/
4343
function linearOracleElement(distributed) {
@@ -46,11 +46,11 @@ function linearOracleElement(distributed) {
4646
div.style.cssText = 'margin-top:0.3rem;font-size:0.85rem;color:#0d47a1;';
4747
try {
4848
katex.render(
49-
'\\text{Linear oracle: } W \\text{ (eigenvalue } \\lambda \\text{)}',
49+
'\\text{Linear oracle: } L \\text{ (eigenvalue } \\lambda \\text{)}',
5050
div, { throwOnError: false }
5151
);
5252
} catch (e) {
53-
div.textContent = 'Linear oracle: W (eigenvalue λ)';
53+
div.textContent = 'Linear oracle: L (eigenvalue λ)';
5454
}
5555
return div;
5656
}

webapp/python/library.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,32 +140,32 @@ def check_all_equivalences(H_user, user_oracles, library, z_var,
140140
# Determine universal params for this comparison.
141141
# Both distributed: lambda is universal (must match for all values).
142142
# Neither distributed: no universal params.
143-
# Cross-category: try lambda=1 substitution (fully connected graph).
143+
# Cross-category: try lambda=0 substitution (trivial one-node graph).
144144
if user_distributed and lib_distributed:
145145
universal_params = user_universal_set | set(algo.get('universal_params', []))
146146
elif not user_distributed and not lib_distributed:
147147
universal_params = set()
148148
else:
149-
# Cross-category: substitute lambda=1 in the distributed TF
149+
# Cross-category: substitute lambda=0 in the distributed TF
150150
lam_sym = PARAMS['lam']
151151
if lib_distributed:
152-
H_lib_cross = H_lib.applyfunc(lambda e: _cancel(e.subs(lam_sym, 1)))
152+
H_lib_cross = H_lib.applyfunc(lambda e: _cancel(e.subs(lam_sym, 0)))
153153
else:
154154
H_lib_cross = H_lib
155155
if user_distributed:
156-
H_user_cross = H_user.applyfunc(lambda e: _cancel(e.subs(lam_sym, 1)))
156+
H_user_cross = H_user.applyfunc(lambda e: _cancel(e.subs(lam_sym, 0)))
157157
else:
158158
H_user_cross = H_user
159-
# Try oracle equivalence with lambda=1 substitution
159+
# Try oracle equivalence with lambda=0 substitution
160160
if sorted(user_oracles) == sorted(lib_oracles):
161161
result = check_oracle_equivalence(
162162
H_user_cross, H_lib_cross, z_var,
163163
lib_params=algo.get('param_symbols')
164164
)
165165
if result['match']:
166166
result['condition_note'] = (
167-
'\\text{Equivalent when } \\lambda=1 '
168-
'\\text{ (fully connected graph)}')
167+
'\\text{Equivalent when } \\lambda=0 '
168+
'\\text{ (trivial one-node graph)}')
169169
matches.append({
170170
'algorithm': algo,
171171
'type': 'oracle',

webapp/python/parser.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ def parse_equations(equations):
135135
# for correct LaTeX rendering, consistent with library.py).
136136
equations = [re.sub(r'\blambda\b', 'lam', eq) for eq in equations]
137137

138-
# Detect linear oracles W (mixing matrix) and L (graph Laplacian).
139-
# W has eigenvalue lambda; L has eigenvalue 1-lambda (since W = I - L
138+
# Detect linear oracles L (graph Laplacian) and W (mixing matrix).
139+
# L has eigenvalue lambda; W has eigenvalue 1-lambda (since W = I - L
140140
# in the simplest case, or W = I - mu*L with mu as a free parameter).
141141
# After rewriting, lam flows through the z-domain pipeline normally
142142
# but is marked as a universal parameter (must match for ALL lambda).
@@ -146,12 +146,12 @@ def parse_equations(equations):
146146
has_L = any(re.search(r'\bL\b', eq) for eq in equations)
147147
has_mixing_matrix = has_W or has_L
148148
if has_mixing_matrix:
149-
# Replace W -> lam, L -> (1-lam), I -> 1
150-
# Order matters: do L before I to avoid I in (1-lam) being replaced
151-
if has_L:
152-
equations = [re.sub(r'\bL\b', '(1-lam)', eq) for eq in equations]
149+
# Replace L -> lam, W -> (1-lam), I -> 1
150+
# Order matters: do W before I to avoid I in (1-lam) being replaced
153151
if has_W:
154-
equations = [re.sub(r'\bW\b', 'lam', eq) for eq in equations]
152+
equations = [re.sub(r'\bW\b', '(1-lam)', eq) for eq in equations]
153+
if has_L:
154+
equations = [re.sub(r'\bL\b', 'lam', eq) for eq in equations]
155155
equations = [re.sub(r'\bI\b', '1', eq) for eq in equations]
156156

157157
# Pre-process: merge shifted oracle calls into single oracles

0 commit comments

Comments
 (0)