WPF is Microsoft's latest, greatest means for developing a graphical user interface for desktop applications, which is one reason to learn it, but in my initial research on the topic I came across a few others that are worth mentioning. Why learn WPF?

  • Broad integration - WPF makes it straightforward to work with 3D graphics, video, speech, rich document viewing, etc. all in one app.
  • Resolution independence - if you have a graphics-heavy app, whether it be fancy backgrounds, skins, and buttons or lots of charts, graphs, or 3D modeling, you'll like WPF. It makes use of vector graphics, which means scaling for different screen resolutions becomes a non-issue.
  • Hardware acceleration - WPF is built on top of Direct3D, so again, that's good for graphics.
  • Declarative programming - The XAML language is nice for the developer, allowing you to quickly lay out an app and make changes to it.
  • Rich composition and customization - The WPF model gives the developer a lot of control over the look and feel of just about every aspect of the GUI. It makes use of templates and chains of inheritance for styles, which makes it easy to change the look of an app or apply skins.

My current motivation for wanting to learn WPF is my search for a quicker way to put together apps for my engineering clients. For the most part, they request desktop apps that involve working with data that represents some physical phenomena, graphing the data in some form or another, querying the data, and performing calculations with the data. I feel as though the "hard" part of my clients' requests should be figuring out the calculations and coming up with clear, concise ways of presenting their data. But in reality, I spend a lot of time on the GUI, programming buttons and list views and tree views and the like. This takes time away from the "interesting" problems. I'm hoping that WPF will help me out a bit.

So initially, I want to learn how to lay out a typical engineering app with WPF, figure out some of the graphics functionality, get started with Model-View-ViewModel architecture (because I've heard from my colleagues that this is the way to go when architecting a WPF app), and put together a basic toolbox that I can share with my clients when we start a new app from scratch.

Step 1. Get a book

I want to keep up with the times, and to that end I'm starting to learn Windows Presentation Foundation (WPF).

But first, my UI history. For most of my career I was not a software developer per se, but rather an engineer who spent most of her time developing software tools to get the job done. Most engineers aren't terribly bothered by UIs. They either don't have a strong aesthetic streak or have been beaten down by stingy managers, and will accept a text-based shell interface as long as it spits out numbers that sort of look right.

But so much of engineering is visual, so I always felt that if we're going to display graphical information, we might as well also incorporate a graphical user interface into the software. I always thought that it would be easier to use, and learn how to use, a piece of software if it has a graphical user interface (though in reality, this isn't always the case!). So I took the time to learn how to add a graphical user interface to the software I was developing.

1994 - Started to learn X Windows/Motif. I worked exclusively on Unix systems back then (SGI, Sun, and IBM RISC). I got pretty good at this. I also learned some OpenGL because my work was mostly in computational geometry.

2000 - The place that I worked at took away our SGI workstations, leaving us with PCs running Windows. Our team was forced to learn something new. How cruel. We looked for the closest thing to Motif, which was Win32. I got pretty good at this. I learned GDI, because I was still doing graphical stuff. I also learned the Cosmo VRML library, and learned how to do rudimentary GUIs in MATLAB.

2007 - I came to SRT and was finally forced into the 21st century; I started to do .NET and WinForms development. I've gotten pretty good at it. Along the way, occasionally a customer wants some data plotted on the screen, so I've learned a little Tee-Chart, ZedGraph, and Microsoft's .NET visualization library.

2009 - I am volunteering, yes volunteering, to learn WPF. No one has taken anything away. I don't currently have a client requesting WPF. I'm doing this so I can suggest WPF to clients if it seems appropriate.

So how to learn WPF? On the suggestion of a couple of co-workers, I got the book:

  • Windows Presentation Foundation Unleashed, Adam Nathan, 2007.

It has been a good starting point. I've also found a few series on CodeProject that have been helpful:

Awhile back, when I first wanted to start learning WPF (I was distracted along the way), I read several of the

So now onto the actual learning...

I've been doing some more TeeChart work for a client, and ran into the following two issues. This is actually the second time I have gone through this pain, so I'm writing them down this time in the hopes that they become imprinted on my brain.

NaN values in 3D surface plots

When doing a 2D line plot in TeeChart, you can specify how you want to TeeChart to handle null or NaN values. TeeChart will set the point representing the NaN value to transparent, and will not attempt to draw a line two or from the point.

With 3D surface plots, this functionality is not available. A work-around can be found at:

http://www.teechart.net/support/viewtopic.php?f=4&t=6622&p=25500&hilit=NaN#p25500

Floating point values on the X- and Z-axes

First I must point out that by default, TeeChart's convention is to treat the X- and Z-axes as the independent plot axes, and the Y-axis is the dependent value. The Z-axis is the depth axis (axis into the page). TeeChart by default assumes that your X- and Z-axis values are integer. If you want to use floating point values on these axes, you must set the IrregularGrid property on the series to true. Sure, you can have regularly spaced values along the X- and/or Z-axis, but if they're floating point values, TeeChart thinks of them as irregular :).

