Loren on the Art of MATLAB

April 28th, 2011

Is There an echo Out There?

If I wanted to act like an old fogey, I could reminisce and say I miss the good old days where we, at MathWorks, delivered demos by using the function echo. But I can't honestly say I miss that aspect of writing demos. These days, we either create GUIs, often light-weight for a demo, perhaps using guide or nested functions such as this example, OR, we write MATLAB code that we publish.

Contents

Do You Hear the echo?

My question to you this week is: do you use the function echo currently? If so, can you please explain why/how (e.g., see no reason to update code, don't want to take the time to write a GUI, etc.). Thanks. As always, let me know your thoughts here.


Get the MATLAB code

Published with MATLAB® 7.12

April 21st, 2011

Deploying Multiple C++ Shared Libraries

Guest blogger Peter Webb returns with another in an occasional series of postings about application deployment.

Contents

Grouping related functions into separate shared libraries is very common, as it promotes good software design and maintainability via separation of concerns. A single application almost always calls functions from multiple shared libraries.

To show you how to build applications that use multiple MATLAB Compiler-generated shared libraries, I've written an example program that computes and displays the Mandelbrot set, a shape with a fractal boundary.

The application consists of three parts:

  • Two shared libraries, each generated by MATLAB Compiler.
  • A main program that interprets command line arguments and calls functions in the shared libraries.

Each of the MATLAB Compiler-generated shared libraries provides a specific kind of functionality: the libmandelbrot library performs mathematical calculations, while libimage displays images.

Building the Shared Libraries

Download the code for this example from MATLAB Central, unpack the ZIP files in a new folder, and then use the mcc command to create the shared libraries:

mcc -Nv -W cpplib:libmandelbrot -T link:lib mandelbrot.m
mcc -Nv -W cpplib:libimage -T link:lib showimage.m

Note the use of -W cpplib, which creates C++ shared libraries. Functions exported from C++ shared libraries are easier to use than those exported from C shared libraries.

Using Two Libraries

The main program, in fractal.cpp, initializes the application as usual:

 if (!mclInitializeApplication(NULL,0))
 {
      std::cerr << "Could not initialize the application properly."
                << std::endl;
  	return -1;
 }

Then, it initializes each shared library in turn:

  // Initialize the mandelbrot library
  if( !libmandelbrotInitialize() )
  {
      std::cerr << "Could not initialize the mandelbrot library properly."
                << std::endl;
      return -1;
  }
  // Initialize the image library
  if( !libimageInitialize() )
  {
      std::cerr << "Could not initialize the image library properly."
                << std::endl;
      return -2;
  }

By testing the value returned from each library's initialization function, fractal provides accurate error messages should initialization fail.

Each library exports a single function.

  • libmandelbrot exports fractal = mandelbrot(size, iterations)
  • libimage exports showimage(fractal)

The fractal main program calls mandelbrot to generate truecolor (24 bit) image data for the Mandelbrot set at a given size and resolution.

  mwArray fractal;
  mandelbrot(1, fractal, width, limit);

mandelbrot returns the image data as an mwArray object, which the main program then passes to showimage. This demonstrates that an mwArray created in one shared library can be processed in another; an mwArray is independent of the shared library that created it.

 showimage(fractal);

showimage creates an image from the image data and displays the image in a figure window.

Building and Running the Application

Compile the main program and link it with the two shared libraries using mbuild. The mbuild command varies by platform:

  • Windows: mbuild -g -v fractal.cpp libmandelbrot.lib libimage.lib
  • UNIX: mbuild -g -v fractal.cpp -L. -lmandelbrot -limage

Then, create a Mandelbrot set 500 pixels wide with an iteration limit of 100 by running the fractal program:

fractal 500 100

Mandelbrot sets require a significant amout of computation. The example above takes about 45 seconds on a PC with a 2.5GHz processor. A 2000-pixel wide set requires more than 15 minutes.

Have you ever written an application that uses multiple Compiler-generated libraries? Did it work as you expected? Let me know here.


Get the MATLAB code

Published with MATLAB® 7.11

April 11th, 2011

size Does Matter Sometimes

Recently at work I was on an email thread where people were discussing the function size and how to use it reliably in the context of arrays that might be two dimensional but could have higher dimensions as well. The original solutions resorted to calling size multiple times.

There is a better way, however, and I pointed it out. The idea is to use ~ to capture all the remaining dimensions after the first two. Like so:

  [rows, cols, ~] = size(A);

Steve has a much more in depth exposé of the problem and solution, and a follow-on post.

Instead of using ~, you could choose to use a junk variable and ignore it, but I (and Steve) prefer to use this relatively new feature and not clutter the code or workspace with something that is a distraction.

Have you used ~ to ignore outputs from a function, or in a function definition to ignore an input? Let me know some details here.


Get the MATLAB code

Published with MATLAB® 7.11

March 31st, 2011

Points and Polygons

Ever wanted to know if some points of interest were inside a region? You can answer that if the region is specified as a polygon in MATLAB. The key is the inpolygon function.

Contents

Polygons

Polygons in two dimensions are generally represented in MATLAB with two arrays, locations for the X vertices and Y vertices. There is no need to have the final points in these match the initial points; that is, when arrays as described are used in situations where they are interpreted as polygon vertices, the polygon is automatically closed.

Let's define a very simple polygon to start.

X = [0 0.5 1]';
Y = [0 0.5 0]';

And look at it.

patch(X,Y, [0.2, 0.7, 0.8], 'edgecolor','r',...
    'facealpha', 0.2, 'linewidth',2);
axis([0 1 -0.2 1])

Some Points of Interest

Let's create some points of interest now. Some inside, some outside, and some on the boundary.

xin = [0.3 0.75 0.82]';
yin = [0.25 0.1, 0.05]';
xout = [0.3 0.75 0.82]';
yout = [-0.15 0.6, 0.3]';
xedge = [0.3 0.75 0.82]';
yedge = [0.3 0.25, 0.18]';
hold all
plot(xin, yin, 'g*', 'markersize',5)
plot(xout, yout, 'mx', 'markersize',9)
plot(xedge, yedge, 'bd', 'markersize',7)
hold off

Test the Points with the Polygon

[inIN onIN] = inpolygon(xin,yin, X, Y)
inIN =
     1
     1
     1
onIN =
     0
     0
     0
[inOUT onOUT] = inpolygon(xout,yout, X, Y)
inOUT =
     0
     0
     0
onOUT =
     0
     0
     0
[inEDGE onEDGE] = inpolygon(xedge,yedge, X, Y)
inEDGE =
     1
     1
     1
onEDGE =
     1
     1
     1

Multiply-connected Polygon

Here's an example from the help for inpolygon, with a square containing a square hole. The outer loop is counterclockwise, the inner clockwise.

xv = [0 3 3 0 0 NaN 1 1 2 2 1];
yv = [0 0 3 3 0 NaN 1 2 2 1 1];
x = rand(1000,1)*3; y = rand(1000,1)*3;
in = inpolygon(x,y,xv,yv);
plot(xv,yv,x(in),y(in),'.r',x(~in),y(~in),'.b')

Do You Work with Points and Polygons?

Have you used inpolygon? I'd love to hear the contexts of the problems you solve with it. Let me know here.


Get the MATLAB code

Published with MATLAB® 7.11

March 22nd, 2011

Interpreting the Code Analyzer’s Deployment Messages

Guest blogger Peter Webb returns with another in an occasional series of postings about application deployment.

Contents

Previously, Jacob introduced the MATLAB code analyzer, mlint, which helps you write better code by notifying you of questionable constructs and opportunities for performance enhancement. The code analyzer's messages are organized into categories, one of which is deployment. The deployment category contains 16 messages. Deployment messages are off by default; you activate them via code analyzer preferences. To help you make the best possible use of the feedback provided by the code analyzer, I'll use this week's posting to provide an interpretation of each of its deployment messages. In the sections below, I quote code analyzer warning messages in italics.

Unsupported MATLAB Features

Some features of MATLAB do not work in deployed applications because of differences between the deployed environment and the MATLAB interactive environment. The MATLAB code analyzer warns about five such features:

  • MCC allows writing .m files, but they cannot be executed by the deployed application.

A MATLAB function may create another MATLAB function and then call it. For example, the Neural Network Toolbox uses this technique to train neural networks. A deployed application may create MATLAB functions on disk, but it cannot execute them. Deployed applications only execute encrypted MATLAB functions and only MATLAB Compiler can create encrypted functions for deployment (MATLAB Compiler itself cannot be deployed).

Functions that create and then call MATLAB functions on disk cannot be deployed. If your code needs to create simple functions at runtime, you may be able to use anonymous functions instead of creating new MATLAB function files.

  • MCC does not allow C++ files to be read directly using LOADLIBRARY.

When processing a C++ header file, loadlibrary creates new MATLAB function files. As discussed above, creating and then calling new MATLAB functions is a non-deployable feature. As a result loadlibrary cannot be used with C++ headers in deployed applications. However, you can deploy applications that use MATLAB function prototypes with loadlibrary. (See the documentation for MATLAB Compiler; search for "loadlibrary".)

  • MCC requires the program to assign a value to output argument name .

When MATLAB Compiler processes a MATLAB function with outputs, it creates a wrapper function with output parameters. The generated code requires that the output variables have valid MATLAB values when the function returns. MATLAB functions that do not assign values to their outputs are likely to cause the program to crash.

  • MCC use of absolute file names is likely to fail.
  • MCC use of toolbox folder file names is likely to fail.

Deployed applications have a different view of the file system than applications running in interactive MATLAB. A deployed application has a limited MATLAB path, and a different notion of the MATLAB root directory. A full discussion of this issue is beyond the scope of this post but, generally speaking, it is best to use relative paths instead of absolute paths, and to avoid references to files in a MATLAB installation. If you need access to a file in MATLAB in a deployed application, include the file in the application with the -a switch when creating it.

Unsupported Functions

MCC does not permit the function name function.

Certain MATLAB functions cannot be deployed because they rely on features of MATLAB that the deployed environment does not support. Avoid using these functions in code you intend to deploy, or use the isdeployed function to ensure your compiled program does not call these functions. The code analyzer issues warnings about five unsupported functions:

  • addpath: The path a deployed application uses to look for executable functions is fixed when the deployed application is created, and cannot be changed.
  • help: The help database is too big to put in a deployed application. Besides, users of your application should not need help with MATLAB functions, since your application encapsulates them.
  • keyboard: The implementation of this function relies on the MATLAB desktop environment, and deployed applications do not have access to the MATLAB desktop.
  • printdlg: On Microsoft Windows platforms, you must use deployprint instead of print. As a result, certain forms of printdlg cannot be deployed.
  • savepath: Deployed applications do not support saving and loading the MATLAB path. The MATLAB path is embedded into a deployed application when it is created, and the path can't be changed (so there's no point in saving it).

