00001
00006 #include "EnergyMinimization.h"
00007 #include "CirclePattern.h"
00008 #ifdef _WIN32
00009 #ifndef MSKDLL
00010 #define MSKDLL
00011 #endif
00012 #endif
00013 #include "mosek.h"
00014 #include "util.h"
00015 #include <fstream>
00016 #include <iomanip>
00017
00018 using namespace std;
00019
00020
00024 static int MSKAPI nlspar(void *nlhandle, int *numgrdobjnz, int *grdobjsub, int i,
00025 int *convali, int *grdconinz, int *grdconisub, int yo,
00026 int numycnz, int ycsub[], int maxnumhesnz,
00027 int *numhesnz, int *hessubi, int *hessubj)
00028 {
00029
00030 Mesh * mesh = (Mesh *)nlhandle;
00031 Mesh::HalfEdgeIterator hIter = mesh->halfEdgeIterator();
00032 int NumInteriorEdges = mesh->numEdges() - mesh->numBoundary();
00033
00034 if ( numgrdobjnz ) {
00036 numgrdobjnz[0] = mesh->numFaces();
00037
00038 if ( grdobjsub ) {
00040 for (int i = 0; i < mesh->numFaces(); i++)
00041 grdobjsub[i] = i;
00042 }
00043 }
00044
00045 if ( convali )
00046 convali[0] = 0;
00047
00048 if ( grdconinz )
00049 grdconinz[0] = 0;
00050
00051 if ( numhesnz ) {
00052 if (yo)
00053 numhesnz[0] = NumInteriorEdges + mesh->numFaces();
00054 else
00055 numhesnz[0] = 0;
00056 }
00057
00058 if ( maxnumhesnz ) {
00059 check_error (maxnumhesnz < (NumInteriorEdges + mesh->numFaces()), "Not enough space was allocated for hessian.");
00060 if (yo) {
00061 if (hessubi && hessubj)
00062 CirclePattern::buildSparsityForHessian(mesh, hessubi, hessubj);
00063 }
00064 }
00065 return ( MSK_RES_OK );
00066 }
00067
00068
00071 static int MSKAPI nleval(void *nlhandle, double *xx, double yo, double *yc,
00072 double *objval, int *numgrdobjnz, int *grdobjsub,
00073 double *grdobjval, int numi, int *subi, double *conval,
00074 int *grdconptrb, int *grdconptre, int *grdconsub,
00075 double *grdconval, double *grdlag, int maxnumhesnz,
00076 int *numhesnz, int *hessubi, int *hessubj,
00077 double *hesval)
00078 {
00079 Mesh * mesh = (Mesh *)nlhandle;
00080 int NumInteriorEdges = mesh->numEdges() - mesh->numBoundary();
00081
00082 if ( objval) {
00083 objval[0] = CirclePattern::evaluateEnergy(mesh, xx);
00084 }
00085 if ( numgrdobjnz ) {
00086 numgrdobjnz[0] = mesh->numFaces();
00087 for (int k = 0; k < mesh->numFaces(); k++)
00088 grdobjsub[k] = k;
00089 CirclePattern::computeGradient(mesh, xx, grdobjval);
00090 }
00091 if ( conval )
00092 for(int k=0; k<numi; ++k)
00093 conval[k] = 0.0;
00094
00095 if ( grdlag )
00096 CirclePattern::computeGradient(mesh, xx, grdlag);
00097
00098 if ( maxnumhesnz ) {
00099 if ( yo==0.0 )
00100 numhesnz[0] = 0;
00101 else {
00103 check_error (maxnumhesnz < (NumInteriorEdges + mesh->numFaces()),
00104 "Not enough space was allocated for hessian.");
00105 numhesnz[0] = NumInteriorEdges + mesh->numFaces();
00106
00107 if ( hessubi && hessubj && hesval ) {
00108 CirclePattern::buildSparsityForHessian(mesh, hessubi, hessubj);
00109 CirclePattern::computeHessian(mesh, xx, hesval);
00110 }
00111 }
00112 }
00113 return ( MSK_RES_OK );
00114 }
00115
00116 EnergyMinimization::EnergyMinimization(Mesh * _mesh, const MSKenv_t & env) {
00117 mesh = _mesh;
00118
00119 NUMVAR = mesh->numFaces();
00120 NUMCON = 1;
00121 NUMANZ = NUMVAR;
00122
00124 int r = MSK_RES_OK;
00125 r = MSK_maketask(env, NUMCON, NUMVAR, &task);
00126 check_error (r != MSK_RES_OK, "Cannot make MOSEK task for radii energy minimization.");
00127 r = MSK_linkfiletotaskstream(task, MSK_STREAM_LOG, "_RadiiMinMosekOut.txt", 0);
00128 check_error (r != MSK_RES_OK, "Cannot link MOSEK \"_RadiiMinMosekOut.txt\" output file.");
00129 }
00130
00131 void EnergyMinimization::doSolve() {
00132 allocateMosekArrays();
00133 setDataStructres();
00134 minimize();
00135 }
00136
00137 void EnergyMinimization::setDataStructres() {
00145 bkc[0] = MSK_BK_FX;
00146 blc[0] = 0.0;
00147 buc[0] = 0.0;
00148
00151 for (int i = 0; i < NUMVAR; i++){
00152 c[i] = 1.0;
00153 ptrb[i] = i; ptre[i] = i+1;
00154 sub[i] = 0; val[i] = 1.0;
00155
00156 bkx[i] = MSK_BK_FR;
00157 blx[i] = -MSK_INFINITY;
00158 bux[i] = MSK_INFINITY;
00159 }
00160 }
00161
00162 void EnergyMinimization::minimize() {
00163 int r = MSK_RES_OK;
00164
00166 r = MSK_inputdata(task, NUMCON, NUMVAR, NUMCON, NUMVAR, c, 0.0, ptrb, ptre, sub, val, bkc, blc, buc, bkx, blx, bux);
00167 check_error ( r != MSK_RES_OK,
00168 "Could not input constraints for radii minimization.\n Check \"RadiiMinMosekOut.txt\" for output." );
00169
00171 r = MSK_putnlfunc(task, mesh, nlspar, nleval);
00172 check_error ( r != MSK_RES_OK,
00173 "Could not input nonlinear function for radii minimization.\n Check \"RadiiMinMosekOut.txt\" for output." );
00174
00176 r = MSK_optimize(task);
00177 check_error ( r != MSK_RES_OK,
00178 "Could not solve for radii minimization.\n Check \"RadiiMinMosekOut.txt\" for output." );
00179
00180 r = MSK_getsolutionslice(task, MSK_SOL_ITR, MSK_SOL_ITEM_XX, 0, NUMVAR, xx);
00181 check_error ( r != MSK_RES_OK, "Could not get radii solution.\n Check \"RadiiMinMosekOut.txt\" for output." );
00182
00183 MSK_solutionsummary(task, MSK_STREAM_ERR);
00184
00186 Mesh::FaceIterator fIter = mesh->faceIterator();
00187 for (int i = 0; !fIter.end(); fIter++) {
00188 fIter.face()->r = exp(xx[i++]);
00189 }
00190 }
00191
00192 void EnergyMinimization::allocateMosekArrays() {
00193 bkc = new int[NUMCON];
00194 bkx = new int[NUMVAR];
00195 ptrb = new int[NUMVAR];
00196 ptre = new int[NUMVAR];
00197 sub = new int[NUMANZ];
00198 blc = new double[NUMCON];
00199 buc = new double[NUMCON];
00200 c = new double[NUMVAR];
00201 blx = new double[NUMVAR];
00202 bux = new double[NUMVAR];
00203 val = new double[NUMANZ];
00204 xx = new double[NUMVAR];
00205 }
00206
00207 void EnergyMinimization::clearMosekArrays() {
00208 if (task) {
00209
00210 delete [] bkc;
00211 delete [] bkx;
00212 delete [] ptrb;
00213 delete [] ptre;
00214 delete [] sub;
00215 delete [] blc;
00216 delete [] buc;
00217 delete [] c;
00218 delete [] blx;
00219 delete [] bux;
00220 delete [] val;
00221 MSK_deletetask(&task);
00222 task = NULL;
00223 }
00224 }
00225