What follows is my sad and painful story of a holiday weekend gone bad as I attempted to (i) install an OS that is not quite ready for primetime (Windows 7) and (ii) simultaneously "upgrade" to a 64-bit OS. I'm writing this story because I made a lot of stupid mistakes, and I'm extremely grateful to those who have made stupid mistakes before me and either submitted their questions on forums or blogged about them, thus making it possible for me to find their stories through Google and get my own mistakes corrected. Here's my story, with links included, on the off chance that others stumble upon this story as they go through their own struggles to upgrade.

Why it was time to repave

Over the course of the last several weeks, the laptop that I use for work started to really drag and complain about anything I asked it to do. I don't know if I should blame VMWare Player, but ever since I had installed it to run a VM I needed for a project, blue screens became common. After the project was over I uninstalled it, and while the blue screens went away, I now had a very sluggish machine. Not seeing any other way to fix the problem, I sensed a repave would be necessary.

Not so awful, I thought to myself, given that just about everyone else in my office has installed this brilliant new Windows 7, so I can take this opportunity to try it out for myself. And what's more, those same smart colleagues of mine have been been slowly migrating to the 64-bit OS, so I figured I ought to join the future and go that route as well.

A happy beginning

Over the weekend I began the repave process. On Friday night I did a little spring cleaning on my hard drive, and then backed up all of my files (I found quite a few gigabytes of unneeded junk in the My Documents basement). Given that I don't care for clutter, that process made me feel all warm and happy inside. Then I launched the Windows 7 RC installer and went to bed. When I woke up in the morning, there were blue skies and cute little bird on my desktop. All was good.

Problem 1 - Touchpad driver for 64-bit Windows OS

The first piece of software that I reinstalled was Visual Studio 2008. I had forgotten how much time that requires. But once it was onboard, I opened it up and started to type. And then the cursor started jumping all over the place, spontaneously highlighting text that I would overwrite before I realized what was going on. This bad behavior had me a bit worried. I quickly figured out that the problem was the driver for the laptop touchpad. It took me a lot longer to realize that the problem had to do with the 64-bit OS, and not Windows 7 per se. After many Google search permutations, I found the following forum discussion. The last entry in the discussion put me on the right track. For the record, I have a Dell Latitude D830 with a Synaptics touchpad.

http://www.vistax64.com/vista-hardware-devices/117419-alps-touchpad-drivers-vista-64-bit.html

Problem 2 - SQL Server installation

A rather important project I'm currently working on requires that I have SQL Server Express 2008 and SQL Server Management Studio Express 2008 installed on my machine. This was incredibly time-consuming.

First, it's worth noting that Visual Studio 2008 Professional comes with SQL Server 2005, so it was already installed on my laptop. But I have read that one can have both the 2005 and 2008 flavors of SQL Server running on the same machine, so I thought it wouldn't be a problem to just add 2008. Perhaps there is some magic that can be performed to make this work, but I couldn't figure it out, so after installing 2008, I uninstalled it, uninstalled 2005, and then went back to 2008.

I started by grabbing the 64-bit installers from the Microsoft website. When these are launched, they immediately detect that I need installers for the service pack 1 version. Now why is that when I Google SQL Server 2008, I'm not led to the most recent installer for the product? Well, never mind, at least the old installer knows about the new installer, so another download ensues, and then the install gets underway.

And for whatever reason, the SQL installer has this complex menu of options with tests, and then more tests, and then you install setup files for the actual install.

To save steps, I tried to get the SQL Server 2008 Express with tools, which in theory should have Management Studio included in it, but it doesn't, so you have to find that separately.

Then the installer for Management Studio is confusing, because while I thought I was just adding a feature to an existing SQL Server instance, you have to go through the menus as though you're adding a completely new instance of the server. After what seemed like hours on Saturday evening, I finally got what I needed.

Then I copied over the database for my project, and SQL Server didn't recognize it. Was this a 32-bit to 64-bit conversion problem? I tried all sorts of things, Googled the problem in various ways, but came up with nothing.

I shut down and went to bed in frustration.

In the morning, I started up my laptop, and magically SQL Server worked and the database was right where it was supposed to be and all was good. The lesson here...sometimes you just have to give up and go to bed.

Problem 3 - Tortoise SVN and Tortoise Bazaar

Different projects call for different version control, so I have them both on my machine. Tortoise SVN comes with a clearly marked 64-bit installer, so I installed that. It was a little less clear with Bazaar, but I think I got the right thing. At first I had two copies of the right-click menu items for Bazaar. How bizarre. Tortoise SVN looked just fine, and for both, the little icons appeared to be correct in Windows Explorer. After a reboot, I still had two copies of the Tortoise Bazaar menu items in the right-click menu. After another reboot, there is just one copy of the Tortoise Bazaar items, and none of the Tortoise SVN icons appear in Windows Explorer. I don't know. The issue remains unresolved.

