* Bug #10269 fixed - qp_solve can now return an error flag 80/11680/8
Paul BIGNIER [Tue, 11 Jun 2013 09:21:32 +0000 (11:21 +0200)]
If a fifth output argument is present (qp_solve used to take up to four arguments),
then qp_solve returns the error flag in it,
and issues warnings intead of errors

Change-Id: Ia1a9fd2e8dd665e2fb0278223f8ae0648c3a1096

SEP/INDEX
SEP/SEP_098_qp_solve.odt [new file with mode: 0644]
scilab/CHANGES_5.5.X
scilab/modules/optimization/help/en_US/qp_solve.xml
scilab/modules/optimization/sci_gateway/c/sci_qp_solve.c
scilab/modules/optimization/tests/nonreg_tests/bug_10269.dia.ref [new file with mode: 0644]
scilab/modules/optimization/tests/nonreg_tests/bug_10269.tst [new file with mode: 0644]

index ea7e6ff..d426624 100644 (file)
--- a/SEP/INDEX
+++ b/SEP/INDEX
@@ -85,10 +85,11 @@ SEP #085: cond improvements
 SEP #086: Improvement of the regexp function
 SEP #087: New binaries: xcos scinotes
 SEP #088: Remote file access functions
-SEP #089: New parameter added at routh_t function (normalized)
+SEP #089: New argument added at routh_t function (normalized)
 SEP #090: New function to access to numerical data in HDF5 files
 SEP #091: New function daskr
 SEP #092: 
 SEP #093: New function cov
 SEP #095: New functions: ismatrix, isrow,iscolumn and issquare.
-SEP #097: New parameter added at strtod function (decimalseparator)
+SEP #097: New argument added at strtod function (decimalseparator)
+SEP #098: New output argument for qp_solve function
diff --git a/SEP/SEP_098_qp_solve.odt b/SEP/SEP_098_qp_solve.odt
new file mode 100644 (file)
index 0000000..f78a785
Binary files /dev/null and b/SEP/SEP_098_qp_solve.odt differ
index 8633a31..59ab62d 100644 (file)
@@ -51,6 +51,10 @@ Improvements
 * New calling sequence allowed for nicholschart: nicholschart(gains, phases, colors).
   See bug #7828.
 
+* qp_solve can now take up to 5 output arguments. The last one is an error flag,
+  if it is present, then the function will issue a warning instead of an error.
+  See bug #10269.
+
 * graypolarplot has been improved in term of performances and rendering.
   See bug #12641.
 
@@ -247,6 +251,9 @@ Bug fixes
 
 * Bug #10254 fixed - Slight improvements in help page of ones.
 
+* Bug #10269 fixed - qp_solve can now take up to 5 output arguments. The last one is an error flag,
+                     if it is present, then the function will issue a warning instead of an error.
+
 * Bug #10287 fixed - An error message added for complex expression as input argument of integrate function.
 
 * Bug #10596 fixed - exit(xxx) from Scilab was failing.
index 9ef34be..594d5d4 100644 (file)
           xmlns:scilab="http://www.scilab.org">
     <refnamediv>
         <refname>qp_solve</refname>
-        
         <refpurpose>linear quadratic programming solver builtin</refpurpose>
     </refnamediv>
-    
     <refsynopsisdiv>
         <title>Calling Sequence</title>
-        
-        <synopsis>[x [,iact [,iter [,f]]]] = qp_solve(Q, p, C, b, me)</synopsis>
+        <synopsis>[x [,iact [,iter [,f [,info]]]]] = qp_solve(Q, p, C, b, me)</synopsis>
     </refsynopsisdiv>
-    
     <refsection>
         <title>Arguments</title>
-        
         <variablelist>
             <varlistentry>
                 <term>Q</term>
