XLL+ Class Library (7.0)

BoostMatrix Sample

Demonstrates how to write a matrix adapter class, to integrate a matrix class into XLL+

Overview

This add-in demonstrates how to integrate matrix classes into XLL+.

The example uses the boost::multi_array class as its matrix container. A simple adapter class, mtx_multi_array_adapter<T>, is created, which provides a bridge between the ple::imtx<T> interface, which is used by the XLL+ data validation functions, and the boost::multi_array<T, 2> template class.

Boost

See the boost web-site at http://www.boost.org/libs/multi_array/doc/index.html for more information about the multi_array class. Visit http://www.boost.org to download a copy of the latest version of the boost libraries.

Features

The sample displays the following features:

Setting the container of a matrix argument

In the example function, MyMatrixAdd, the two matrix arguments were amended in the XLL+ Function Wizard, as shown below:

Argument Details window with Container field populated

The container class for the first argument was typed into the Container field. For the second argument, it appears in the drop-down, which saves on typing and reduces errors.

Argument Details window with Container drop-down

As a result of the change to the arguments' container class, slightly different code was generated by the XLL+ Function Wizard:

CopyC++
CXlOper* MyMatrixAdd_Impl(CXlOper& xloResult, const CXlOper* A_op, 
    const CXlOper* B_op)
{
    // Input buffers 
    boost::multi_array<double, 2> A;
    boost::multi_array<double, 2> B;
    // Named bounds 
    long heightOfA = -1;
    long widthOfA = -1;
    // Validate and translate inputs
    XlReadMatrix(*A_op, mtx_adapter(A), L"A", XLA_TRUNC_ONEMPTY|
        XLA_TRUNC_ONBLANK|XLA_FLAG_REJECT_NULL_ARRAY, &heightOfA, 0, &widthOfA);
    XlReadMatrix(*B_op, mtx_adapter(B), L"B", XLA_TRUNC_ONEMPTY|
        XLA_TRUNC_ONBLANK|XLA_FLAG_REJECT_NULL_ARRAY, &heightOfA, 0, &widthOfA);
    // End of generated code 
    //}}XLP_SRC

The only difference between this code and the standard wizard-generated code is in the declaration of the local variables that hold the matrix values. Instead of the standard ple::mtx_ptrs container, boost::multi_array is used.

The global function mtx_adapter is called, which creates an adapter for the multi_array instance and passes that to the validation function, XlReadMatrix.

For more about setting an argument's container class, see Matrix containers in the User Guide.

Returning a matrix value to Excel

The sample function uses the two input matrices, A and B, and adds them to make a third matrix, C, also of type boost::multi_array. The function then returns the value to Excel by wrapping it in an adapter class, as shown below:

CopyC++
CXlOper* MyMatrixAdd_Impl(CXlOper& xloResult, const CXlOper* A_op, const CXlOper
    * B_op)
{
    // Input buffers
    boost::multi_array<double, 2> A;
    boost::multi_array<double, 2> B;
    ...
    // End of generated code 
    //}}XLP_SRC
    boost::multi_array<double, 2> C(boost::extents[heightOfA][widthOfA]);

    for (long i = 0; i < heightOfA; i++)
    for (long j = 0; j < widthOfA; j++)
    C[i][j] = A[i][j] + B[i][j];

    xloResult = mtx_adapter(C); 
    return xloResult.Ret();
}

Adapter class

The matrix adapter class is defined in the file XlpMultiArray.h in the sample directory.

The XLL+ validation methods expect matrix classes to support the ple::imtx interface. The following ple::imtx methods are used by the validation functions, and must be implemented by an adapter class.

In addition, if you wish to return matrix values to Excel, the adapter class must implement the following methods:

(Note: mtx_size is typedef'd to size_t in the XLL+ implementation of imtx.)

The code for the adapter class is shown below:

CopyC++
template<class T>
class mtx_multi_array_adapter : public ple::imtx_impl<T> {
public:
    mtx_multi_array_adapter(boost::multi_array<T, 2>& impl) : _impl(&impl) {}
    virtual void resize(bool preserve, mtx_size dim0, mtx_size dim1) {
        boost::multi_array<T, 2>::extent_gen extents;
        (*_impl).resize(extents[dim0][dim1]);
    }
    virtual T& at(mtx_size i0, mtx_size i1) {
        return (*_impl)[i0][i1];
    }
    virtual const T& at(mtx_size i0, mtx_size i1) const {
        return (*_impl)[i0][i1];
    }
    virtual mtx_size size(int dim) const {
        return (mtx_size)(*_impl).shape()[dim];
    }
protected:
    boost::multi_array<T, 2>* _impl;
};
template<class T>
mtx_multi_array_adapter<T> mtx_adapter(boost::multi_array<T, 2>& src) {
    return mtx_multi_array_adapter<T>(src);
}

The adapter is derived from the abstract base class ple::imtx_impl<T>.

The constructor takes a reference to a multi_array instance as its only argument, and saves it in _impl.

resize() calls multi_array::resize with the arguments transformed into the notation used by multi_array. (Note that the preserve argument is ignored. The calls made to resize() by the validation functions always assume that the content is destroyed after a resize operation.)

The two at() methods simply pass the coordinates through to the adapted class.

size() extracts the size of the matrix in the requested dimension and returns it, cast to the appropriate integer type.

Finally, the generic template function mtx_adapter creates a new instance of the adapter class and returns it. This global function is used by the validation functions to create adapters for all matrix types. As we saw above, it can also be used in your own code, to create an adapter for a matrix, so that it can be used with the XLL+ run-time library.

Notes

In order to build this sample project, you need to do the following:

  1. Download and install the boost libraries. (Visit http://www.boost.org.)

  2. In the project's list of Additional Include Directories, change the directory C:\3rdParty\boost_1_46_0 to the directory where you installed the boost libraries. (The directory you select should be the parent of the main boost sub-directory.)

When you use the boost libraries under Visual Studio 2005, a host of C4996 warnings appear. These can be prevented by adding /D _SCL_SECURE_NO_WARNINGS to the project's advanced compiler options, or by adding #define _SCL_SECURE_NO_WARNINGS to your code. The former was done for the sample project.

Classes and functions used

imtx<T> | CXlOper::Ret

Sample project

Each sample project is located in a sub-directory of the Samples directory of the XLL+ installation. To use the sample project, open the solution file BoostMatrix.sln or the project file BoostMatrix.vcproj.

You can enable debugging under Excel by using the Setup Debugging command in the XLL+ ToolWindow.

When delivered, the help files are excluded from the build. You can enable the help build by selecting the files BoostMatrix.help.xml and BoostMatrix.chm in the Solution Explorer, and using the right-click menu to view Properties. Select the page "Configuration Properties/General" and set the "Excluded from build" property to "No". See Generating help in the User Guide for more information.

See Also

List of Sample Projects | Matrix containers