Problem 4 - Printing

My husband thought it would be a quick, fun, and endearing project to get printing to our home printer working. He plugged the printer directly into my laptop to upload the drivers for both printing directly through the USB port, and printing over the network when the printer is plugged into our router, as it usually is. This had worked just fine for him on the 32-bit version of Windows 7 RC. This did not work so well for the 64-bit version. The laptop recognized and installed the drivers, but try as we might, we cannot get it to print over the network. I guess it's not all that important at the moment; and I still love my husband for trying.

Problem 5 - Configuring IIS

I serve up a website I'm working on locally, so I had to get IIS configured and working. This was a royal pain in the neck!

After I added my site as an application in IIS, I tried browsing to it and got the following error:

Login failed for user 'IIS APPPOOL\Classic .NET AppPool'.

I had to Google this one, and found this helpful forum, even if it's in a language I don't know.

http://www.codetoday.net/default.aspx?g=posts&t=1595

As it turns out, in IIS 7.5, which is what Windows 7 ships with, there are two configured AppPools, one in the IIS 7 default managed pipeline mode, and the other in the classic managed pipeline mode. Both default to a virtual identity that is named after the name of the application pool, rather than LocalService, as was done in earlier versions of IIS. So if you're running a website out of these application pools and the site connects to a database, you either have to set up a special user account for them, or change the identity on the application pools to LocalService. The latter seemed the easier option in my case.

The website is built on 32-bit AspDotNet Storefront. In order for it to work on a 64-bit OS, one has to set up ASP.NET to work in 32-bit mode. This requires following the directions on this page:

https://support.aspdotnetstorefront.com/index.php?_m=knowledgebase&_a=viewarticle&kbarticleid=140

It doesn't mention it in the article, but you need to run the DOS command window in administrative mode for the instructions to work. Perhaps this is obvious to everyone else in the world, but it wasn't obvious to me. My coworkers pointed out that running as administrator is not the same thing as running in administrative mode.

Finally, the website appeared in browser - only the style sheets weren't applied. Argh! This one was a bit strange. To turn on IIS, I go to the Control Panel, select Programs, then select Turn Windows features on or off. Apparently when I enabled IIS, under World Wide Web Services / Common HTTP Features, I neglected to select Static Content. I don't recall going into the Common HTTP Features hierarchy, which would imply that Static Content is not selected by default. Sure enough, when I Googled "IIS 7 css not loading", I found this forum, which set me straight:

http://stackoverflow.com/questions/800500/iis-7-0-with-pipeline-mode-integrated-doesn180t-load-any-image-css-in-asp-n

Problem 6 - Windows Live Writer and Community Server

I wanted to write up this blog post using Windows Live Writer, as I always have before this upgrade adventure began. However, I have been unable to get WLW to connect to my blog, which is hosted by a Community Server site. I haven't been able to resolve this issue yet. Instead, I switched over to my home Mac and I'm using MarsEdit.

Conclusions

It's definitely too soon to say that things are back to normal for me. After all, I've been running Windows 7 in 64-bit mode for less than a week. And I have yet to do any actual work with it. I'm exhausted just from the initial install and setup.

In hindsight, I think it was too ambitious to make the jump to both Windows 7 and 64-bit. Either one of them by itself has issues, so upgrading both at once confounds those issues and make sorting them out take quite a bit longer.

But then again, that which doesn't kill us makes us stronger, right? I feel like I'm going to be the world's most case-hardened software developer after this is over.

Several of us at SRT have formed a study group to better learn the .NET framework. Our eventual goal is to take the MCTS 70-536 certification exam. One area of .NET that has caused us some confusion is Code Access Security (CAS). This is my attempt to sort out two of the concepts associate with CAS that have been rattling around in my brain.

Signatures and Certificates

What does it mean to sign an assembly? This means giving the assembly a strong name. When strong-naming an assembly, a hash is computed for the assembly, the hash is encrypted with a private key, and the encrypted hash and the public key are stored in the assembly, forming part of the assembly signature. Now when the CLR loads the assembly, it decrypts the hash using the public key, computes a second hash for the assembly, and then checks to make sure the two hashes are the same. If they are, we can assume that the assembly has not been tampered with. If the public key is bundled with information about who is issuing it and verification provided by a third party that certifies the key really belongs to that person or organization, then it's called a public key certificate. The confusing part is that an assembly that contains a public key certificate is said to be digitally signed. In CAS, I can set up a code group that looks for Publisher Evidence, or the digital signature on an assembly, and based on the value of the digital signature grant certain permissions.

Strong Name Hash and Hash Evidence