-                
                 <listitem>
                     <para>
                         real positive definite symmetric matrix (dimension <literal>n
                     </para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>p</term>
-                
                 <listitem>
                     <para>
                         real (column) vector (dimension <literal> n</literal>)
                     </para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>C</term>
-                
                 <listitem>
                     <para>
                         real matrix (dimension <literal> (me + md) x n</literal>).
                     </para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>b</term>
-                
                 <listitem>
                     <para>
                         RHS column vector (dimension <literal> m=(me +
                     </para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>me</term>
-                
                 <listitem>
                     <para>
                         number of equality constraints (i.e. <literal>x'*C(:,1:me) =
                     </para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>x</term>
-                
                 <listitem>
                     <para>optimal solution found.</para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>iact</term>
-                
                 <listitem>
                     <para>
                         vector, indicator of active constraints.
                     </para>
                 </listitem>
             </varlistentry>
-            
             <varlistentry>
                 <term>iter</term>
-                
                 <listitem>
                     <para>2x1 vector, first component gives the number of "main"
                         iterations, the second one says how many constraints were deleted
                     </para>
                 </listitem>
             </varlistentry>
+            <varlistentry>
+                <term>info</term>
+                <listitem>
+                    <para>integer, error flag. If it is present and qp_solve encounters an error,
+                        then a warning is issued. The current results are returned, so in this case they are probably inaccurate.
+                    </para>
+                </listitem>
+            </varlistentry>
         </variablelist>
     </refsection>
-    
     <refsection>
         <title>Description</title>
-        
         <informalequation>
             <mediaobject>
                 <imageobject>
                 </imageobject>
             </mediaobject>
         </informalequation>
-        
         <para>
             This function requires <literal>Q</literal> to be symmetric positive
             definite. If this hypothesis is not satisfied, one may use the contributed
             <emphasis role="bold">quapro toolbox</emphasis>.
         </para>
     </refsection>
-    
     <refsection>
         <title>Examples</title>
-        
         <programlisting role="example"><![CDATA[ 
 // Find x in R^6 such that:
 // x'*C1 = b1 (3 equality constraints i.e me=3)
@@ -178,50 +161,38 @@ me=3;
 // Only linear constraints (1 to 4) are active 
  ]]></programlisting>
     </refsection>
-    
     <refsection>
         <title>See Also</title>
-        
         <simplelist type="inline">
             <member>
                 <link linkend="optim">optim</link>
             </member>
-            
             <member>
                 <link linkend="qld">qld</link>
             </member>
-            
             <member>
                 <link linkend="qpsolve">qpsolve</link>
             </member>
         </simplelist>
-        
         <para>The contributed toolbox "quapro" may also be of interest, in
             particular for singular <literal>Q</literal>.
         </para>
     </refsection>
-    
     <refsection>
         <title>Memory requirements</title>
-        
         <para>Let r be</para>
-        
         <programlisting> 
             r=min(m,n)
         </programlisting>
-        
         <para>Then the memory required by qp_solve during the computations
             is
         </para>
-        
         <programlisting> 
             2*n+r*(r+5)/2 + 2*m +1
         </programlisting>
     </refsection>
-    
     <refsection>
         <title>References</title>
-        
         <itemizedlist>
             <listitem>
                 <para>Goldfarb, D. and Idnani, A. (1982). "Dual and Primal-Dual
@@ -231,14 +202,12 @@ me=3;
                     226-239.
                 </para>
             </listitem>
-            
             <listitem>
                 <para>Goldfarb, D. and Idnani, A. (1983). "A numerically stable dual
                     method for solving strictly convex quadratic programs", Mathematical
                     Programming 27: 1-33.
                 </para>
             </listitem>
-            
             <listitem>
                 <para>QuadProg (Quadratic Programming Routines), Berwin A
                     Turlach,<ulink
@@ -247,12 +216,21 @@ me=3;
             </listitem>
         </itemizedlist>
     </refsection>
-    
     <refsection>
         <title>Used Functions</title>
-        
         <para>qpgen2.f and &gt;qpgen1.f (also named QP.solve.f) developped by
             Berwin A. Turlach according to the Goldfarb/Idnani algorithm
         </para>
     </refsection>
+    <refsection>
+        <title>History</title>
+        <revhistory>
+            <revision>
+                <revnumber>5.5.0</revnumber>
+                <revdescription>
+                    Fifth output argument <literal>info</literal> added for error information.
+                </revdescription>
+            </revision>
+        </revhistory>
+    </refsection>
 </refentry>
index 9da3fd6..bf94e1d 100644 (file)
@@ -17,6 +17,8 @@
 #include "api_scilab.h"
 #include "MALLOC.h"
 #include "Scierror.h"
+#include "sciprint.h"
+#include "warningmode.h"
 #include "localization.h"
 /*--------------------------------------------------------------------------*/
 /* fortran subroutines */
@@ -43,7 +45,7 @@ int sci_qp_solve(char *fname, unsigned long fname_len)
     static int m = 0, next = 0;
     static int mbis = 0;
     static int pipo = 0;
-    static int nact = 0, ierr = 0;
+    static int nact = 0;
     int r = 0;
     static int lw = 0,  k = 0;
     static SciSparse Sp;
@@ -66,11 +68,12 @@ int sci_qp_solve(char *fname, unsigned long fname_len)
     int* iact = NULL;
     int* iter = NULL;
     double* crval = NULL;
+    int *ierr = NULL;
 
 
     /*   Check rhs and lhs   */
     CheckInputArgument(pvApiCtx, 5, 5) ;
-    CheckOutputArgument(pvApiCtx, 1, 4) ;
+    CheckOutputArgument(pvApiCtx, 1, 5) ;
 
     /*Warning this interface does not support arguments passed by reference */
 
@@ -270,6 +273,14 @@ int sci_qp_solve(char *fname, unsigned long fname_len)
         return 1;
     }
 
+    sciErr = allocMatrixOfDoubleAsInteger(pvApiCtx, next + 5, un, un, &ierr);
+    if (sciErr.iErr)
+    {
+        printError(&sciErr, 0);
+        Scierror(999, _("%s: Memory allocation error.\n"), fname);
+        return 1;
+    }
+
 
     r = Min(n, m);
     lw =  2 * n + r * (r + 5) / 2 + 2 * m + 1;
@@ -278,13 +289,13 @@ int sci_qp_solve(char *fname, unsigned long fname_len)
         Scierror(999, _("%s: Cannot allocate more memory.\n"), fname);
     }
     /* change the sign of  C and b.*/
-    ierr = 0;
+    *ierr = 0;
     if (!issparse)
     {
         /* linear constraints matrix is stored full */
         C2F(qpgen2)((Q), (p), &n, &n,  (x), (crval), (C),
                     (b), &n, &m, (me), (iact), &nact, (iter), work,
-                    &ierr);
+                    (ierr));
     }
     else
     {
@@ -317,7 +328,7 @@ int sci_qp_solve(char *fname, unsigned long fname_len)
         C2F(qpgen1sci)((Q), (p), &n, &n,  (x), (crval),
                        ind, ind + m,  R,
                        (b), &m, (me), (iact), &nact, (iter),
-                       work, &ierr);
+                       work, (ierr));
         FREE(work);
         work = NULL;
         FREE(R);
@@ -331,24 +342,47 @@ int sci_qp_solve(char *fname, unsigned long fname_len)
         (iact)[k] = 0;
     }
     /* LhsVar: [x, iact, iter, f] = qp_solve(...) */
