# [makes] CIA.mat## [rule] copymat# Solve a small MINLP problem with a CIA (Combinatorial Integral Approximation)# heuristic. System: x^+ = RK4(x, u, Delta) with f(x,u) = x^3 - u.importnumpyasnpfromscipy.optimizeimportminimize,milp,LinearConstraint,Boundsfromscipy.ioimportsavemat# Problem parameters.xref=0.7Delta=0.05x0=0.9Ncontroller=30time=Delta*np.arange(Ncontroller)defrk4_step(x,u,h):"""One step of RK4 for dx/dt = x^3 - u."""f=lambdaxv:xv**3-uk1=f(x)k2=f(x+h/2*k1)k3=f(x+h/2*k2)k4=f(x+h*k3)returnx+h/6*(k1+2*k2+2*k3+k4)defsimulate(u,x_init):"""Simulate N steps, return state trajectory (N+1,)."""x=np.empty(len(u)+1)x[0]=x_initforkinrange(len(u)):x[k+1]=rk4_step(x[k],u[k],Delta)returnx# ── NLP: relax u to [0,1] and solve as a multiple-shooting problem ───────────# Variables: z = [u_0,...,u_{N-1}, x_1,...,x_N] (length 2*N)# Constraints: x_{k+1} - rk4_step(x_k, u_k, Delta) = 0 (N equalities)Nu=NcontrollerNz=2*Nudefunpack(z):returnz[:Nu],z[Nu:]# u (Nu,), x (Nu,) representing x_1..x_Ndefnlp_obj_ms(z):u,x=unpack(z)x_full=np.concatenate(([x0],x))# x_0..x_Nreturnfloat(np.sum((x_full-xref)**2))defnlp_defect(z):u,x=unpack(z)x_prev=np.concatenate(([x0],x[:-1]))# x_k for k=0..N-1returnx-np.array([rk4_step(xp,uk,Delta)forxp,ukinzip(x_prev,u)])u_init_ms=np.ones(Nu)x_init_ms=simulate(u_init_ms,x0)[1:]# trajectory from constant u=1z_init=np.concatenate([u_init_ms,x_init_ms])bounds_ms=[(0.0,1.0)]*Nu+[(None,None)]*Nunlp_res=minimize(nlp_obj_ms,z_init,method='SLSQP',bounds=bounds_ms,constraints={'type':'eq','fun':nlp_defect},options={'ftol':1e-12,'maxiter':500})unlp=nlp_res.x[:Nu]xnlp=simulate(unlp,x0)Vnlp=nlp_res.fun# ── MILP: CIA heuristic ───────────────────────────────────────────────────────Nc=NcontrollerA_lower=np.tril(np.ones((Nc,Nc)))# cumulative-sum matrixC_vec=np.ones(Nc)# B encodes switching constraints (from MATLAB code).B=np.zeros((Nc,Nc))foriinrange(Nc-2):B[i:i+3,i]=[-1,1,-1]B[Nc-2:Nc,Nc-2]=[-1,1]B[Nc-1,Nc-1]=-1# Variables: x = [eta, u_0, ..., u_{Nc-1}]# Minimise eta.c_obj=np.zeros(Nc+1)c_obj[0]=1.0# Constraints (all of the form lb <= A*x <= ub):# [-1, A_lower] * [eta;u] <= A_lower @ unlp (A*(u-unlp) <= eta)# [-1,-A_lower] * [eta;u] <= -A_lower @ unlp (A*(unlp-u) <= eta)# [0, B ] * [eta;u] <= 0 (B*u <= 0)A_con=np.zeros((3*Nc,Nc+1))A_con[:Nc,0]=-1.0;A_con[:Nc,1:]=A_lowerA_con[Nc:2*Nc,0]=-1.0;A_con[Nc:2*Nc,1:]=-A_lowerA_con[2*Nc:,1:]=Bb_ub=np.concatenate([A_lower@unlp,-(A_lower@unlp),np.zeros(Nc)])milp_bounds=Bounds(lb=np.concatenate([[-np.inf],np.zeros(Nc)]),ub=np.concatenate([[np.inf],np.ones(Nc)]),)integrality=np.zeros(Nc+1)integrality[1:]=1# u is binarymilp_res=milp(c_obj,constraints=LinearConstraint(A_con,-np.inf,b_ub),integrality=integrality,bounds=milp_bounds)maxcianorm=milp_res.x[0]umilp=milp_res.x[1:]# Simulate with binary control.xopt=simulate(umilp,x0)savemat('CIA.mat',{'xref':xref,'time':time,'xnlp':xnlp,'unlp':unlp,'xopt':xopt,'umilp':umilp,})