"""Exact minimizers for identity-design squared loss plus L1/L2; no general solver."""
from fractions import Fraction as F
from itertools import product
import json
Y=[F(3),F(1,2)]
def objective(w,l1,l2):
    loss=sum((a-b)**2 for a,b in zip(w,Y))/2
    p1=l1*sum(abs(a) for a in w);p2=l2*sum(a*a for a in w)/2
    return loss,p1,p2,loss+p1+p2
def fit(l1,l2):
    if l1<0 or l2<0:raise ValueError('nonnegative penalties')
    return [(1 if y>=0 else -1)*max(abs(y)-l1,F(0))/(1+l2) for y in Y]
def check_kkt(w,l1,l2):
    for a,y in zip(w,Y):
        smooth=(a-y)+l2*a
        if a:assert smooth+l1*(1 if a>0 else -1)==0
        else:assert abs(smooth)<=l1
def demo():
    cases=[('OLS',F(0),F(0)),('L2',F(0),F(1)),('L1',F(1),F(0)),('mixed',F(1,2),F(1,2))];out=[];checked=0
    grid=[F(i,4) for i in range(-16,17)]
    for name,l1,l2 in cases:
        w=fit(l1,l2);check_kkt(w,l1,l2);parts=objective(w,l1,l2)
        for trial in product(grid,repeat=2):assert objective(trial,l1,l2)[-1]>=parts[-1];checked+=1
        out.append({'name':name,'lambda1':str(l1),'lambda2':str(l2),'minimizing_weights':[str(x) for x in w],'half_SSE':str(parts[0]),'L1_penalty':str(parts[1]),'half_L2_penalty':str(parts[2]),'objective':str(parts[3])})
    assert [x['minimizing_weights'] for x in out]==[['3','1/2'],['3/2','1/4'],['2','0'],['5/3','0']]
    return {'X':[[1,0],[0,1]],'y':[str(y) for y in Y],'intercept':False,'objective_scale':'half SSE, not mean','cases':out,'KKT_checked':True,'bounded_grid_comparisons':checked,'general_design_solver':False,'best_generalizing_method_selected':False}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=False,indent=2))