DEPLOYPRINT

MCC prefers Windows applications to call DEPLOYPRINT instead of PRINT, but use PRINT when printing to a file.

On Microsoft Windows platforms, a deployed application generates printed output by creating a JPEG file and then sending that file to printer. This mechanism is very different from the way MATLAB prints on Windows platforms. Deployed applications must use the deployprint function on Microsoft Windows platforms.

WEBFIGURE

  • MCC requires that the first argument of WEBFIGURE not come from FIGURE(n).
  • MCC requires that the first argument of WEBFIGURE not come from FIGURE(n) (line number).

Deployed applications use the webfigure function to display graphics inside of a web browser. webfigure takes a single argument: the handle of a figure. Certain details of the implementation require that the figure's numerical ID be automatically assigned by Handle Graphics rather than specified by the user. The code analyzer issues this webfigure warning when it detects code manually specifying figure IDs. For example:

f_bad = figure(1);
wf = webfigure(f_bad);   % Warning generated
f_ok = figure;
wf = webfigure(f_ok);   % No warning generated

Functions with Unexpected Behavior

MCC use of the function name function is problematic.

The code analyzer generates warnings for the first two of these functions because they manipulate or rely on the program's view of the file system, which is is very different in a deployed application. The third warning, about deployprint, only appears on UNIX systems. Deployed applications on UNIX systems print using print instead of deployprint.

  • cd: Changing the current directory in a deployed application does not affect the order in which the application will search directories for executable functions. In fact, the current directory is never searched for executable functions.
  • matlabroot: In a deployed application, matlabroot refers to the root of the installed MCR against which the application is running. An MCR installation is not a full MATLAB installation; applications cannot rely on being able to find all of MATLAB's functions or data files in an MCR installation.
  • deployprint: As noted above, applications deployed to UNIX systems use print instead of deployprint.