-
-    if (ierr == 0)
+    if (Lhs != 5)
+    {
+        if (*ierr == 0)
+        {
+            for (k = 0; k < Lhs; k++)
+            {
+                AssignOutputVariable(pvApiCtx, 1 + k) = next + 1 + k;
+            }
+            ReturnArguments(pvApiCtx);
+        }
+        else if (*ierr == 1)
+        {
+            Scierror(999, _("%s: The minimization problem has no solution.\n"), fname);
+        }
+        else if (*ierr == 2)
+        {
+            Scierror(999, _("%s: Q is not symmetric positive definite.\n"), fname);
+        }
+    }
+    else
     {
         for (k = 0; k < Lhs; k++)
         {
             AssignOutputVariable(pvApiCtx, 1 + k) = next + 1 + k;
         }
+        if (*ierr == 1)
+        {
+            if (getWarningMode())
+            {
+                sciprint(_("\n%s: Warning: The minimization problem has no solution. The results may be inaccurate.\n\n"), fname);
+            }
+        }
+        else if (*ierr == 2)
+        {
+            if (getWarningMode())
+            {
+                sciprint(_("\n%s: Warning: Q is not symmetric positive definite. The results may be inaccurate.\n\n"), fname);
+            }
+        }
         ReturnArguments(pvApiCtx);
     }
-    else if (ierr == 1)
-    {
-        Scierror(999, _("%s: The minimization problem has no solution.\n"), fname);
-    }
-    else if (ierr == 2)
-    {
-        Scierror(999, _("%s: Q is not symmetric positive definite.\n"), fname);
-    }
     return 0;
 }
 /*--------------------------------------------------------------------------*/
