$ontext ================================================================== LAST MODIFIED: 07 February, 2005 FILENAME: restime.gms PURPOSE: Creates two tables of comparative solve resource times of two solvers. One table considers those models where an optimal solution has been found and the other considers all models in the trace files. Both tables output model resource times. For the first table, optimal is defined as modelstat=1 or 2, solvestat=1. For the second, if one solver found a solution, but the other did not, the first solver is considered infinitely faster. If both failed to find a solution, then the resource times are considered the same. Also, each resource time category (same, faster, much faster, etc. is subdivided into subcategories, comparing objective function values. Output is in .txt or in .html files. Also lists models for each resource time category. Works for all modeltypes. REQUIRED INPUTS: --trace1: GAMS trace file of solver 1 (or) --ntrace1: GENERIC data file 1 --trace2: GAMS trace file of solver 2 (or) --ntrace2: GENERIC data file 2 Users cannot input two tracefile numbers of different type with the same (n)trace number, i.e. --trace1=... --ntrace1 is not allowed, only --trace1=... --ntrace2=... OPTIONAL INPUTS: --bnd: real. Bound for optimal outcome. Outcome is optimal if both solvers scaled solutions are within bnd of eachother. (default: 1e-5) --modelfile: modelfile containing models to be considered in comparison --objmin: minimum obj. threshhold. If both solvers report an obj. less than the threshhold, the objdiff is computed as absolute difference, otherwise use relative difference (default 0.1). --outfile: root filename of restimes output file (default is out --> out_resA.txt, out_resB.txt, out_resA.htm, out_resB.htm) --resmin: minimum resource time threshold. If both solvers report a resource time below --resmin, then no ratio is reported. In this case, both solver times are considered the same (default 0.05). --tsame: bound in % for solver res. times to be considered same (default 10%) --tfaster: bound in % for solver res. times to be considered much faster (default 50%) REMARKS: Each tracefile can contain information from only one (1) solver for a given set of models. For example, tracefiles containing solver A and solver B will cause error message upon compilation. Users cannot input two tracefile numbers of different type with the same (n)trace number, i.e. --trace1=... --ntrace1 is not allowed, only --trace1=... --ntrace2=... SAMPLE OUTPUT: Solvers used : A, B Solver A much faster : 1 Solver B faster : 28 Solvers perform the same : 31 Solver A faster : 184 Solver B much faster : 40 Total models solved optimally : 284 $offtext ================================================================= *=== Create trace reading routine (readtrace.gms) $onecho > %gams.scrdir%readtrace.gms $eolcom ,# display '++++ TRACEOPT=3'; Set modelname, modeltype, solvername, nlpdef, mipdef; Set col /julian, direction,eqnum,varnum,dvarnum,nz,nlnz, optfile,modelstat,solvestat,obj,objest,res,iter,dom,nodes/ Alias(u1,u2,u3,u4,u5,*); Set domain(*,*,*,*,*); Table tracedata(*,*,*,*,*,col) $ondelim modelname, modeltype, solvername, nlpdef, mipdef, julian, direction,eqnum,varnum,dvarnum,nz,nlnz, optfile,modelstat,solvestat,obj,objest,res,iter,dom,nodes $offlisting $include %tracefile% $onlisting $offdelim ; domain(u1,u2,u3,u4,u5)$sum( col, tracedata(u1,u2,u3,u4,u5,col)) = yes; loop(domain(u1,u2,u3,u4,u5), modelname(u1) = yes; modeltype(u2) = yes; solvername(u3) = yes; nlpdef(u4) = yes; mipdef(u5) = yes; ); *execute 'rm -f tracedata' $offecho *=== Convert non-GAMS data files to GAMS trace files $onecho > %gams.scrdir%tconvawk {print $1 "," $2 "," $3 ",none,none,-1", $4, "-1,-1,-1,-1,-1,-1," $5 "," $6 "," $7 ",-1," $8 "," $9 ",-1,-1,#"} $offecho $if set ntrace1 $call 'awk -F, -f "%gams.scrdir%tconvawk" %ntrace1% > %gams.scrdir%C_%ntrace1%' $if set ntrace1 $set trace1 %ntrace1% $if set ntrace2 $call 'awk -F, -f "%gams.scrdir%tconvawk" %ntrace2% > %gams.scrdir%C_%ntrace2%' $if set ntrace2 $set trace2 %ntrace2% *=== Error checks $if not set trace1 $goto errors_notrace1 $if not set trace2 $goto errors_notrace2 $if not exist %trace1% $goto errors_trace1notexist $if not exist %trace2% $goto errors_trace2notexist *=== Set defaults $if not set bnd $set bnd 1e-5 $if not set objmin $set objmin 1e-1 $if not set outfile $set outfile out $if not set minobj $set minobj 1e-1 $if not set modelfile $goto nomodelfile *=== If only the subset of models as listed in "modelfile" is to be *=== analyzed Set m(*) the subset of models to consider / $onempty $include %modelfile% $offempty /; $echo > %gams.scrdir%tracedata $if not set ntrace1 $echo '$include %trace1%' >> %gams.scrdir%tracedata $if not set ntrace2 $echo '$include %trace2%' >> %gams.scrdir%tracedata $if set ntrace1 $echo '$include %gams.scrdir%C_%ntrace1%' >> %gams.scrdir%tracedata $if set ntrace2 $echo '$include %gams.scrdir%C_%ntrace2%' >> %gams.scrdir%tracedata $set tracefile %gams.scrdir%tracedata $include %gams.scrdir%readtrace $goto donemodelfile *=== All models in trace files are to be analyzed $label nomodelfile $echo > %gams.scrdir%tracedata $if not set ntrace1 $echo '$include %trace1%' >> %gams.scrdir%tracedata $if not set ntrace2 $echo '$include %trace2%' >> %gams.scrdir%tracedata $if set ntrace1 $echo '$include %gams.scrdir%C_%ntrace1%' >> %gams.scrdir%tracedata $if set ntrace2 $echo '$include %gams.scrdir%C_%ntrace2%' >> %gams.scrdir%tracedata $set tracefile %gams.scrdir%tracedata $include %gams.scrdir%readtrace Set m(*); m(modelname) = yes; $label donemodelfile *=== Set default options $if not set resmin $set resmin 5e-2 $if not set tsame $set tsame 10 $if not set tfaster $set tfaster 50 *=== Possible solver outcomes Set all_results /opt "globally optimal", feas "locally optimal/feasible", infeas "infeasible", unbnd "unbounded", f "fail" nd "no data" /; Set result_cont(all_results) "possible results for cont. models" result_disc (all_results) "possible results for discrete models" ; result_cont(all_results) = yes; result_disc(all_results) = yes; Parameter is_discrete/0/; Set discrete_mods / MIP, MINLP/; loop(modeltype, is_discrete = sum(discrete_mods, sameas(modeltype, discrete_mods)); ); Set result(*), resultA(*), resultB(*); if(is_discrete, result(result_disc) = yes; resultA(result_disc) = yes; resultB(result_disc) = yes; else result(result_cont) = yes; resultA(result_cont) = yes; resultB(result_cont) = yes; ); Parameter solvernum /0/ nummodels /0/ ratio /0/; Alias(solvers,solvername) Parameter square(*,*,*) GAMS solver results; square(modelname,solvername,result) = 0; *=== Determine solvers in tracefiles Set solverA, solverB; Parameter i /1/; loop(solvername, if(i eq 1, solverA(solvername) = solvername(solvername); elseif(i eq 2), solverB(solvername) = solvername(solvername); ); i = 2; ); *=== Compute totals Parameter scale(*) "this is the scaling factor" optimal(*) "this is 1 if optimal solution found" error(*) "relative error between solutions of A and B" ; Parameter bound "relative objc func difference threshold" / %bnd% / resourcemin "min resource time threshold for ratio" / %resmin%/ ; *=== Determine scale loop((modelname,modeltype,nlpdef,mipdef), scale(modelname) = max(smax(solvername, abs(tracedata(modelname,modeltype, solvername,nlpdef,mipdef,"obj"))), 1e-4); ); *=== Determine error loop((modelname,modeltype,nlpdef,mipdef), error(modelname) = abs( sum(solverA, tracedata(modelname,modeltype,solverA,nlpdef,mipdef,"obj")) - sum(solverB, tracedata(modelname,modeltype,solverB,nlpdef,mipdef,"obj")) ) / scale(modelname); ); Parameter modstat /0/; Parameter solstat /0/; *=== Compute result totals loop( (modelname(m),modeltype,solvername,nlpdef,mipdef), i = i+1; modstat = tracedata(modelname,modeltype,solvername,nlpdef,mipdef,'modelstat'); solstat = tracedata(modelname,modeltype,solvername,nlpdef,mipdef,'solvestat'); *=== Assign DISCRETE model square only if data exists if(is_discrete, if (modstat and solstat, if( (modstat=1 or modstat=15) and solstat=1, square(modelname,solvername,"opt") = yes; elseif( (modstat=2 or modstat=8 or modstat=16) and (solstat=1 or solstat=2 or solstat=3 or solstat=4 or solstat=5)), square(modelname,solvername,"feas") = yes; elseif( (modstat=4 or modstat=5 or modstat=10 or modstat=19)and solstat=1), square(modelname,solvername,"infeas") = yes; elseif( (modstat=3 or modstat=18) and solstat=1 ), square(modelname,solvername,"unbnd") = yes; else square(modelname,solvername,"f") = yes; ); ); *=== Assign CONTINUOUS model square only if data exists else if (modstat and solstat, if( (modstat=1 or modstat=15) and solstat=1, square(modelname,solvername,"opt") = yes; elseif( (modstat=2 or modstat=7 or modstat=16 or modstat=17) and (solstat=1 or solstat=2 or solstat=3 or solstat=4 or solstat=5)), square(modelname,solvername,"feas") = yes; elseif( (modstat=4 or modstat=5 or modstat=19) and solstat=1), square(modelname,solvername,"infeas") = yes; elseif( (modstat=3 or modstat=18) and solstat=1), square(modelname,solvername,"unbnd") = yes; else square(modelname,solvername,"f") = yes; ); ); ); ); *=== Assign square for model/solver with no trace data loop( (modelname,solvername), if(not sum[(modeltype,nlpdef,mipdef), tracedata(modelname,modeltype,solvername,nlpdef,mipdef,'modelstat')], square(modelname,solvername,"nd") = yes; ); ); *========================================================================= *=== Create HTML output: considers only models solved optimally *=== by both solvers *========================================================================= *=== Compute result total *=== Compute models which were solved succesfully by both solvers set bothsolve(*); bothsolve(modelname) = no; parameter tmpA, tmpB; loop(modelname, bothsolve(modelname) = yes$( ( sum(solverA, square(modelname,solverA,'opt')) or sum(solverA, square(modelname,solverA,'feas')) ) and ( sum(solverB,square(modelname,solverB,'opt')) or sum(solverB, square(modelname,solverB,'feas')) ) ); ); parameter numbothsolve; numbothsolve = card(bothsolve); display numbothsolve; Set restype /Aifaster "Solver A infinitely faster", Amfaster "Solver A much faster", Afaster "Solver A faster", same "Solvers perform same on optimally solved models", Bfaster "Solver B faster", Bmfaster "Solver B much faster", Bifaster "Solver B infinitely faster" ABnonopt "Both solvers failed to solve optimally" /; Set objtype / ObjAbet "Solver A has better solution" Objsame "Solvers both return optimal solution" ObjBbet "Solver B has better solution" /; Parameter res_same "times within tsame %" res_faster "times within tfaster %" ; res_same = 0.01*%tsame%; res_faster = 0.01*%tfaster%; *==== Extract resource times Parameter restimes(restype) "resource times by category", modelrestime(*,restype) "resource times by model and category", modelresobj(*,restype,objtype) "resource times", resdiff "difference in resource times", resA(*) "resource times for solver A", resB(*) "resource times for solver B", objA(*) "objective value using solver A", objB(*) "objective value using solver B", objdiff "difference in obj value", dir(*) "direction of optimization: 0=min 1=max" ; modelrestime(modelname,restype) = 0; restimes(restype) = 0; loop( (modelname,modeltype,solverA,nlpdef,mipdef)$m(modelname), modstat = tracedata(modelname,modeltype,solverA,nlpdef,mipdef,'modelstat'); solstat = tracedata(modelname,modeltype,solverA,nlpdef,mipdef,'solvestat'); if( modstat and solstat, resA(modelname) = tracedata(modelname,modeltype,solverA,nlpdef,mipdef,'res'); objA(modelname) = tracedata(modelname,modeltype,solverA,nlpdef,mipdef,'obj'); dir(modelname) = tracedata(modelname,modeltype,solverA,nlpdef,mipdef,'direction'); ); ); loop( (modelname,modeltype,solverB,nlpdef,mipdef)$m(modelname), modstat = tracedata(modelname,modeltype,solverB,nlpdef,mipdef,'modelstat'); solstat = tracedata(modelname,modeltype,solverB,nlpdef,mipdef,'solvestat'); if (modstat and solstat, resB(modelname) = tracedata(modelname,modeltype,solverB,nlpdef,mipdef,'res'); objB(modelname) = tracedata(modelname,modeltype,solverB,nlpdef,mipdef,'obj'); ); ); *=== objdiff is relative difference for min(obj)>= minobj, *=== otherwise use absolute diff. loop(modelname, if( max( abs(objA(modelname)), abs(objB(modelname)))> %minobj%, objdiff(modelname) = ( objA(modelname)-objB(modelname) ) / max( abs(objA(modelname)), abs(objB(modelname)), %minobj%); else objdiff(modelname) = ( objA(modelname)-objB(modelname) ); ); ); loop(bothsolve(modelname)$m(modelname), if( min(resA(modelname), resB(modelname)) < %resmin%, resdiff = resA(modelname) - resB(modelname); else resdiff = (resA(modelname) - resB(modelname)) / max(abs(resA(modelname)), abs(resB(modelname)), %bnd% ); ); *=== Solver B much faster if ( resdiff > res_faster, restimes("Bmfaster") = restimes("Bmfaster") + 1; modelrestime(modelname,"Bmfaster") = yes; ); *=== Solver B faster if ( (res_same < resdiff and resdiff <= res_faster), restimes("Bfaster") = restimes("Bfaster") + 1; modelrestime(modelname,"Bfaster") = yes; ); *=== Res times are the same if ( (-res_same < resdiff and resdiff <= res_same), restimes("same") = restimes("same") + 1; modelrestime(modelname,"same") = yes; ); *=== Solver A faster if ( (res_same < -resdiff and -resdiff <= res_faster), restimes("Afaster") = restimes("Afaster") + 1; modelrestime(modelname,"Afaster") = yes; ); *=== Solver A much faster if ( -resdiff > res_faster, restimes("Amfaster") = restimes("Amfaster") + 1; modelrestime(modelname,"Amfaster") = yes; ); ); *=== Disaggregate resource time categories by objective function *=== categories loop( (modelname,restype)$modelrestime(modelname,restype), * === Maximize objective function if (dir(modelname), if (objdiff(modelname) > bound, modelresobj(modelname,restype,"ObjAbet") = yes; elseif(-objdiff(modelname) > bound ), modelresobj(modelname,restype,"ObjBbet") = yes; else modelresobj(modelname,restype,"Objsame") = yes; ) * === Minimize objective function else if (-objdiff(modelname) > bound, modelresobj(modelname,restype,"ObjAbet") = yes; elseif(objdiff(modelname) > bound), modelresobj(modelname,restype,"ObjBbet") = yes; else modelresobj(modelname,restype,"Objsame") = yes; ) ); ); *========================================================================= *=== Create square: considers all models *========================================================================= *=== Compute models which were solved succesfully by one solver only set onesolve(*,*); onesolve(modelname,solvers) = no; loop(modelname$(not bothsolve(modelname) and m(modelname)), onesolve(modelname,solverA) = yes$( (square(modelname,solverA,'opt') or square(modelname,solverA,'feas')) and not sum(solverB, square(modelname,solverB,'opt') + square(modelname,solverB,'feas') ) ); onesolve(modelname,solverB) = yes$( (square(modelname,solverB,'opt') or square(modelname,solverB,'feas')) and not sum(solverA, square(modelname,solverA,'opt') + square(modelname,solverA,'feas') ) ); ); *=== Compute models which were not solved succesfully by any solver set nosolve(*); nosolve(modelname) = no; loop(m(modelname)$(not bothsolve(modelname) and not sum(solvers,onesolve(modelname,solvers))), nosolve(modelname) = yes; ); *=== Compute result total modelrestime(modelname,"Aifaster") = no; modelrestime(modelname,"Bifaster") = no; modelresobj(modelname,"Aifaster",objtype) = no; modelresobj(modelname,"Bifaster",objtype)=no; loop( onesolve(m(modelname),solvers), if(sum(solverA,onesolve(m,solverA)), restimes("Aifaster") = restimes("Aifaster") + 1; modelrestime(modelname,"Aifaster") = yes; modelresobj(modelname,"Aifaster","ObjAbet") = yes; elseif(sum(solverB,onesolve(m,solverB))), restimes("Bifaster") = restimes("Bifaster") + 1; modelrestime(modelname,"Bifaster") = yes; modelresobj(modelname,"Bifaster","ObjBbet") = yes; ); ); loop( nosolve(modelname), restimes("ABnonopt") = restimes("ABnonopt") + 1; modelrestime(modelname,"ABnonopt") = yes; modelresobj(modelname,"ABnonopt","Objsame") = yes; ); res_same = res_same*100; res_faster = res_faster*100; *=== *=== Create HTML file *=== file fresB_htm /%outfile%_res.htm/; put fresB_htm; put / '
| Date / Time: | ' / '%system.date% %system.time% | ' / '
| Tracefile 1 : | ' '%trace1% |
| Tracefile 2 : | ' '%trace2% |
| Solvers used : | '; solvernum = 0; loop(solvers, solvernum = solvernum+1; put$(solvernum eq 1) '' solvers.tl:0 ' |
| ' solvers.tl:0 ' | |
| Modeltype(s) | ' ''; loop(modeltype, put '   ' modeltype.tl:0 '' ); put ' |
| Threshold: Solver Faster | ' / '%tsame%% | ' / '
| Threshold: Solver Much Faster | ' / '%tfaster%% | ' / '
| Threshold: Solver Infinitely Faster | ' / 'Other solver failed | ' / '
| Total | '; loop(objtype, if (sameas(objtype,"ObjAbet"), put / 'Obj '; loop(solverA, put solverA.tl:0); put ' better | '; elseif(sameas(objtype,"ObjBbet")), put / 'Obj '; loop(solverB, put solverB.tl:0); put ' better | '; else put / 'Obj same | '; ); ); put / '|
| Solver ' solvers.tl:0 ' infinitely faster : | ' if(restimes("Aifaster"), put '' restimes("Aifaster"):>6:0 ' | '; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"Aifaster",objtype) ); if (nummodels, put / '' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| Solver ' solvers.tl:0 ' much faster : | ' if(restimes("Amfaster"), put '' restimes("Amfaster"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"Amfaster",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| Solver ' solvers.tl:0 ' faster : | '; if(restimes("Afaster"), put '' restimes("Afaster"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"Afaster",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| Solvers perform the same':0 ' : | '; if(restimes("same"), put '' restimes("same"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"same",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| Solver ' solvers.tl:0 ' faster : | ' ''; if(restimes("Bfaster"), put '' restimes("Bfaster"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"Bfaster",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put '|
| Solver ' solvers.tl:0 ' much faster : | '; if(restimes("Bmfaster"), put '' restimes("Bmfaster"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"Bmfaster",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| Solver ' solvers.tl:0 ' infinitely faster : | '; if(restimes("Bifaster"), put '' restimes("Bifaster"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"Bifaster",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| Both solvers failed to solve ' 'optimally : | '; if(restimes("ABnonopt"), put '' restimes("ABnonopt"):>6:0 ''; else put '-'; ); loop(objtype, nummodels = sum(modelname, modelresobj(modelname,"ABnonopt",objtype) ); if (nummodels, put / ' | ' nummodels:0:0 ' | '; else put / '- | '; ); ); put / '|
| '; put 'Total models:':33 ' : | ' / '' sum(restype, restimes(restype)):>6:0 ' | '; loop(objtype, nummodels = sum((modelname,restype), modelresobj(modelname,restype,objtype)); put '' nummodels:0:0 ' | '; ); put / '
| Outcome | ' 'Model Status | ' 'Solver Status |
| globally optimal | 1 or 15 ' ' | 1 |
| locally optimal/feasible | 2 or 8 or 16 ' ' | 1 or 2 or 3 or 4 or 5 |
| Outcome | ' 'Model Status | ' 'Solver Status |
| globally optimal | 1 or 15' ' | 1 |
| locally optimal/feasible | 2 or 7 or 16 or 17' ' | 1 or 2 or 3 or 4 or 5 |
Back to top'; put / '
Back to top'; put / '
Back to top'; put / '
Back to top'; put / '
Back to top'; put / '
Back to top'; put / '
Back to top'; put / '
Back to top'; put / '
| Modelname | ' loop(solverA, put / 'Time (' solverA.tl:0 ') | '); loop(solverB, put / 'Time (' solverB.tl:0 ') | ' ); put / 'Ratio ('; loop(solverA, put solverA.tl:0 ' / '); loop(solverB, put solverB.tl:0 ')' ); put ' | '; loop(solverA, put / 'Obj (' solverA.tl:0 ') | '); loop(solverB, put / 'Obj (' solverB.tl:0 ') | '); put / '|||||
| ' modelname.tl:0 ' | ' '' resA(modelname):0:4 ' | ' '' resB(modelname):0:4 ' | ' ; if( resA(modelname) > %bnd% and resB(modelname) < %bnd%, ratio = inf; elseif( resA(modelname) < %bnd% and resB(modelname) < %bnd%), ratio =1; else ratio = resA(modelname) / resB(modelname); ); if(resA(modelname)' ratio:0 '.000 | '; else put '' ratio:0:3 ' | '; ); fresB_htm.nr = 2; if (sameas(objtype,"ObjAbet"), put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; elseif(sameas(objtype,"ObjBbet")), put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; else put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; ); fresB_htm.nr = 1; put '
| ' modelname.tl:0 ' | ' '' resA(modelname):0:4 ' | '; loop( (solverB,result), if( square(modelname,solverB,result), put all_results.te(result):0; ); ); put ' | -- | ' ; fresB_htm.nr = 2; if (sameas(objtype,"ObjAbet"), put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; elseif(sameas(objtype,"ObjBbet")), put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; else put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; ); fresB_htm.nr = 1; put '|
| ' modelname.tl:0 ' | '; loop( (solverA,result), if( square(modelname,solverA,result), put all_results.te(result):0; ); ); put ' | ' resB(modelname):15:4 ' | -- | '; fresB_htm.nr = 2; if (sameas(objtype,"ObjAbet"), put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; elseif(sameas(objtype,"ObjBbet")), put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; else put / '' ObjA(modelname):>25:8 ' | ' ObjB(modelname):>20:8 ' | ' /; ); fresB_htm.nr = 1; put '|
| ' modelname.tl:0 ' | ' loop( (solverA,result), if( square(modelname,solverA,result), put all_results.te(result):0; ); ); put / ' | ' loop( (solverB,result), if( square(modelname,solverB,result), put all_results.te(result):0; ); ); put / ' | -- | ' ; fresB_htm.nr = 2; put '' ObjA(modelname):>25:8 ' | ' '' ObjB(modelname):>20:8 ' |