How do you use the code analyzer? Do these error messages make sense? Would you like to see the code analyzer integrated with deploytool or mcc? Let us know here.


Get the MATLAB code

Published with MATLAB® 7.11

March 8th, 2011

Common Design Considerations for Object Properties

I’m pleased to introduce guest blogger Dave Foti. Dave has worked on MATLAB for over 15 years and currently manages the group responsible for object-oriented programming features in MATLAB. He is interested in giving MATLAB users the tools to meet increasingly complex challenges. This post will take a look at making use of object properties in MATLAB.

Contents

Property Basics

Properties are how MATLAB objects store data. At their most basic level, properties provide a way to define what data are required for a particular kind of object. For example, if I have a set of measurements and each measurement has the same pieces of information, then I can create a class of measurement objects with a property to store each piece of information as in:

type surfaceTempReading1
classdef surfaceTempReading1
  properties
    Date
    Latitude
    Longitude
    Temperature
  end
end

I might have an instance that looks like this:

t1 = surfaceTempReading1;
t1.Date = date;
t1.Latitude  = '42:16:4 N';
t1.Longitude = '71:20:2 W';
t1.Temperature = 260;
disp(t1);
  surfaceTempReading1

  Properties:
           Date: '16-Mar-2011'
       Latitude: '42:16:4 N'
      Longitude: '71:20:2 W'
    Temperature: 260

