| Using the C++ Math Library | ![]() |
The C++ roots() Function
The example is divided into two parts. The first part shows the main program, which sets up the problem and invokes the example version of roots(): the example_roots() function. The second part contains the example_roots() function. In the C++ source file, the order of the parts is reversed. The parts are reordered here for clarity.
You can find the code for this example in the<matlab>/extern/examples/cppmath directory on UNIX systems and in the <matlab>\extern\examples\cppmath directory on PCs, where <matlab> represents the top-level directory of your installation. See Building C++ Applications for information about building and running the example program.
In the example, note the following:
colon() and ramp() in the MATLAB C++ Math Library replace the MATLAB colon operator.const.mwIndex constructor produces an mwIndex object that acts, when used as a subscript, like a colon in MATLAB.if-statement, unlike the MATLAB if statement, requires that any matrices tested be reduced in rank to scalars by calls to any() or all(). See the online MATLAB C++ Math Library Reference for further explanation of the functions. Accessing Online Reference Documentation describes how to access the Help Desk.error() function throws an mwRuntimeException exception. mwRuntimeException is a subclass of mwException.vertcat() vertically concatenates two or more matrices. horzcat() behaves like vertcat() except performs horizontal concatenation.! to invert the truth value of a logical scalar mwArray; use the MATLAB C++ Math Library operator ~ to invert the truth value of a logical array. Do not apply ! to arrays.// Call example_roots() and the library's roots().
int main(void)
{
// Static array of doubles used to initialize the matrices.
static double input[] = { 1, -6, -72, -27 }; // #1
// Declare three matrices, one with initial values.
mwArray x(1, 4, input), result, verify; // #2
// Call our version of roots().
result = example_roots(x); // #3
// Call the MATLAB C++ Math Library roots.
verify = roots(x); // #4
// Print the input and output matrices from example_roots().
cout << "x = " << endl << x << endl;
cout << "example_roots(x) = " << endl << result << endl; // #5
// Check to see if the answer is equal to the real roots().
if (tobool(result == verify)) // #6
cout << "Success!" << endl;
return(EXIT_SUCCESS);
}
The numbered items in the list below correspond to the numbered comments in the code example:
The main program is straightforward, so the explanations below are brief. If you have difficulty understanding this section of the example, refer to Example Program: Writing Simple Functions (ex4.cpp) in Chapter 2.
x, a row vector (one row, four columns), is the input matrix. result and verify are initially null matrices.
example_roots() function and place the return value in the matrix result.
roots() and store the return value in the matrix verify. verify will be used to confirm that the rewriting of roots produces the correct result.
example_roots(). Print the output from example_roots().
verify contains the correct result. The mwArray class provides an overloaded operator==(), which makes comparing two matrices for equality easy.
The second part of the example is the example_roots() function itself. This function is part of the same file as the main program shown above.
#include <stdlib.h>
#include "matlab.hpp" // #1
// EXAMPLE_ROOTS(C) computes the roots of the polynomial whose
// coefficients are the elements of the vector C. If C has N+1
// components, the polynomial is C(1)*X^N + ... + C(N)*X + C(N+1).
mwArray example_roots(mwArray c) // #2
{
mwArray n, inz, nnz, r, a; // #3
mwIndex icolon;
// Make sure number of dimensions is not greater than 1.
n = size(c); // #4
if (all(n > 1.0))
error("Must be a vector");
n = max(n); // #5
c = transpose(c(icolon)); // Make sure it's a row vector.
inz = find(abs(c)); // Find nonzero elements. #6
nnz = max(size(inz)); // Count nonzero elements.
// Test all elements against zero.
if (!(nnz == 0.0)) // #7
{
c = c(ramp(inz(1), inz(nnz))); //Strip leading/trailing 0's
r = zeros(n - inz(nnz), 1); //Remember trailing 0's
}
// Polynomial roots via a companion matrix
n = max(size(c)); // Size of largest dimension of c #8
a = diag(ones(1, n - 2.0), -1.0); // Create a row vector of 1's.
if (n > 1.0) // #9
a(1,icolon) = -c(ramp(2, n)) / c(1);
r = vertcat(r, eig(a)); // #10
return r;
}
The numbered items in the list below correspond to the numbered comments in the code example:
matlab.hpp declares the MATLAB C++ Math Library's data types and functions. matlab.hpp includes iostream.h, which declares the input and output streams cin and cout. stdlib.h contains the definition of EXIT_SUCCESS.
example_roots(). We can't use the name roots() because the MATLAB C++ Math Library defines a roots() function with exactly the same number and type of input and output arguments. example_roots() has one input and one output, both of which are matrices. The input argument is not declared const because example_roots() stores temporary results in c.
icolon is declared using the default mwIndex constructor, this variable acts like MATLAB's : operator when used in array indexing expressions. Declaring a variable like this is more efficient than repeatedly calling the colon() function. See Programming Efficient Indices in Chapter 4 for more information.
n. At least one of the dimensions of the input matrix must be equal to one, that is, the matrix must be a vector. Report an error to the user and terminate if the matrix is malformed. Calling the error() function causes a runtime exception to be thrown.
n is now a 1-by-1 matrix: a scalar. Use the colon operator (here represented by the variable icolon) to extract the input matrix into a column vector. Transpose this vector to get a row vector. The root-finding algorithm below requires that the matrix be a row vector. You could improve the efficiency here by testing the dimensions of the input matrix and transforming them only when necessary.
inz is a vector, size() returns a vector [ 1 N ], where N is the length of the vector. N is the count of elements in inz.
find() will have returned a null matrix and nnz will be equal to 0. Note that wrapping the logical expression with all() is not necessary in this case, since nnz is known to be a scalar.
If the input matrix did not contain all zeros, inz contains the nonzero
elements. Replace the input matrix with a vector 1,2,...,N where N is the
number of nonzero elements originally in the input matrix. The result from
the call to ramp() goes from the first nonzero index to the last.
Set r to a column vector of zeros, with one row for each trailing zero element
of the input matrix. The arguments to the zeros() function are row count
and column count.
c is not empty, replace the first row of matrix a with the vector resulting from dividing the negative of the 2,...,N elements of c (enumerated by the call to ramp()) by c(1). This type of assignment, where an indexing expression appears on the left-hand side, is the only way to modify the contents of a matrix.
r and eig(a). The number of columns in both matrices must be the same. The rows of eig(a) are placed below the rows (in this case, the single row) of r. Reassign the result to r. Return the matrix r. Unlike MATLAB, C++ requires an explicit return statement.
Output
The program produces this output:
x =
[
1 -6 -72 -27
]
example_roots(x) =
1.0e+01 *
[
1.21229 ;
-0.57345 ;
-0.03884
]
Success!
| The M-File roots() Function | mwArray Class Interface | ![]() |