I'm not the first person to wonder about the difference between the two of these. See this blog post for a nice technical discussion. As I described in the above section, the strong name for an assembly contains an encrypted hash. That's the strong name hash. It's different from a general hash for an assembly because a general hash makes use of every single bit in the assembly when it is computed, whereas the strong name hash skips certain parts of the assembly. In CAS, I can set up a code group that looks for Hash Evidence in order to grant certain permissions to an assembly. Hash evidence is a general hash computed for the assembly, not the strong name hash. The problem with hash evidence is that every time I recompile an assembly, it will have a different hash value. Therefore, hash evidence is primarily used to grant permissions to a specific build of an assembly.
with no comments
Filed under: ,

I'm really happy to finally be trying out MATLAB's objected oriented features that first appeared in release 2008a. What a treat to finally be able to prototype algorithms and write tools for clients using a paradigm that comes very naturally to so many software developers. Also, it's a lot easier to bridge the gap between scientific and engineering algorithm inventors and software developers when each party's code looks similar to the other's.

Here are some introductions to object oriented MATALB:

Information from The MathWorks

An article by a MATLAB user 

Here's a sample class that I assembled today from several scripts that I have for a single project. The Apply, Plot, and CreateFromConstantValueSignalFiles methods had previously been standalone .m files. Now they are grouped together as they should be in the PolyTransform class. This makes me so much happier! Thanks, MATLAB!!

classdef PolyTransform

    properties
        coeffs
        degree
    end

    methods

        % Constructor
        function obj = PolyTransform(degree, coeffs)
            obj.degree = degree;
            obj.coeffs = coeffs;
        end

        % Other methods
        function signal2 = Apply(obj, signal)
            signal2 = Signal(signal.time, polyval(obj.coeffs, signal.response));
        end

        function Plot(obj, xx, yy)
            testx = min(xx):0.01:max(xx);
            testy = polyval(obj.coeffs, testx);
            figure();
            cla
            hold on
            plot(xx, yy, 'bo');
            plot(testx, testy, 'g-');
        end

    end

    methods (Static)

        function obj = CreateFromConstantValueSignalFiles(degree, ndiameters, diameters, basicFileName)

            averageValue = zeros(degree, 1);

            for ii = 1:ndiameters
                % Load in noise file
                fileName = strcat(basicFileName, num2str(ii-1), '.bin');
                signals = Signal.LoadFromNoiseFile(fileName);

                % Get average value
                averageValue(ii) = signals(1).Average();
            end

            coeffs = polyfit(averageValue, diameters, degree);

            obj = PolyTransform(degree, coeffs);
            obj.Plot(averageValue, diameters);

        end
    end