The MATLAB documentation describes properties here.

Dependent Properties

In simple cases like this, it is probably fine to have all properties directly store and retrieve data. However, MATLAB provides ways to define properties that don’t directly store data. These dependent properties are defined using the Dependent attribute as in:

type surfaceTempReading2
classdef surfaceTempReading2
  properties
    Date
    Latitude
    Longitude
    Temperature
  end

  properties(Dependent)
    Altitude
  end  

  methods
    function A = get.Altitude(reading)
      A = lookupAltitude(reading.Latitude, reading.Longitude);
    end
  end
end

In this case, if I have a data set of surface temperature readings, I just need latitude and longitude to identify where the temperature was sampled. However, in analyzing the data, it might be helpful to correlate temperatures with surface altitude. Rather than have to input this data, the altitude can be calculated from a database of Earth surface topography. Assume I have a function that can provide such a value called lookupAltitude, then I can invoke that function from the Dependent property called Altitude.

t2 = surfaceTempReading2;
t2.Date = date;
t2.Latitude  = '42:16:4 N';
t2.Longitude = '71:20:2 W';
t2.Temperature = 260;
disp(t2)
  surfaceTempReading2

  Properties:
           Date: '16-Mar-2011'
       Latitude: '42:16:4 N'
      Longitude: '71:20:2 W'
    Temperature: 260
       Altitude: 342

Changing Property Names

Dependent properties allow me some flexibility to implement the same external interface in different ways. A user of our class doesn’t necessarily need to know how altitude was determined or whether or not it is actually stored in a class instance. This flexibility can be useful in evolving a class over time while not breaking scripts and functions that might use the class. For example, if I decide that TimeStamp is a better name for the Date property, I can gradually start switching over to the new name without immediately changing all of the code I have using Date:

type surfaceTempReading3
classdef surfaceTempReading3
  properties
    TimeStamp
    Latitude
    Longitude
    Temperature
  end
  
  % Deprecated property names
  properties(Dependent, Hidden) 
    Date
  end

  methods
    function D = get.Date(reading)  
      D = reading.TimeStamp;
    end

    function reading = set.Date(reading, D)
      reading.TimeStamp = D;
    end
  end
end

When I change my class as above, not only will old scripts using Date continue to work, but old MAT-Files saved using the old class definition will automatically load the Date value into the new TimeStamp property. I use the Hidden attribute so that the old property name doesn’t show up in object display, the properties command, or tab completion.

t3 = surfaceTempReading3;
t3.Date = date;
disp(t3);
  surfaceTempReading3

  Properties:
      TimeStamp: '16-Mar-2011'
       Latitude: []
      Longitude: []
    Temperature: []

Side Effects and Validation

Dependent properties can also be useful any time a property has side effects – when for example changing a property triggers an update to some other object or graphic or when getting a property requires doing some expensive operation to acquire or validate the result. Often these expensive operations can be avoided from certain "trusted" code defined inside the class. Having a one private property that doesn’t perform any side effects allows the trusted code to work on the raw property value. Other code inside and outside the class can use a public and dependent property that performs the side effects or expensive operations. Sometimes the expensive operation is just validating the input value being assigned to the property. For example, in our class if I want to validate temperature values, I can do something like the following:

type surfaceTempReading4;
classdef surfaceTempReading4
  properties
    Date
    Latitude
    Longitude
  end
  properties (Dependent)
    Temperature
  end
  
  properties(Access=private)
    pTemperature
  end

  methods
    function reading = set.Temperature(reading, t)
      if t < 0 
        error('SurfaceTemp:BadTemp', ...
              'Temperature must be a positive number in Kelvins.');
      end
      reading.pTemperature = t;
    end
    function t = get.Temperature(reading)
        t = reading.pTemperature;
    end
  end
end

NOTE: The above example has been changed to correct an error in the original post.

t4 = surfaceTempReading4;
try
    t4.Temperature = -15;
catch err
    disp(err.message);
end
Temperature must be a positive number in Kelvins.

Default Values

Classes can define default values for properties. A default value is defined by the class and each instance of the class is assigned that default value. Default values can be used when there is a constant default that can be documented with the class definition. Default values can save space in MAT-Files because defaults are saved once per class and values of properties not differing from default values don’t need to be saved. Generally speaking default values should be literal values wherever possible so that it is clear what the default is. For example:

type surfaceTempReading5
classdef surfaceTempReading5
  properties
    Date
    Latitude = '0N';
    Longitude = '0E';
    Temperature = 0;
  end
end

While it is possible to use the result of a function for a default value, one should avoid doing so unless the function returns a constant value. For example, it might be tempting to do something like:

type surfaceTempReading6
classdef surfaceTempReading6
  properties
    % Get the current date from MATLAB
    Date = date; 
    
    Latitude
    Longitude
    Temperature
  end
end

However, the problem with this is that the current date is not a constant default value that can be documented as part of the class. Moreover, since MATLAB evaluates default property expressions in class definitions only when a class is loaded or reloaded, the function call will generally happen once in a MATLAB session. Each object will get the same date stamp that was current when the class was loaded and not the current date at the time an object is created (perhaps the next day). Generally, one doesn’t want to assign a default value to a handle for a similar reason. If the intent is to make a new handle for each instance, then this handle has to be created in the constructor and not as a default value. Since defaults are the same for all instances created from a given class definition, all objects would get the same handle. For more information on handle classes, see Handle and Value Classes.

I’ve described a few uses for properties and a few common attributes, but I would be very interested in hearing how you use properties. You can post ideas here.


Get the MATLAB code

Published with MATLAB® 7.11

February 24th, 2011

Using the MATLAB Code Analyzer to Help Write Deployable Code

This week, guest blogger Jacob writes about how to use MATLAB-based tools to develop applications that are deployment-ready from inception.

Deployed applications rely on the MATLAB Compiler Runtime (the MCR) for execution. The MCR differs from MATLAB in subtle but important ways. You will find it much easier to deploy your MATLAB-based applications if you code with these differences in mind. You can learn how to develop deployable applications by reading our documentation and blog articles. To help you keep track of all the details, we're working on pushing some of this information into our development tools. One of first tools we enhanced for deployment is the MATLAB code analyzer, mlint.

Contents

Turning Deployment Messages On

The code analyzer examines MATLAB code to detect possible problems or improvements. The code analyzer is integrated into the MATLAB Editor so you can see its suggestions as you develop your code.

Code analyzer suggestions are divided into several categories (you can fine-tune which messages are shown through the Code Analyzer Preferences).

