123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175(*
* OSDP (OCaml SDP) is an OCaml frontend library to semi-definite
* programming (SDP) solvers.
* Copyright (C) 2012, 2014 P. Roux and P.L. Garoche
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)moduletypeS=sigmoduleCoeff:Scalar.Stypetvalof_list:(Ident.t*Coeff.t)list->Coeff.t->tvalto_list:t->(Ident.t*Coeff.t)list*Coeff.tvalvar:Ident.t->tvalconst:Coeff.t->tvalmult_scalar:Coeff.t->t->tvaladd:t->t->tvalsub:t->t->tvalreplace:t->(Ident.t*t)list->tvalremove:t->Ident.t->tvalcompare:t->t->intvalis_var:t->(Ident.t*Coeff.t)optionvalis_const:t->Coeff.toptionvalchoose:t->(Ident.t*Coeff.t)optionvalpp:Format.formatter->t->unitendmoduleMake(SC:Scalar.S):SwithmoduleCoeff=SC=structmoduleCoeff=SCmoduleIM=Ident.Map(* type invariant: lin is sorted by Ident.compare
* and doesn't contain any zero coefficient *)typet={const:Coeff.t;lin:Coeff.tIM.t}letof_listlc=letl=List.filter(fun(_,s)->Coeff.(s<>zero))linletm=List.fold_left(funacc(id,c)->letc=tryCoeff.(c+IM.findidacc)withNot_found->cinIM.addidcacc)IM.emptylin{const=c;lin=m}letto_lista=IM.bindingsa.lin,a.constletvarid={const=Coeff.zero;lin=IM.singletonidCoeff.one}letconstc={const=c;lin=IM.empty}letmult_scalarsa=ifCoeff.(s=zero)thenconstCoeff.zeroelse{const=Coeff.(s*a.const);lin=IM.map(func->Coeff.(s*c))a.lin}letmap2fm1m2=letopts=ifCoeff.(s<>zero)thenSomeselseNoneinIM.merge(fun_c1c2->matchc1,c2with|None,None->None|Somec1,None->opt(fc1Coeff.zero)|None,Somec2->opt(fCoeff.zeroc2)|Somec1,Somec2->opt(fc1c2))m1m2letmap2fa1a2={const=fa1.consta2.const;lin=map2fa1.lina2.lin}letadd=map2Coeff.addletsub=map2Coeff.subletreplacelll=letm,ll=List.fold_left(fun(m,ll)(id,l')->tryletc=IM.findidminIM.removeidm,(c,l')::llwithNot_found->m,ll)(l.lin,[])llinList.fold_left(funl(c,l')->letm=IM.fold(funidc'm->letc=tryCoeff.(IM.findidm+c*c')withNot_found->Coeff.(c*c')inifCoeff.(c<>zero)thenIM.addidcmelseIM.removeidm)l'.linl.linin{const=Coeff.(l.const+c*l'.const);lin=m}){const=l.const;lin=m}llletremoveli={const=l.const;lin=IM.removeil.lin}letcomparea1a2=letc=Coeff.comparea1.consta2.constinifc<>0thencelseIM.compareCoeff.comparea1.lina2.linletis_vara=ifCoeff.(equala.constzero)thenmatchIM.bindingsa.linwith|[id_c]->Someid_c|_->NoneelseNoneletis_consta=ifIM.is_emptya.linthenSomea.constelseNoneletchoosel=trySome(IM.choosel.lin)withNot_found->Noneletppfmta=letpp_coefffmt(x,a)=ifCoeff.(a=one)thenFormat.fprintffmt"%a"Ident.ppxelseifCoeff.(a=minus_one)thenFormat.fprintffmt"-%a"Ident.ppxelseFormat.fprintffmt"%a %a"Coeff.ppaIdent.ppxinifis_consta<>NonethenFormat.fprintffmt"%a"Coeff.ppa.constelseifCoeff.(a.const=zero)thenFormat.fprintffmt"@[%a@]"(Utils.pp_list~sep:"@ + "pp_coeff)(IM.bindingsa.lin)elseFormat.fprintffmt"@[%a@ + %a@]"(Utils.pp_list~sep:"@ + "pp_coeff)(IM.bindingsa.lin)Coeff.ppa.constendmoduleQ=Make(Scalar.Q)moduleFloat=Make(Scalar.Float)exceptionNot_linearmoduleMakeScalar(L:S):Scalar.Swithtypet=L.t=Scalar.Make(structtypet=L.tletcompare=L.compareletzero=L.constL.Coeff.zeroletone=L.constL.Coeff.oneletof_floatf=L.const(L.Coeff.of_floatf)letto_float_=assertfalse(* should never happen *)letof_qx=L.const(L.Coeff.of_qx)letto_q_=assertfalse(* should never happen *)letadd=L.addletsub=L.subletmulte1e2=matchL.is_conste1,L.is_conste2with|None,None->raiseNot_linear|Somes,_->L.mult_scalarse2|None,Somes->L.mult_scalarse1letdiv__=assertfalse(* should never happen *)letppfmta=letlin,const=L.to_listainletl,l'=(ifL.Coeff.(const=zero)then0else1),List.lengthlininifl+l'<=1thenFormat.fprintffmt"%a"L.ppaelseFormat.fprintffmt"(%a)"L.ppaend)