Don’t be the MATLAB guy.

Occasionally I’m asked if I “know” MATLAB. My former company had two licenses for MATLAB, and my development machine was one of the two computers with a license installed.

You see, the last guy that owned my work computer was a Ph.D. HE knew MATLAB. The guy was also clearly into math, and he developed his own field of study. I would name drop the guy, but he’s moved on to another company now, and I don’t know how he would feel about his good name associated with my blog. He teaches at a University, and he’s a cool guy, rest assured. By pure virtue of having one of the only two company licenses, however, I was subject to the periodic question of “Hey, Lee, can you do this in MATLAB for me?” to which I’d yield only a forlorn rejoinder of “Please… tell I.T. to move this license off of my machine.”

My company was paying money for a license that I, nor anyone else, was using. I was forced to shoo people away over this. I.T. eventually transferred the license, but that didn’t happen for four years. Lately, I’ve been getting back into pure math, and the irony of all of this is now that I have a spare moment actually to investigate math tools, I wish I still had a copy! Such is life it seems.

So I’m glad that in the year 2018, we, collectively as the human race, have figured out all of this math stuff. Students have across the world ceased deforesting the planet with failed math equations on notebook paper. Now, all around the globe, pupils have ended merely assimilating skill by rote but instead have forged ahead by applying learned concepts to problems which have decidedly resulted in a greater general understanding of the underlying fundamental mathematical principals civilizations have long sought to know. Long abandoned are the ancient ways of having every formula, equation, or neat trick named after a person, and instead, these devices are now designated by which service they perform. Finally, mathematicians, encouraged by the struggles of their predecessors, have taken a page from Gutenberg and decided to localize their sacred tomes in languages for mass consumption with their mortal progeny foremost in due consideration.

Or it’s remained being the Greek tragedy it has always has been.

Think about it for a second. Mathematics changes, but not by THAT much, and not every year. Couldn’t it be made just a little easier? I guess that this is what this post is all about. In the decade since I graduated college, and joined the world of applied computer science, is there anything that will make math a little easier?

Every programmer starts with a “Hello World” program, and I wanted this to be no exception. I figured my “Hello World” evaluation for a purely math solving program should complete the following:

  1. Calculate two single variable functions (compound interest formula, the second function should intersect with the first at some point)
    1. f(x) = 30000*(1.1)^x
    2. f(x) = 40000*(1.05)^x
  2. Find the intersection of these functions
    1. The intersection point should be a decimal number
  3. Display the results
    1. Text or graph, either is fine.

Stupidly simple, I know, but that was the point. As it turns out, it wasn’t so stupidly simple.

WOLFRAM ALPHA

Oh, Wolfram, you get me.

I type:

30000*(1.1)^x  and 40000*(1.05)^x

And it barks at me to use “|” instead of “and.” When I do that it produces a very nice graph:

By clicking the “plain text” button, I get Wolfram’s formula:

Plot[{30000 1.1^x, 40000 1.05^x}, {x, -12, 12}]

After some digging on how to obtain intersection points, I find that I can use the following code:

Intersection points of [//math:30000 1.1^x//] and [//math:40000 1.05^x//]

And that yields this:


By clicking the Result itself, I get a decimal approximation:  6.184049350060875

I probably spent 20 minutes doing this. Most of those twenty minutes was figuring out how to dump out intersections. So far everything is almost in English. I gave it a bunch of commands, I was prompted to fix certain things, I did so, and it gave me an answer. With Graphs! Cool!

So far I’m feeling this whole math thing again. I wished it was this easy when I was in college in my 20’s, not going to lie.

SAGEMATH

I honestly thought that this was going to be a lot easier than it was. I wrote a blog post with code for a price analysis of running my Git server. It was that post that inspired me to write this one.

The code I started with modified from my other post:

x = var('x')

f1 = 30000*1.1^x
f2 = 40000*1.05^x

p1 = plot(f1, (0,8), color="red", legend_label='Function 1')
p2 = plot(f2, (0,8), color="blue", legend_label='Function 2')

i1=solve(f1==f2,x)

print 'Intersection of f1', f1
print 'and f2', f2
print i1[0].rhs().n()
sect1 = i1[0].rhs().n()

pt1 = point((sect1,f2(x=sect1)), color="purple")

t1 = text(sect1.n(digits=6),(sect1,f2(x=sect1) + 10), color="black")

g = plot(p1+p2+pt1+t1)

save(g,'hello_world.png',axes=true) 

os.system('display hello_world.png')

to run it, I saved off this text to a file and called:

~/Desktop/sage$ sage hello_world.sage

But it didn’t work. I should have gotten a pretty graph, and an answer in the terminal window, but instead I got this error:

Intersection of f1 30000*1.10000000000000^x
and f2 40000*1.05000000000000^x
Traceback (most recent call last):
  File "hello_world.sage.py", line 18, in <module>
    print i1[_sage_const_0 ].rhs().n()
  File "sage/structure/element.pyx", line 863, in sage.structure.element.Element.n (build/cythonized/sage/structure/element.c:8004)
  File "sage/symbolic/expression.pyx", line 5784, in sage.symbolic.expression.Expression.numerical_approx (build/cythonized/sage/symbolic/expression.cpp:36107)
TypeError: cannot evaluate symbolic expression numerically

I couldn’t find much documentation out there, and after about 4 or 5 hours of trying, I decided that this was a problem that should be so simple I should be laughed at for even asking what I’m doing wrong. So I asked.

Sure enough, I did get an answer. And frankly, it was a great answer too. But man, I was not expecting to be accused of cheating on my homework, and then be cursed with pox should I be some unscrupulous student trying to pull a fast one.

Anyway, with my final code ready, I could finally produce a result.

x = var('x')

f1 = 30000*1.1^x
f2 = 40000*1.05^x

p1 = plot(f1, (0,8), color="red", legend_label='Function 1')
p2 = plot(f2, (0,8), color="blue", legend_label='Function 2')

i1=f1==f2
n1=i1.log().expand_log().solve(x)

print 'Intersection of f1', f1
print 'and f2', f2
print n1
sect1 = n1[0].rhs().n()

pt1 = point((sect1,f2(x=sect1)), color="purple")

t1 = text(sect1.n(digits=6),(sect1,f2(x=sect1) - 1000), color="black")

g = plot(p1+p2+pt1+t1)

save(g,'hello_world.png',axes=true) 

os.system('display hello_world.png')

And this produces:


I love the graphs that SageMath produces, but considering how much of a pain it was to get intersections, I think I’m going to pass on SageMath for future work.

Here’s why:

  • I can’t get consistent output from one project to the next using non-python scripts
  • The documentation assumes that learning SageMath is my job
  • Despite there being a SageMath script language you can use for pure math, people assume you’re using Python
  • Even though I got a fantastic answer to my very simple question, I’m probably cursed for the foreseeable future.

Oh well. I was hoping that SageMath was going to be the one. I like making sage files with my editor of choice, and the graphs it produces are astounding.

GNU OCTAVE

At this point, I was running out of steam. From everything, I read GNU Octave was almost a direct MATLAB replacement. While using it, I found that I was hitting MATLAB help sites to find answers. Alas, there’s always a catch.

Setting up Octave was a bit of a pain. I just assumed that being able to support symbols (read variables) was going to be a thing that just came with it. So even getting the first few lines working was a bit of a hassle.

%package stuff
pkg load symbolic

%actual math
syms x real
x = sym("x");

f1 = @(x) 30000*(1.1)^x
f2 = @(x) 40000*(1.05)^x

idx=simplify(solve(f1(x)==f2(x)))

%graph stuff
x_pos = double (idx)
y_pos = f1(double (idx))

disp ("The intersection is:"), disp (double (idx))
font_sz = 12
ezp1 = ezplot(f1(x), [0,9])
set(ezp1,'LineWidth',6);
hold on
ezp2 = ezplot(f2(x), [0,9])
set(ezp2,'LineWidth',6);
hold on
plot (x_pos, y_pos, ".", "markersize", 50)
hold on
t1 = text(x_pos, y_pos - 2000,num2str(x_pos))
set(t1, 'FontSize',font_sz)
hold on
set(gca,'FontSize',20)
title('Hello World', 'FontSize', font_sz)
grid on
xlabel ("X Axis", 'FontSize', font_sz);
ylabel ("Y Axis", 'FontSize', font_sz);
lgd = legend('Function 1 10%','Function 2 5%', 'Intersection Point');
set(lgd,'FontSize',font_sz);

I only needed the first five lines of code to get what I wanted, but in a vain attempt, I tried to make a graph. The problem I faced is that my laptop’s monitor is in “high DPI mode” which means the lines that my chart was producing were too small. When I exported my graph as a PDF, they started to look a bit ridiculous as can be seen:

Overall, I enjoyed working with Octave despite spending way too much time trying to get the graph to work correctly.

SUMMARY

Has actually doing math gotten easier? Yes. Absolutely. I wish I had these tools ten years ago. You can see the results of your trainwreck equations immediately. In many ways, it’s pretty much just programming now. Heck, despite me knocking SageMath a bit, I think it’s impressive that it’s already in Python and can merge math code into whatever program you’re working on. I find reading code versions of math functions is much more understandable than the Greek and LaTeX crap they throw at students in universities. Poor kids.

Anyway, don’t be the MATLAB guy. You’ll end up with a license, and you’ll be too busy even to be able to do anything with it. Then when you try to hand-off your floating license to your coworkers, they don’t want it because in reality they just wanted you to make pretty graphs for them.

Download free software, play around with math, practice concepts, and don’t get caught.

Tagged ,