MATLAB Compiler (Deployment) Messages alert you when you use certain functions that may not deploy. However, you might not have noticed these messages before since this category is disabled by default. In order to enable this category of messages:

  • Invoke Code Analyzer Preferences by selecting File > Preferences > Code Analyzer
  • In the Default Settings box, locate the MATLAB Compiler (Deployment) Messages category and click Enable Category.
  • Catching Non-Deployable Code

    With Deployment messages enabled, the code analyzer can help detect when you are developing problematic code. For example, Writing Deployable Code used the following as an example of code that may compile but yield undesired results at run-time:

      cd mathFcns
      z = add(x,y);
      cd ../stringFcns
      s = add(s1,s2);

    In the MATLAB editor, the code analyzer highlights both instances of the cd command. By hovering your cursor over the underlined word, you view the warning message:

    MCC use of the CD function is problematic.

    Furthermore, if you click on the message, you get an explanation and suggested action. In this case, the suggested action is to avoid use of the CD command.

    Limitations of the Code Analyzer

    The code analyzer can help catch many instances of non-deployable code. Most of these instances involve the use of known problematic functions like cd, addpath or help.

    In fact, the Default Settings window in Code Analyzer Preferences displays all possible messages the code analyzer might display. Reading these messages helps you understand what code constructs the code analyzer is likely to catch.

    While the code analyzer is a useful tool for detecting some instances of non-deployable code, it cannot detect all instances. For example, consider the following example which results in no warning or error message:

      set(gca, 'ButtonDownFcn', 'LogButtonPress');

    This code may result in a failure when deployed because MATLAB Compiler's dependency analysis (depfun) cannot detect that LogButtonPress is a function that must be included in the application. For this code to work in deployed mode, you must explicitly include LogButtonPress at compile-time (by using the -a switch in mcc). In this case, the code analyzer suffers from some of the same limitations that MATLAB Compiler's dependency analysis does---the inability to understand the contents of a string.

    Use the Code Analyzer but Don't Depend on It

    The code analyzer can help you to write deployable code, but it is not a substitute for understanding the compilation process or how running your application in MATLAB differs from running against the MCR. This understanding ultimately provides the best foundation for writing deployable code.

    However, even if you cannot completely depend on the code analyzer to guarantee deployable code, you can still use it to quickly catch instances that might otherwise require lengthy debugging to correct. After all, problems caught while in development usually cost much less to fix than problems caught when the application is deployed.

    Are there other MATLAB coding patterns for which you think the code analyzer should issue deployment warnings? Let us know here.


    Get the MATLAB code

    Published with MATLAB® 7.11

    February 18th, 2011

    Hump-day Puzzler on MATLAB Answers

    Have you checked out MATLAB Central lately? There's a new service called MATLAB Answers. It is a place where you can pose questions or search questions already asked to look for preferred solutions.

    Recently there's been some fun activity on MATLAB Answers. The following thread is almost like a miniature MATLAB contest. Check out the hump-day puzzler. And add your own solution there if you'd like!


    Get the MATLAB code

    Published with MATLAB® 7.11

    February 10th, 2011

    Book Review: The Elements of MATLAB Style

    I've recently been offered the opportunity to review a new book, The Elements of MATLAB Style by contributor to the FEX, Richard K. Johnson. It's a great opportunity for me to see what's important in the eyes of one particular prolific MATLAB user. And it's a book worth you investigating for questions of style, especially if you work in a group or organization where there is lots of shared code and lots of people looking at and using the code.

    The first thing I like about Richard's book is the intent, to make it a reference in the venerable tradition of The Elements of Style, by Strunk and White. If you write in English, I highly recommend this book. Neither book is comprehensive but rather attempts to boil ideas down to the ones with the largest pay-off and the ones where mistakes are often made. So you get some essentials & pitfalls, and conventions (some, but not all, particular to MATLAB).

    Taking a look at the table of contents, we see first some high level principles, followed by a small number of main topics:

    • Formatting
    • Naming
    • Documentation
    • Programming
    • Files and Organization
    • Development

    with a few helpful lists bringing up the rear (e.g., keywords).

    Each of these chapters ends with a summary section which pulls together the main themes of each section. These summaries serve as a helpful review when you want to go back to look for more information. If it's listed there, you can be sure there will be some items in the chapter to guide you.

    I don't happen to agree with every choice Richard has made in terms of conventions, e.g., for layout or formatting. Nor does MathWorks follow all of these (or all of any convention, in some cases). I do agree that he has identified relevant topics worthy of any group embarking on a project to discuss and standardize on.

    I'd now like to take a little time mentioning a few of many points from the book that resonate for me. These are only a sampling, so don't read anything into ones that I have not listed here!

    • #7 Split Long Code Lines at Graceful Points - I find this one useful as it is a total pain having to trail far off to the right in any editor, even though it is possible.
    • # 10 Do Not Use Hard Tabs - This helps keep sanity when working among a group with possibly different editing environments.
    • # 43 Use Meaningful Names for Variables with a Large Scope - This makes code much easier to read, understand, and debug, if necessary.
    • # 69 Name Functions for What They Do - Since functions perform an action, the name should include information about the action.
    • # 86 Use Sortable Numbering in Data Filesnames - If you have many similar files of data, having a rational numbering scheme can only help you out.
    • # 97 Be Sure That Comments Agree with the Code - I will never forget the time that my thesis advisor called me because he was really irritated. I had left him a copy of a Fortran program that had copious comments, the final one being "Ignore all the comments above; they were for a previous version."
    • # 135 Avoid Cryptic Code - I have found that generally, writing cryptic code buys less than I expect in terms of good things, and more headaches than it warrants. On occasion, I have used cryptic code for performance in something time-critical. When I do, I try to comment it fully, including a straight-forward implementation in the comments which I have tested. That way, when the performance trade-offs change, I understand what the code is supposed to do and have two starting options for doing a code update.
    • # 150, 151 Minimize the Use of Global Variables and Minimize the Use of Global Constants -- I would say this even more strongly myself. There are superior techniques for dealing with information you want to share, whether they be function handles, classes and their properties, or some other methods. These techniques are much safer to use for many reasons - e.g., more easily controlled side effects, should any be desired, and code becomes more suitable for parallelism potentially.
    • # 172 Use Parenthese - Clarity of meaning is paramount, especially if others need to understand, modify, or translate the code.
    • # 176 Avoid Use of eval When Possible - I'm sure it doesn't seem so to some MATLAB users, but eval is avoidable most of the time.
    • # 185-188 The first of these is Avoid Complicated Conditional Expressions - These entries contain some useful thoughts on dealing with conditional constructs, the ordering of the cases, etc.
    • # 271-275 The first of these is Write Small Tests - I love that Richard has made testing a central tenet of this style guide. I don't see how programmers function well without a robust test suite.

    Congratulations to Richard for writing "The Elements of MATLAB Style." It's a book that I recommend you read. I encourage you to adapt the guidelines in a way suitable for your programming environment.


    Get the MATLAB code

    Published with MATLAB® 7.11

    February 3rd, 2011

    Creating C++ Shared Libraries and DLLs

    Guest blogger Peter Webb returns with another in an occasional series of postings about application deployment.

    Contents

    A previous post demonstrated how to use MATLAB Compiler to create standalone executables. In this article, I'll demonstrate how to use MATLAB Compiler to create C and C++ shared libraries or DLLs.

    You create a shared library or DLL to add MATLAB-based functionality to an application you're developing. You select one or more MATLAB-based functions to include in the shared library, and MATLAB Compiler generates a binary file that you link against your application. Shared libraries generated by MATLAB Compiler are compatible with the Microsoft Visual Studio development environment on Windows and with the GNU C/C++ tool suite on most UNIX platforms. The list of supported compilers changes from one release to the next; be sure to check that list before starting your project.

    Building a Shared Library

    To illustrate the process of creating and using shared libraries, I'll use a cryptographic algorithm, the Vigenere cipher. The program I've written consists of two parts:

    • libvingenere: A shared library containing two MATLAB functions encrypt and decrypt.
    • vigenere.cpp: A C++ main program that calls the functions in libvigenere.

    The source code for the MATLAB functions and the main program is available on MATLAB Central. The download package also includes VigenereDetails.html, which describes the implementation of the Vigenere cipher in MATLAB.

    The mcc command invokes MATLAB Compiler both from within interactive MATLAB and at the system (DOS or UNIX shell) prompt. Use mcc to build a shared library from the MATLAB encrypt and decrypt MATLAB functions:

     mcc -v -W cpplib:libvigenere -T link:lib encrypt decrypt

    This mcc command breaks down into four parts:

    • -v: Turn on verbose output.
    • -W cpplib:libvigenere: Generate C++ wrapper code. Name the generated library libvigenere.
    • -T link:lib: Invoke a C/C++ compiler to create a platform-specific binary shared library file from the generated code.
    • encrypt decrypt: Place the encrypt and decrypt functions in the shared library. Generate C++ wrapper functions for each.

    This command generates several files. Two of them are relevant here:

    • libvigenere.dll: The platform-specific binary: the shared library itself. On most Unix systems, this file ends with a .so extension: libvigenere.so.
    • libvigenere.h: Declarations of the C++ wrapper functions and C++ type conversion classes and utilities.

    The Generated Interface

    MATLAB Compiler generates many different kinds of functions: initialization, termination, error and print handling and, of course, the functions you selected to compile into the library.

    In our example, MATLAB Compiler generates a C++ entry point for encrypt and decrypt. Stripped of some bookkeeping annotation, these functions look very much like the corresponding MATLAB functions.

    void encrypt(int nargout, mwArray& ciphertext,
                 const mwArray& plaintext, const mwArray& key);
    void decrypt(int nargout, mwArray& plaintext,
                 const mwArray& ciphertext, const mwArray& key);

    The generated functions differ from the MATLAB functions in two significant ways:

    • The C++ functions explicitly declare the types of their arguments.
    • The C++ functions return void, passing back results in output parameters provided in the argument list.

    Let's look at the encrypt function in detail. For comparison, here's encrypt's MATLAB function signature:

     function ciphertext = encrypt(plaintext, key)

    The encrypt MATLAB function has one output and two inputs. The encrypt C++ function has zero outputs (the void return type) and four inputs. The first C++ input indicates the number of outputs requested by the caller. As indicated by the MATLAB function, the number of outputs may be zero or one. Passing any other value will result in an error. The second C++ input is the output argument, passed by reference. encrypt will overwrite any data in this argument with the encrypted message. The third and fourth C++ input arguments are the function inputs, the plaintext and the encryption key. They are passed by constant reference which means the encrypt function cannot change their contents.

    Unlike MATLAB, C++ requires all variables have declared, immutable types. Variables in MATLAB have types as well (matrix, cell array, structure, etc.), but the type of a MATLAB variable can change at any time. To accommodate this dynamic behavior in C++, the MATLAB Compiler provides the mwArray data type. All the functions generated by the MATLAB Compiler take mwArray inputs and return mwArray outputs. The mwArray API allows you to create mwArray objects from most C++ data types and to extract native C+++ data from a returned mwArray.

    Calling Functions in a Shared Library

    Now that I've created a shared library, I need to write a program to call the library's public functions. The program performs six tasks:

  • Includes the shared library's header file.
  • Parses command line arguments.
  • Initializes the MATLAB Compiler Runtime's global state and the shared library's state.
  • Creates input arguments; convert native C++ data types to MATLAB data types.
  • Invokes one or more functions from the shared library.
  • Shuts down the library and the MATLAB Compiler Runtime.
  • Below, I demonstrate how these steps translate into the code of the example's main program, vigenere.cpp.

    Step 1: All programs that use a MATLAB Compiler-generated shared library must include the library's header file. The header file has the same base name as the compiled library, libvigenere in this case, and a .h extension.

    // vingenere.cpp: Encrypt and decrypt using the Vigenere cipher.
    #include "libvigenere.h"
    #include <iostream>

    Step 2: The main program parses the command line. The first argument, a switch, determines the type of action: -e means encrypt, -d decrypt. The second argument is the message, and the third, the key.

    int main(int ac, const char *av[])
    {
        // Encrypt or decrypt? Determined by command line switch
        bool enc = strcmp(av[1], "-e") == 0;

    Step 3: Initialize the runtime and start the library before calling any functions exported from the runtime or the library. Failure to initialize will cause your program to crash. Always check for success (the initializers return false if they fail) and issue error messages as necessary.

        // Initialize the MATLAB Compiler Runtime global state
        if (!mclInitializeApplication(NULL,0))
        {
            std::cerr << "Could not initialize the application properly."
                      << std::endl;
            return -1;
        }
        // Initialize the Vigenere library
        if( !libvigenereInitialize() )
        {
            std::cerr << "Could not initialize the library properly."
                      << std::endl;
            return -1;
        }

    Step 4: Convert the C++ strings from the command line (the message and the key) into MATLAB strings by creating mwArray objects. These declarations cannot appear before the initialization calls in Step 3.

        // Must declare all MATLAB data types after initializing the
        // application and the library, or their constructors will fail.
        mwArray text(av[2]);
        mwArray key(av[3]);
        mwArray result;

    Step 5: Invoke the exported functions. Encrypt or decrypt as indicated by the command line switch. Note that the C++ functions have the same name as their MATLAB counterparts, and that all return values must be passed in by reference. The mwArray class defines

        // Initialization succeeded. Encrypt or decrypt.
        if (enc == true)
        {
            // Encrypt the plaintext text with the key.
            // Request one output, pass in two inputs
            encrypt(1, result, text, key);
        }
        else
        {
            // Decrypt the ciphertext text with the key.
            // Request one output, pass in two inputs
            decrypt(1, result, text, key);
        }
        std::cout << result << std::endl;

    Step 6: Shut down the library and the runtime, in the opposite order of initialization (library first, then runtime).

        // Shut down the library and the application global state.
        libvigenereTerminate();
        mclTerminateApplication();
    }

    Creating and Running the Application

    MATLAB Compiler uses the mbuild function to compile the code it generates into a shared library. mbuild knows how to invoke the C/C++ compiler with the correct switches so the compiler can find the required include files and libraries. You can use mbuild to create your own executables and link them with MATLAB Compiler-generated shared libraries. On Windows, for example, issue this command:

    mbuild vigenere.cpp libvigenere.lib

    On UNIX, you link against a .so file instead of a .lib file:

    mbuild vigenere.cpp libvigenere.so

    In both cases, mbuild produces an executable called vigenere.

    Encrypt the message with the secret key.

    >> !vigenere -e "Algebra, the Music of the Reason" "MATLAB"
       MLZPBSM LSEAYUKTCA FSDHFLRXLSPZ

    The first argument is the message, the second argument the key. Note the leading exclamation point -- this command runs the vigenere executable from within MATLAB, using the system command. You can run these commands on the UNIX or DOS command line as well, but you have to configure your environment correctly.

    Decrypt to verify the encryption worked:

    >> !vigenere -d "MLZPBSM LSEAYUKTCA FSDHFLRXLSPZ" "MATLAB"
    ALGEBRA THE MUSIC OF THE REASON

    Because the alphabets in the Vigenere square only include letters and the space character, the decrypted message lacks punctuation marks. Extending the algorithm to handle punctuation is an exercise left to the reader.

    And extra points if you can figure out why I chose that phrase (aside from its poetic merit, which is in the eye of the beholder).

    Next: Using Multiple Shared Libraries

    I've shown you how to combine several MATLAB-based functions into a single shared library, and how to incorporate that library into a host application. In a later posting, I'll demonstrate how to use multiple shared libraries from a single host application.

    What else can I tell you about shared libraries? Let me know here.


    Get the MATLAB code

    Published with MATLAB® 7.11


    MathWorks
    Loren Shure works on design of the MATLAB language at MathWorks. She writes here about once a week on MATLAB programming and related topics.

    These postings are the author's and don't necessarily represent the opinions of The MathWorks.