end
with 2 comment(s)
Filed under:
I recently rediscovered an article my father sent to me from a radiology journal that emphasizes the importance of individual creativity and perseverance when it comes to scientific and technological discoveries. The author's primary point is as relevant to computer science and engineering as it is to radiology:
Advances may come from a single individual -- often young, often working alone, often with limited resources, often not at what's considered a premier institution -- who perseveres in the face of the conventional wisdom. It's the idea that counts. (Meyers, M. A.; American Journal of Roentgenology, March 2008, pp. 561-564.)
The author gives lots of humorous examples from medicine in which the establishment initially rejected history-changing breakthroughs such as the discovery of X-rays and the bacterium that causes peptic ulcers. To me, the article was a reminder that what companies and universities can best do to foster innovation is to provide us with the time and space in which to explore new ideas. SRT does this by giving all of its employees time each week for learning and exploration. They make it a part of the job description and review process, to make sure that we take our RECESS time (as one of my colleagues calls it) seriously. We don't always need a big budget to come up with something new and cool (as the computer industry has proven time and time again), but an environment that encourages discovery and learning definitely does help.
Awhile back I solved Euler problem 13, and then today I took a look at problem 16 and noticed that it's very similar. Problem 13 asks us to find the first 10 digits of the sum of 100 50-digit numbers. The first thing one notes immediately is that you can't store a 50 digit number with a long int in MATLAB; it needs to be stored as a string. So, provided that I've stored the specific 100 numbers that Project Euler wants me to add in a string array called bigNumbers, I can solve the problem with the following line of code:
sum(str2num(bigNumbers))
The str2num MATLAB built-in function converts a string to a numerical value. The sum function takes care of the rest. Problem 16 challenges us to sum the digits in the number 2^1000. Once again, one line of MATALB does the trick:
sum(str2num(num2str(2^1000)'))
In this case I convert the large number (2^1000) to a character array (using num2str), transpose the array so I can treat each digit individually, then convert back to a numerical value and compute the sum.

Awhile back I wrote part 1 of a series on design optimization. At long last here is Part 2.

As a quick review, design optimization is a mathematical process that we can use to (i) describe a system in terms of mathematical variables, (ii) change the values of the variables in order to explore different system configurations, and (iii) find the values of the variables that give us the "best" system. Design optimization can be applied to many different kinds of systems. If you can model your system with mathematical equations, then most likely you can apply design optimization to it. For instance, mathematical equations can be used to model the flow of a fluid such as water in a series of interconnected pipes. Design optimization can be used to find the best size for each pipe in order to minimize the cost of the pipes, but still move the the fluid through the system without backups or ruptures.

In part 1 of this series, I introduced the key concepts in modeling a system: our system is defined in terms of variables, the system must satisfy certain constraints, and we are trying to minimize an objective function. Usually design optimization problems are written like this:

Optimization problem formulation

Note that we group the design variables into a vector x. One thing I didn't mention in Part 1 about the design variables is that they are generally assumed to be real-valued, which is indicated in the last line of figure above.

Once we've described our optimization problem using mathematical equations, the question becomes, "How do we find the value of x that results in the best design?" The basic idea is that we start with some arbitrary value, called xi, and then we use a systematic way of tweaking that value to get xi+1. Ideally, our objective function evaluated at xi+1 will be less than at xi, or f(xi+1) < f(xi). Following the design algorithm, we would have a series of values x1, x2, ... , xn, and corresponding series f(x1) > f(x2) > ... > f(xn), with xn being the optimal point. Schematically, it would look like this:

image

At this point, two questions must be answered: (1) What goes on in the "Do some math" box? And (2) how do we know when to stop iterating?

I'll answer the second question first. There are several different stopping criteria that are used in design optimization practice. One of the most common is to stop if the the objective function doesn't change very much between xi and xi+1, i.e. if:

image

This works if as we approach the optimal point we take smaller and smaller steps. Another approach is to stop if we reach some predetermined maximum number of iterations, i.e. if:

n >= max_iterations.

There are other criteria, especially depending on the optimization algorithm that is used, but the ones shown above are fairly common.

But back to question 1, what goes on inside the black box? This is where most of the work in design optimization takes place: designing and tweaking the optimization algorithm. The type of algorithm that is used depends on the type of design variables - whether they are continuous or discrete; the type of constraints - whether they are linear or non-linear; and the objective function - can derivatives be computed or not.

To give you an idea of the variety of optimization algorithms that are available to choose from, take a look at Wikipedia's summary on the topic. It lists 89 different algorithms. Some are fairly exotic and used in highly specialized situations. Others are more general purpose and are the workhorses of the design optimization community. In my next installment, I'll talk about some of the commonly used algorithms, going over the basic idea behind them and in what scenarios they can be applied.

I use the charting library TeeChart from Steema for one of my clients. This library is large and rambling, uses non-conventional naming schemes, and lacks good documentation. On the other hand, it does allow the user to do some very nice things with plots, if she can figure out how to do them. It wouldn't be my first choice for a plotting library, but the client has it and has asked me to use it, so use it I will.

In TeeChart, one adds to data to a chart in the form of a series. There are all sorts of useful, predefined series to choose from, but the most basic is a Line series. I add (x,y) points to the Line series, and when plotted, those points are connected with a straight line. By default, TeeChart sorts the points on the x-value, which for time series data makes sense. But for a lot of my work, I'm plotting generalized 2D paths, so it is imperative that the points maintain the ordering that I assign to them. To turn off sorting for a TeeChart Line series, use the following:

Steema.TeeChart.Styles.Line dataSeries = new Steema.TeeChart.Styles.Lines();

dataSeries.XValues.Order = Steema.TeeChart.Styles.ValueListOrder.None; dataSeries.YValues.Order = Steema.TeeChart.Styles.ValueListOrder.None;

If you want your points to automatically be sorted on the y-value, then use the HorizLine series.

That problem I was able to solve after searching on Google and the Steema forums. The next two problems have been trickier.

First, I want to be able to reposition an axis Title. ("Title" is the Steema terminology; to me it should be called an axis label, but they use "Label" to mean the labels associated with axis tick marks.) By default the axis title is centered on the axis. I'd like to be able to move it along the axis because if I've positioned my axis so that it is not at the edge of the plot (e.g. if I have the axis at the center of the plot), then the data that I'm plotting might sit right on top of the axis label. According to Steema, Titles cannot be repositioned, so I'm supposed to use Annotations and work out their position based on the position of the axis and the size of its tick marks. Seems like a big pain, if you ask me!

My second problem is the color that is automatically assigned to a series. TeeChart has 11 built in color palettes, and to switch between them you do the following:

Steema.TeeChart.TChart chart;
int paletteIndex;

chart.Aspect.ColorPaletteIndex = paletteIndex;

I've also seen it done this way:

Steema.TeeChart.Themes.ColorPalettes.ApplyPalette(chart, paletteIndex);

Then when series are added to the chart, each one is assigned the next color in the palette (there seems to be about 15-20 colors in each palette). But when you get to the end of the palette, every new series gets the last color in the palette. The indexer doesn't seem to wrap around back to the start of palette. To work around this, I wrote my own code to rotate through a list of colors, and I manually set the series color each time I add a new series, using code like this:

dataSeries.Color = GetColor();

static int colorIndex = 0;

private static System.Drawing.Color GetColor()
{
    ++colorIndex;
    if (colorIndex > 3)
        colorIndex = 0;

    switch (colorIndex)
    {
        case 0:
            return System.Drawing.Color.Red;
        case 1:
            return System.Drawing.Color.Blue;
        case 2:
            return System.Drawing.Color.Green;
    }

    return System.Drawing.Color.Black;
}

This solution is fine, but seems like it should be unnecessary!

Currently I'm working on three different projects, and the one common component of all three is that they involve design optimization. Design optimization can be used in any discipline to find the "best" design for a particular system (the definition of "best" will vary from discipline to discipline, from system to system, and from one situation to another). Methodical, mathematic approaches to design optimization have been developed over the past 50 years, and their practical implementation, especially for large problems, has been made possible through the use of computers. A basic understanding of optimization is a good thing for software developers to have, especially those who are writing scientific and technical tools. This post is part one of a short primer on design optimization. I perused the book Principles of Optimal Design: Modeling and Computation by Panos Papalambros and Douglass Wilde before writing this, so their influence cannot be escaped.

Any system that can be modeled mathematically can be optimized. This means that disciplines as varied as engineering, physics, chemistry, biology, statistics, economics, finance, and others can make use of design optimization. Within engineering, systems such as automotive engines, building structures, HVAC systems, integrated circuits, etc. can be optimized. Two very simple systems that could be optimized are shown below. The first is a collection of 2D data points that are to be described by quadratic polynomial (a parabola). The second is a cantilevered beam that has a load applied at its tip. Different aspects of the beam can be described with mathematical equations, such as the geometry of the beam, the loading along the length of the beam, and the stresses in the beam at an point within it.

image

The next requirement for a design optimization problem is to identify a set of variables that describe design alternatives. These are parameters that the designer has control over, things that can be changed during the design process. For our data fitting problem above, the design variables would be the coefficients in the polynomial; the engineer can tweak their values to modify how the polynomial fits the data point. For the cantilevered beam problem, the designer has control over the length, height, and width of the beam (additionally, the beam material could be a design variable, but for this example we'll say that the material choice has been predetermined and the designer cannot change it).

image

Now we need to choose an objective function, expressed in terms of the design variables, that should be minimized. The objective function is frequently called a cost function. Note that if you ask any manager of a design optimization project what it is they are trying to minimize, they will say cost! It's up to the designers (and managers) to figure out what contributes to system cost and express it mathematically. In our beam example, clearly the larger the beam is, the more it will cost. But the beam has to perform a function, such as support a floor in a building, and therefore we can't minimize the size of the beam. Instead, a more typical objective would be to minimize beam deflection at its tip (if this beam is indeed supporting a floor in a building, it will make the building occupants feel a lot better if the floor doesn't sag when they walk over it). For our data fitting problem, the objective is to find the polynomial that best fits the data. A typical way of measuring the fit is to sum the squares of the distance of the given data points to the polynomial.

 image

Designers next need to identify a set of constraints, expressed in terms of the design variables, that must be satisfied in order for their system to be valid. These can be practical limits on design variables, or more complicated relationships that describe the function of the system. For instance, in our data fitting problem, perhaps we want to ensure that the peak of our parabola is at x greater than some value d. Typical constraints for a beam design problem might be that the material properties are fixed because a certain material has been selected, or the stresses need to be below the limits of the material.

image

Now we have a complete specification for our design optimization problem: variables, objective function, and constraints. The formal way of expressing an optimization problem is:

minimize f(x)
s.t. (subject to)
g(x) < 0
h(x) = 0

The final step is to solve the problem, which is of course easier said than done! I will discuss this in the next installment.

But before I close, I want to point out that modeling a system using mathematical equations can itself be a challenging problem. In engineering, we spend much of our bachelors degree education learning how to do this, and it's something that doesn't always come easily, even to seasoned practitioners.

Since I'm new to this blogging thing, it has taken me awhile to figure out what tools to use to make writing and publishing posts easy to do. After reading what others have to say on the topic, and talking to my co-workers at SRT, I have hit upon Windows Live Writer with the Code Snippet plugin. But it hasn't been straightforward getting these tools to cooperate with Community Server 2007.1, the server SRT uses for blogs. Here are two tricks to make things work right.

Windows Live Writer makes writing a post and including things such as images and videos and bits of code very easy. One of the big advantages is that it can go to your blog site and grab your template, so that as you compose your post you can see just what it will look like when it is published. I could have used that feature when I wrote my last post on ZedGraph and made the images too wide for the main text column. To get the template, WLW creates a temporary post, publishes it to the server, then goes to that post and downloads the CSS. Seems straightforward...except that it failed the first and second and third and fourth times I asked it to do this. Then I went searching for a solution. What I figured out is that in Community Server Dashboard, under Global Settings -> Default Post Settings, there is an option called "Auto Name Posts". If set to "Yes", CS tries to name each post based on the title, rather than use the de facto standard blog post naming convention, which is based on the date the post was created. After I disabled this option, WLW successfully located its post and downloaded my template to my local machine. Success!

My second problem that I've been struggling with is coming up with a quick and easy way to insert formatted, colored code into posts. Before I had WLW, I would cut and paste code and then go and manually add <div> and <span> tags with with embedded CSS styles using the horrible Community Server interface with the TinyMCE editor. Death seemed preferable. If I specified colors like this:

<span style="color: blue;">

things worked just fine. I would get blue text. But if instead I specified:

<span style="color: #0000FF;">

then the TinyMCE editor would modify the tag to look like this:

<span style="color: rgb(0,0,255);">, which would then turn into:

<span>

by the time it was published. I would not get blue text. Argh!

By using WLW with the Code Snippet plugin, as long as I never open up the post in the TinyMCE editor before it's published, everything is fine and my span tags with their color styles are left untouched. Stay away from TinyMCE!

I haven't worked out all of my blog problems just yet. For instance, Code Snippet supports C# code, but not Matlab. But I got two big problems solved, so I will declare success for the moment.

Previously I wrote about choosing ZedGraph as my graphing tool in a C#.Net project for a client. Today I'd like to give an update on how it's going. I have been very pleased with this graphing library, and it has been relatively straightforward to figure out how to make it do what I want it to do.

I'm plotting X-Y data that represents the shape of an airfoil on a 2D plot with grid lines, axes, and axes labels. One of my main concerns was having the ability to force the scales of the X and Y axes to be the same value. If they are locked, my plot will show the airfoil with the right proportions. If not, the airfoil appears to be a lot fatter than it really is.

Figure 1. Airfoil with axis scales locked

airfoil_with_axes_locked

 

Figure 2. Airfoil with axis scales determined independently of one another

airfoil_with_axes_unlocked

 

The ZedGraph library comes with a ZedGraph control, which contains of a collection of one or more GraphPane objects. The GraphPane holds all of the plotting information for a single plot, including settings and options in addition to the actual plotting data. For my particular problem I only need one GraphPane, which is the default. My first step is to initialize my GraphPane object.

public MainForm()
{
InitializeComponent();

// Initialize ZedGraph
GraphPane graphPane = zedGraphControl1.GraphPane;
graphPane.XAxis.Title.Text = "Chord";
graphPane.YAxis.Title.Text = "Thickness";
graphPane.XAxis.MajorGrid.IsVisible = true;
graphPane.YAxis.MajorGrid.IsVisible = true;
graphPane.Legend.IsVisible = false;
graphPane.Title.IsVisible = false;
//graphPane.Title.Text = "ZedGraph";
zedGraphControl1.Resize += new System.EventHandler(this.zedGraphControl1_Resize);
graphPane.AxisChangeEvent += new GraphPane.AxisChangeEventHandler(graphPane_AxisChangeEvent);

}

The key here is the last line of initialization, where I add an event handler for the AxisChangeEvent. This event is invoked by calling the AxisChange() method in the ZedGraphControl object. One generally calls this method whenever new plotting data is added to a GraphPane; it takes care of adjusting the minimum and maximum axes values and the grid spacing. AxisChangeEvents are also generated whenever the user zooms or pans a GraphPane. It is not invoked, however, when the user resizes the ZedGraphControl, so I added an event handler for the Resize event that calls the AxisChange() method. The Resize event handler looks like this:

private void zedGraphControl1_Resize(object sender, EventArgs e)
{
zedGraphControl1.AxisChange();
}

The AxisChange event handler is called after the the ZedGraphControl has recomputed the minimum and maximum axis values and the grid spacing. It adjusts the minimum and maximum values so that the scale in the X and Y directions are equal, and then it recomputes the grid spacing to ensure that the grid does not have too many or too few lines.

private void graphPane_AxisChangeEvent(GraphPane target)
{
GraphPane graphPane = zedGraphControl1.GraphPane;

// Correct the scale so that the two axes are 1:1 aspect ratio
double scalex2 = (graphPane.XAxis.Scale.Max - graphPane.XAxis.Scale.Min) / graphPane.Rect.Width;
double scaley2 = (graphPane.YAxis.Scale.Max - graphPane.YAxis.Scale.Min) / graphPane.Rect.Height;
if (scalex2 > scaley2)
{
double diff = graphPane.YAxis.Scale.Max - graphPane.YAxis.Scale.Min;
double new_diff = graphPane.Rect.Height * scalex2;
graphPane.YAxis.Scale.Min -= (new_diff - diff) / 2.0;
graphPane.YAxis.Scale.Max += (new_diff - diff) / 2.0;
}
else if (scaley2 > scalex2)
{
double diff = graphPane.XAxis.Scale.Max - graphPane.XAxis.Scale.Min;
double new_diff = graphPane.Rect.Width * scaley2;
graphPane.XAxis.Scale.Min -= (new_diff - diff) / 2.0;
graphPane.XAxis.Scale.Max += (new_diff - diff) / 2.0;
}

// Recompute the grid lines
float scaleFactor = graphPane.CalcScaleFactor();
Graphics g = zedGraphControl1.CreateGraphics();
graphPane.XAxis.Scale.PickScale(graphPane, g, scaleFactor);
graphPane.YAxis.Scale.PickScale(graphPane, g, scaleFactor);
}

Having the ZedGraph source control was extremely useful in figuring all of this out, particularly for resizing the grid after I have adjust the minimum and maximum axes values. In the end, I did not need to modify any of the ZedGraph source code, but because it is fairly clean and readable, I was able to use it in place of documentation when I needed more explanation than what was provided in the basic tutorial and class descriptions.

So I still feel good about ZedGraph, and my customer is happy, too!

I'm on vacation this week in northern Michigan, enjoying the good weather and time with my family, and also reading quite a bit, including a book called Beautiful Code published by O'Reilly (more about that in another post). One chapter in particular got me fired up to revisit Euler Problem 14, which I started to work on back in May, but got stuck and have been thinking about it ever since.

The problem goes like this:

The following iterative sequence is defined for the set of positive integers:
 
n -> n/2 (n is even)
n -> 3n + 1 (n is odd)

Using the rule above and starting with 13, we generate the following sequence:
13 40 20 10 5 16 8 4 2 1

It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

Which starting number, under one million, produces the longest chain?

I'm solving the Euler problems in Matlab, and I'm working on a 867 MHz Mac PowerBook G4. Sometimes I also limit myself to the time it takes to drain the battery, just so that I don't end up spending days and days solving a problem (I have to work once in awhile, and my kids get upset if I ignore them too much :). So my goal is generally to come up with a fast solution, which in most cases rules out brute force.

With these goals in mind, I thought and thought and thought and thought about this problem, trying to come up with a trick that would allow me to rule out most numbers between 1 and 1,000,000. The most obvious thing to try is only the odd numbers. But I wanted to winnow down my search set even further. Not coming up with anything, I gave up and abandoned Euler problems altogether. I had plenty of other things to work on. But this problem kept gnawing at the edges of my brain.

With so many problems in life, sometimes it's best to stop thinking and start doing. So finally this week I threw in the towel and wrote some code to do a brute force search on all odd numbers. It definitely occured to me that once a sequence has been generated for a number, when that number shows up in a subsequent sequence I should reuse what has already been computed. But I got hung up in figuring out how big I should preallocate my array to store the sequence count for each integer, so I even left off that. I just wrote a loop that computes the sequence for every number.

Imagine my surprise when it took only about 15 or 20 minutes to run!

Sometimes brute force isn't so bad. Sometimes the only way to know is to try it.

Here's my code:

function euler14

max_count = 0;
max_nn = 1;
for nn = 3:2:1000000

    new_nn = nn;
    count = 0;

    while new_nn ~= 1
        if mod(new_nn,2) == 0
            new_nn = new_nn/2;
        else
            new_nn = new_nn*3+1;
        end
        count = count + 1;
    end

    if count > max_count
        max_count = count;
        max_nn = nn;
    end

    disp([num2str(nn), ': ', num2str(count)]);
end

disp(['Max: ', num2str(max_count), ' for nn = ', num2str(max_nn)]);

In the past year I've worked on two projects that involved piecing through someone else's Matlab code, making sense of it, making it work, and figuring out how to link to it from a Windows desktop application. In both cases, it was clear that the Matlab had been writen by someone who does not normally spend a lot of time writing code. All of the tenets that we developers hold sacred had been broken: global variables abounded; code was copied over and over; large sections of code were commented out for no apparent reason; and in one of the projects, functions were dispensed with all together in favor of scripts, which often relied on variables that had been declared and set elsewhere in another script. In both cases the original author of the code was not available to explain how things were supposed to work, so fixing the code was a lengthy, tedious process.

It got me wondering...why do engineers write bad Matlab code? Most engineers have had at least one programming course in college, and presumably in that course they are taught how to organize code, declare functions, and pass arguements. Now granted, some people have a harder time than others in figuring out a good architecture for a project. But my observation is that engineers writing Matlab seem to have an aversion to declaring functions. They would rather copy and paste code 20 times than make that code into a function.

And then, as I was working on my most recent Matlab project, it occurred to me what the problem is. When I write C# or C++ code with Microsoft Visual Studio 2005 or 2008, I have IntelliSense, which is a godsend because I can never remember the order in which arguements are supposed to be passed to a function. Matlab does not have anything like IntelliSense, and it has lots and lots of functions, most of them overloaded or with a variable number of arguments. I can't be the only scatter-brained engineer out there who has trouble keeping track of all of my options.

So this blog post is really a plea to The MathWorks folks - give us IntelliSense!

At a minimum, I'd be happy if there were a window that I could have open that would automatically show me the help file for a function as I type its name into an M-file. This would be similar to the context-sensitive help that's available in Labview, another engineering tool that has lots and lots of functions that are hard (for me) to keep track of.

More Posts Next page »