-
diff --git a/scilab/modules/optimization/tests/nonreg_tests/bug_10269.dia.ref b/scilab/modules/optimization/tests/nonreg_tests/bug_10269.dia.ref
new file mode 100644 (file)
index 0000000..26d354b
--- /dev/null
@@ -0,0 +1,44 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Paul Bignier
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+// <-- CLI SHELL MODE -->
+// <-- ENGLISH IMPOSED -->
+// <-- Non-regression test for bug 10269 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/show_bug.cgi?id=10269
+//
+// <-- Short Description -->
+//    qp_solve can now take up to 5 output arguments. The last one is an error flag,
+//    if it is present, then the function will issue a warning instead of an error.
+// Run with test_run('optimization', 'bug_10269', ['no_check_error_output'])
+C1 = [1, -1, 2; -1, 0, 5; 1, -3, 3; 0, -4, 0; 3, 5, 1; 1, 6, 0];
+b1 = [1; 2; 3];
+// x'*C2 >= b2 (2 inequality constraints)
+C2 = [0 ,1; -1, 0; 0, -2; -1, -1; -2, -1; 1, 0];
+b2 = [1; -2.5];
+// and minimize 0.5*x'*Q*x - p'*x with
+p = [-1; -2; -3; -4; -5; -6]; Q = eye(6, 6);
+me = 3;
+// Normal behavior
+[x, iact, iter, f] = qp_solve(Q, p, [C1 C2], [b1; b2], me);
+assert_checkequal(iter, [5; 0]);
+assert_checkalmostequal(f, -14.843248, 1e-5);
+// Still normal, but with error flag
+[x, iact, iter, f, info] = qp_solve(Q, p, [C1 C2], [b1; b2], me);
+assert_checkequal(info, 0);
+assert_checkequal(iter, [5; 0]);
+assert_checkalmostequal(f, -14.843248, 1e-5);
+// Provoked error, without flag
+Q = rand(6, 6);
+refMsg = msprintf(_("%s: Q is not symmetric positive definite.\n"), "qp_solve");
+assert_checkerror("[x, iact, iter, f] = qp_solve(Q, p, [C1 C2], [b1; b2], me);", refMsg);
+// Provoked error, with flag
+[x, iact, iter, f, info] = qp_solve(Q, p, [C1 C2], [b1; b2], me);
+
+qp_solve: Warning: Q is not symmetric positive definite. The results may be inaccurate.
+
+assert_checkequal(info, 2);
diff --git a/scilab/modules/optimization/tests/nonreg_tests/bug_10269.tst b/scilab/modules/optimization/tests/nonreg_tests/bug_10269.tst
new file mode 100644 (file)
index 0000000..5fcc71f
--- /dev/null
@@ -0,0 +1,53 @@
+// =============================================================================
+// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+// Copyright (C) 2013 - Scilab Enterprises - Paul Bignier
+//
+//  This file is distributed under the same license as the Scilab package.
+// =============================================================================
+
+// <-- CLI SHELL MODE -->
+// <-- ENGLISH IMPOSED -->
+
+// <-- Non-regression test for bug 10269 -->
+//
+// <-- Bugzilla URL -->
+// http://bugzilla.scilab.org/show_bug.cgi?id=10269
+//
+// <-- Short Description -->
+//    qp_solve can now take up to 5 output arguments. The last one is an error flag,
+//    if it is present, then the function will issue a warning instead of an error.
+
+// Run with test_run('optimization', 'bug_10269', ['no_check_error_output'])
+
+C1 = [1, -1, 2; -1, 0, 5; 1, -3, 3; 0, -4, 0; 3, 5, 1; 1, 6, 0];
+b1 = [1; 2; 3];
+
+// x'*C2 >= b2 (2 inequality constraints)
+C2 = [0 ,1; -1, 0; 0, -2; -1, -1; -2, -1; 1, 0];
+b2 = [1; -2.5];
+
+// and minimize 0.5*x'*Q*x - p'*x with
+p = [-1; -2; -3; -4; -5; -6]; Q = eye(6, 6);
+me = 3;
+
+// Normal behavior
+[x, iact, iter, f] = qp_solve(Q, p, [C1 C2], [b1; b2], me);
+assert_checkequal(iter, [5; 0]);
+assert_checkalmostequal(f, -14.843248, 1e-5);
+
+// Still normal, but with error flag
+[x, iact, iter, f, info] = qp_solve(Q, p, [C1 C2], [b1; b2], me);
+assert_checkequal(info, 0);
+assert_checkequal(iter, [5; 0]);
+assert_checkalmostequal(f, -14.843248, 1e-5);
+
+// Provoked error, without flag
+Q = rand(6, 6);
+refMsg = msprintf(_("%s: Q is not symmetric positive definite.\n"), "qp_solve");
+assert_checkerror("[x, iact, iter, f] = qp_solve(Q, p, [C1 C2], [b1; b2], me);", refMsg);
+
+// Provoked error, with flag
+[x, iact, iter, f, info] = qp_solve(Q, p, [C1 C2], [b1; b2], me);
+assert_checkequal(info, 2);
+
+