Wednesday, May 29, 2013

Lloyd's (Hypothetical) Math Fair Contest Entry

You can tell from the title that I didn't actually submit this idea to any math fair. But, I think imagining a math and science fair is the right mindset for this blog posting. I really like the idea of giving the power of computer programming to students to explore topics that would be most suitable as entries into a math and science fair. Remember that there is a free edition of LiveCode available, so I hope many teachers will choose to begin offering this powerful computer programming environment to their students. Consider this blog posting as an example of what a student might do with such a powerful analytic and computational tool.

Like most people, I often dream of prime numbers. Actually, no, I'm not that geeky. However, I have been reading and viewing lots of stuff related to calculus lately. I do this from time to time. I get back into the most challenging mathematics I have ever tried to see if I can understand again some of the stuff I supposedly once learned, plus make some new personal advances. (Despite my love of mathematics, I'm honestly not that good at it.)

Anyhow, a couple of weeks ago, on a Saturday morning, I somehow got to thinking about prime numbers and how easy it would be to write a little computer program to identify a list of prime numbers. After all, all one would have to do is start with the number 2, then begin listing all of the natural (i.e. plain 'ol counting) numbers one by one, dividing each of them into the given number and see if there is any remainder. If any of the numbers divide into it evenly (without any remainder), then voila, it's a prime number! I'll just let the computer do all of the nasty, tedious, number crunching. I wondered just how big a prime number I could find (or in my personal case, "discover"). In doing a quick Internet search, it was cool to find that there is a name for this time-honored approach to divining prime numbers, the trial division approach (though it fell out of favor centuries ago - hey, better late than never). I also was quite thrilled to learn a neat trick to greatly reducing the numbers needed to run the program in order to determine if a number if prime or composite -- stop when you get to the number that is or larger than the square root of the number in question. Of course, this makes total sense if you think about it. There can obviously be no factors to consider that are greater than the square root of the number because you would have found already the other factor that multiplies with it to obtain the number. So, for a number like 100, the largest number you would have to check is 10. For a much bigger number, say one million, 1000 is the largest number that needs to be checked as a factor. No need to try out the remaining 999,000 numbers!

So, I quickly wrote such a program and the fruits of my labor are contained in this blog posting. As promised, I also integrated the graphing techniques I've been describing in recent posts by including the option of drawing a running graph of the total number of prime and composite numbers found. I'm not going to provide the level of explanation to my code as I have previously, but I'm very happy to answer questions about it if you look at the code and can't figure it out.


Here is a snapshot of the program:


How It Works


First, you enter a number as the upper limit of the range that will be searched for prime numbers. Then, you click the "Start Search" button to have the program begin its number crunching to search for prime numbers beginning with 2 and ending with the number you entered. You can also choose to graph totals of prime and composite numbers found so far, though the program runs a lot more slowly if you choose this option.

In the "Status Window" you will see the current number being analyzed with the factors being considered on the next line. Of course, the numbers are buzzing by very fast at the beginning, though things do slow down after awhile.

As prime numbers are found, they are listed in the first column. That column is actually the heart of the program, because all factors of other numbers can be reduced to two or more prime numbers. So, when a number is being analyzed (let's call it the target), each of the prime numbers found so far are divided into the target. If there is no remainder, then it is not a prime number and it is added to the middle column as a composite number, and the next natural number becomes the target.

As the program runs, you are given a running total of prime and composite numbers found so far.

The script that makes all this work can be found in the "Start Search" button. Basically, there are two Repeat loops, one nested in the other.

The first Repeat loop increments the variable "varNumber" which serves as the target number. Within that is another Repeat loop that is dividing all of the prime numbers found so far into it. Let's dissect this second Repeat loop. Here's the code:

      put true into varPrimeFlag
      put the number of lines in field "prime numbers" into varL
      repeat with i = 1 to varL-1
         put line i of field "prime numbers" into line 3 of field "feedback"
         put varNumber/(line i of field "prime numbers") into varAnswer
         put varNumber&", "&(line i of field "prime numbers")&", "&varAnswer&", r="&varAnswer-
            round(varAnswer) into line (number of lines in field "answer")+1 of field "answer"
         if varAnswer-round(varAnswer) = 0 then
            put varNumber&", "&(line i of field "prime numbers") into line (number of lines in field
              "composite numbers")+1 of field "composite numbers"
            put false into varPrimeFlag
            exit repeat
         else
         end if
         if line i of field "prime numbers" > sqrt(varNumber) then exit repeat
      end repeat
      wait 1 tick
      if varPrimeFlag is true then
         put varNumber into line (number of lines in field "prime numbers")+1 of field "prime numbers"
      end if

I really like the scripting technique of using LiveCode's list processing capabilities in tandem with text fields. It's a snap to continually add to any text field just by a script that counts up how many lines are being used, then saying to put the next data item to the +1 line. Similarly, it's a snap to take and use each line of data just by building a repeat loop that starts at line 1 and repeats for the number of lines in the field.

I use the variable "varPrimeFlag" to flag whether or not the target number is prime. As you can see, before the loop begins, I assume the number will be prime by setting it to true; if the loop finds it to be a composite number, I set varPrimeFlag to false. So, if nothing triggers this, the repeat ends with varPrimeFlag being true, and the number is added to the list of primes.

Lines 5 and 8 are key to determining if a number is composite:

put varNumber/(line i of field "prime numbers") into varAnswer
...
if varAnswer-round(varAnswer) = 0 then 

Line 5 divides the target number by each and every prime number found so far. Line 8 takes the answer and subtracts from it the answer rounded off to the nearest whole number. If the answer is 0 this means that there was no remainder to the original division problem. Any number that divides into a second number, with no remainder, is a factor of the second number.

This line checks to see if the next prime number to be used to check out the target is larger than the square of the target number:

if line i of field "prime numbers" > sqrt(varNumber) then exit repeat

If it is, the repeat loop ends.

Also, you will find a procedure within the script for this button titled "graphPrime" that handles the graphing tasks.

Lloyd's Findings


Next, here are some of my "findings."

First, I programmed the time it took the program to compute all of the primes up to a given range. I think this is an interesting data point in and of itself. Here are three examples:
 
  • Analyzing 1000 numbers takes 1:01 minutes
  • Analyzing 2000 numbers takes 3:01 minutes
  • Analyzing 5000 numbers takes 16:56 minutes 
So, if I were to devise alternate ways of crunching the numbers, I could use these data to compare the efficiency of the strategies. But, that wasn't a question I was interested in at the moment.

Next, here are two other interesting facts:
  • 4999 is the largest prime number I've found so far.
  • In the set of numbers 2-5000, there are 669 prime numbers (and 4330 composite numbers)
Don't worry, at some point I'll run the program for much longer periods of time. I'm curious as to how long it could run before crashing -- I don't know of any limit to the number of lines in a text field, but I'm sure at some point I'll exceed some memory cache. (It will be rather cool to keep posted somewhere the "largest prime I found so far.")

Next, I became interested in the factors of composite numbers. The program is not looking for all the factors, but merely asking the question of whether the number being analyzed is a prime or composite number. So, as soon as a factor is found, the number is deemed composite and the program moves on to the next number. So, obviously, every even number is quickly determined not to be a prime number because the factor 2 reveals this fact. So, I thought it be at least interesting to include in the output the first (i.e. smallest) factor found. So, the number 2 is obviously common with it being the first factor of half of the numbers. But, I was intrigued to find what would be the largest first factor.

My program revealed that in the data set 2-5000, 67 is largest first factor, and it is found in the following composite numbers: 4489, 4757, 4891.

I found this answer by copying and pasting all of the data in column two into Excel. I decided it would be good to partner LiveCode with Excel for this project. After all, why take the time to program functionality into my computer program when it already exists in Excel. There is a wonderful option in Excel called "Text to Columns..." under the "Data" file menu choice that lets you parse a list of numbers in each cell of a column into separate columns. So, the number pairs...

4,2
6,2
8,2

...can easily be parsed into two separate columns in excel using the comma as the delimiter.

Next, I found the results of the graph quite amazing. For example, consider your own hypotheses about the distribution of prime and composite numbers. Are they evenly spread out or they do they appear randomly, or in clusters? Do they occur is equal numbers, or in some proportion. Are the patterns consistent, or do the patterns stop and start up again? To be honest, I didn't know what to expect and I forced myself not to do any google searches because I wanted to make the discovery myself!

The running graph shows that the rate of which composite and prime numbers are distributed looks to be a linear function for each. The fact that the slopes are so straight and smooth is fascinating. I wasn't sure if I would find some "jaggy" lines showing gaps in the number of primes. However, there does seem to be a slight bend in the prime number graph, where the rate seems to be falling off slightly. So, I programmed the file to keep track of the ratio of the totals of prime and composite number found at any given point, and these are found in the third data column (each line contains a pair of numbers: the ratio and the point in the list). When I copy and paste these into Excel and plot them in a graph, here is what you find:


This graph clearly shows that the ratio gets smaller and smaller, meaning that as the more numbers you analyze, the fewer prime numbers there are, relative to the total. It seems to resemble an exponential-logarithmic distribution. (Rather impressive of me to notice this, don't you think?) Actually, in doing some research (aka I looked it up on Google), the distribution of prime numbers is known as the Prime Number Theorem. According to the Wikipedia entry, "Informally speaking, the prime number theorem states that if a random integer is selected in the range of zero to some large integer N, the probability that the selected integer is prime is about 1 / ln(N), where ln(N) is the natural logarithm of N." I guess that's about as informally as most mathematicians speak.

This also means that it is an asymptotic distribution, which is actually something I do understand. An asymptote is a number representing a limit. So, the ratio of prime to composite numbers will approach, but never reach, this number. (Interestingly, I did a google search for this number, but did not find it. Hmm, this makes me "curiouser."

After analyzing 5000 numbers, the ratio is .15, in other words, there are about 6.7 times as many composite numbers as prime numbers between the range of 2-5000, the number continues to decline. Amazing!

My little program, of course, is not of interest to a mathematician as it reveals nothing not previously know. Indeed, although the largest prime I have found is 4999, a number with 4 digits, the largest prime number yet discovered has 17,425,170 digits! (Read this article to learn about the largest prime number yet found.) However, contributing to the mathematics literature was not the point of this exercise. In was intended to be my own wonderful journey of personal discovery. But, you never know from where the next major mathematical discover will arise. I just read an article on Slate.com  titled "The Beauty of Bounded Gaps" of an "ordinary" mathematician -- Yitang “Tom” Zhang, a  math professor at the University of New Hampshire -- making a monumental discovery about prime numbers.

Here's a quote from the Slate article I found  interesting:

"The primes are the atoms of number theory, the basic indivisible entities of which all numbers are made."

Boy, this really makes me feel that my humble investigation into prime numbers is important stuff. But, I had a truly emotional reaction to next quote from the article:

"This means, in particular, that prime numbers get less and less common as the numbers get bigger, though the decrease is very slow; a random number with 20 digits is half as likely to be prime as a random number with 10 digits."

I got emotional because I feel like I'm the one who discovered this! That's what math and science projects do to people.

There are so many other questions that I want to explore if I had time. The Slate.com article actually gives me some ideas for how to look for gaps in prime numbers. An obvious next question -- obvious just by thinking about it, and especially by watching the program run -- is that it takes more and more time to analyze a number as the number increases. But, does the time increase in a linear or exponential fashion? Perhaps I'll analyze these data and report on what I find in a future blog posting.

Perhaps you have a question you'd like me to consider exploring. If so, send it on! Better yet, use my program to explore your own prime number questions. And better still, build your own program to explore your questions, feeling free to use any of my code as a starting point.

So, those of you who teach mathematics, especially with middle and high school students, please consider integrating LiveCode into your teaching and challenge your students to think like a mathematician to discover mathematical principles and ideas on their own. Who cares if the answers are already found in some book or some Google search. A personal discovery based on questions you find meaningful makes it a real discovery.


Saturday, May 18, 2013

Graphing with LiveCode, Part 3: Graphing Parabolas and the Sine & Cosine Functions

It's time to turn our attention to graphing functions that will result in curves. I think this is where mathematics truly becomes beautiful for me. We will graph three of the most common mathematical functions that result in classic curved shapes: parabolas, the sine curve, and the cosine curve. (The sine and cosine curves look exactly the same, except that they cross the x-axis at different places.)

As promised, here is a copy of the LiveCode stack with all of the scripts from this and the previous two blog postings, along with Mac and Windows executable versions of each (for those of you who have not yet downloaded LiveCode, which would be strange given that it is now free):


Note: I just learned that when saving a stack that uses the brush tool as a stand-alone application, you have to go to the standalone settings, and under "General" choose to "select inclusions for the standalone application," then check "brushes."

Graphing Parabolas


Let's start with the parabola, which is derived from the function: y=x2
(This is read as "y equals x squared.")

Here are x, y pairs of numbers for this function:
-3,9
-2,4
-1,1
0,0
1,1
2,4
3,9

Here is a graph of a parabola linked from purplemath.com:


I just love how the curve mirrors itself around the y-axis due to the fact that a negative times a negative gives a positive.

Graphing a Parabola in LiveCode

Let's turn now to doing this in LiveCode. In the previous blog post, we ended with the script for a button that graphed a line of the following function:

y=3x+50

Here's the entire script of that button:

on mouseUp
   choose brush tool
   set the brush to 32
   set the brushColor to orange -- could use an RGB triplet here
   set the dragSpeed to 0
   //Set the starting point for the x and y variables:
   put 0 into var_x
   put 0 into var_y
   put -1000 into var_xprev
   put -1000 into var_yprev
  
   repeat 250 times
      //add one to var_x:
      put var_x+1 into var_x
      //This is the function "y=3x+50" scripted in LiveCode:
      put -(3*var_x+50) into var_y
      drag from var_xprev, var_yprev to var_x+250, var_y+250
      put var_x+250 into var_xprev
      put var_y+250 into var_yprev     
   end repeat
   choose browse tool
end mouseUp

Line 5 of the repeat script is the LiveCode version of that function:

      put -(3*var_x+50) into var_y

Recall that in order to "flip" the y-axis of LiveCode to match that of a traditional Cartesian coordinate system, we took the negative of the function, hence the negative sign near the beginning of the line. Also recall that we wanted the origin of the graph -- 0, 0 in a Cartesian system -- to be at the center of our 500 by 500 pixel large card. So, lines 6-8 add 250 to varx and vary to accomplish this. We repeated the loop 250 times because that seemed about right. (Don't you just love my precise way of describing things.)

Now we need to rewrite line 5 to graph not the function of the line "y=3x+50," but instead the function of the parabola "y=x2." A digital piece of cake.

      put -(var_x^2) into var_y

Here is what the resulting graph looks like:

OK, it kinda looks like the right half of the parabola shown above at purplemath.com. But it's rather tall and skinny. Let's analyze this a bit. Keep in mind that squaring a positive number makes it much bigger. (Yes, a profound statement, I know.) As x gets bigger by 1, y grows exponentially. So, it doesn't take long for the value of y to be so big that it is "off the charts," so to speak. Indeed, in the above example, since 250 is the upper limit of y, we can calculate the biggest value of x that will actually appear on our graph just by taking the square root of 250, which is approximately 15.8. So, obviously, it does not good to repeat the loop 250 times; 15 or so will get us the same results. So, change the script to repeat 15 or 16 times to see what I mean.

To flatten the curve out, we just need to divide y by some amount. In playing around, 50 worked out pretty well. There are a couple of ways to do this, but I think the simplest is just to change line 5 in the repeat loop to the following:

      put -(var_x^2)/50 into var_y

When you run the script now, you only get a small arc graphed because we need to repeat the loop many more times. So, since we are dividing y by 50, we can calculate the largest x value by taking the square root of 250*50, which is not quite 112. So, let's repeat this loop 112 times and see what we now get:

Very nice parabolic shape, if I say so myself.

Anyhow, play around with dividing y by 60 or 40 or 106, whatever, to see how to make the curve flatter or skinnier.

To get the full parabola (left and right halves), we just need to set the first value of x to the negative of the number of loops we needed to attain the perfect right half, then of course we need to double the number of times we repeat the loop.

Line 7 of the mouseUp script becomes:

   put -112 into var_x

We will repeat the loop 224 times to get the following:
Here is the final script of my button "Graph y=x^2":

on mouseUp
   choose brush tool
   set the brush to 32
   set the brushColor to brown -- could use an RGB triplet here
   set the dragSpeed to 0
   //Set the starting point for the x and y variables:
   put -112 into var_x
   put 0 into var_y
   put -1000 into var_xprev
   put -1000 into var_yprev
  
   repeat 224 times
      //This is the function "y=x squared" scripted in LiveCode:
      put -(var_x^2)/50 into var_y
      //put var_x&", "&var_y into line 1 of field "data"
      //put var_x+250&", "&var_y+250 into line 1 of field "data"
      drag from var_xprev, var_yprev to var_x+250, var_y+250
      //wait until the mouseclick
      put var_x+250 into var_xprev
      put var_y+250 into var_yprev     
      //add one to var_x:
      put var_x+1 into var_x
   end repeat
   choose browse tool
end mouseUp

You'll notice some variations to what we used above. First, notice that I moved the code to increase x by 1 to the bottom of the repeat loop. That just seemed a better place.

Second, notice lines 4-5 and line 7 in the repeat loop. They are set as comment lines now, so they do not get executed. But, they will if you delete the "//" in front of each.  What would these do? Well, I added them to help me understand and troubleshoot the code. I do this all the time. After I perfect a script, I usually delete them, but I thought you might like to see them so as to learn a good programming trick to help you figure out what's going on in your script as you work on it. Line 7 - "wait until the mouseclick" - is a simple way to have the repeat loop pause at each loop and wait for you to click the mouse button. This lets you look at what is happening at each loop. Lines 4 and 5 put var_x and var_y into a (now hidden) card field titled "data." (This field can easily be made visible in the Application Browser tool.)

Let's move on graphing two more interesting curves -- the sine and cosine functions.

Graphing the Curves Derived from the Sine and Cosine Functions


OK, let's explore the sine and cosine curves. First, here is a graph of the sine curve linked from purplemath.com:



It's important to understand how this curved shape is generated. For most people, the shapes, though familiar, are quite mysterious, even though everyone certainly graphed them at some point in high school. The explanation of these curves is rather simple and is derived by considering a circle.

Here is a figure of the circle linked from the purplemath.com web site that will help explain things for us:



As you can see, the radius of this circle is conveniently set to 1. Any radius I draw will obviously intersect the circle at one and only one point. Now, take a moment and look at the figure above and estimate the angle that is formed at left point of the triangle formed by the line segments r and x. It looks to be about 30 degrees to me. Well, the sine of that angle is y and the cosine of that angle is x. That's it. It's no more complicated than that. So, the sine of an angle of 0 degrees would 0 and the cosine would be 1. The sine of an angle of 90 degrees would be 1 and cosine would be 0. What about 45 degrees? Although one might be first tempted to say both sine and cosine are .5 (half of 1), the answer is actually about .707. One way to reason this out is with the all-powerful Pythagorean Theorem, which for right triangles is a2 = b2 + c2 and is read as "a squared equals b squared plus c squared." b squared and c squared both equal .5, and the square root of .5 is .707 (when rounded to 3 decimal places).

Click here to try out a very nice interactive animation of the sine curve at intmath.com -- it nicely shows how the sine curve is formed just by tracing out the value of y.

Graphing the Sine and Cosine Functions in LiveCode

An important fact to remember throughout the next few minutes is that the maximum value of sine or cosine is 1 and the minimum value is 0. So, this is not a very large range for graphing purposes. So, obviously, we are going to need to multiply some value in our code to make the curve more readily apparent. So, tuck that thought away as we proceed to program these curves in LiveCode. We'll start with the sine curve.

Fortunately, all need to do is revise a single line of code in the script for the parabola. And I'll bet you've already figured out which line of code I mean - line 3 of the final script shown above:

      put -(var_x^2)/50 into var_y

LiveCode already includes the sine and cosine functions. These are "sin" and "cos," respectively. (Refer to the LiveCode dictionary to learn more about them.) To change from graphing a parabola to graphing the sine curve, it seems it should be as easy as change it first to the following:

      put -(sin(var_x)) into var_y

But, not so fast. By default, LiveCode using radians instead of degrees to express an angle. (Rather than take the time to explain it here, I suggest you do a google search on the difference between radians and degrees. In short, radians are based on pi, not degrees, where 2*pi equals 360 degrees. Remember the formula for the circumference of a circle? "A=2*pi*r") We could stick with radians, but this would take some more programming gymnastics to get everything to work. So, we'll just convert radians to degrees by multiplying the value by (pi/180):

      put -(sin(var_x * pi/180)) into var_y

Finally, we need to multiply everything by some number so the result will be bigger than 1. I think multiplying by 100 will do the trick. So, here is the final script:

      put -(sin(var_x * pi/180))*100 into var_y

Let's start the graph as far left of the card as we can. Since the card is 500 pixels wide and high, let's set var_x to about -240. We'll repeat everything twice this amount, or 480 times. Here's what we get:

Let's duplicate this button and title it "Graph cosine function." We change the line of code above to the following:

      put -(cos(var_x * pi/180))*100 into var_y

I changed the brush color to blue. Here is the resulting graph:

Poetry in motion.

So what?


I admit that the past three blog posts have been rather theoretical in nature. Being able to graph simple lines, parabolas, and the sine and cosine functions may impress our high school algebra teachers, but what good is all this for LiveCode development? In my next posting, I'll show an example that puts this graphing script to use in a blog posting that I'm thinking of calling "Lloyd's Math Fair Contest Entry."

A Mystery Remains


Although I'm tempted not to tell you this, there is one last mystery that, frankly, I've not been able to solve. Remember way back when (in my first blog posting in this graphing series) that we had to choose our first point "way out to the left" in order to avoid that awkward first line segment -- we chose -1000, -1000. Well, I'm actually wondering why we are not seeing the first line segment connecting -1000,-1000 with the first point of the parabola, sine curve, or cosine curve. I've played around a little bit with this. If you change this first point where the coordinates are both positive numbers - say 5, 5 - then that pesky line segment appears. So, it has something to do with the fact that the initial point is not shown on the visible area of the card. I hope anyone who knows more about this will help explain this for us.

Saturday, May 11, 2013

Graphing with LiveCode, Part 2: Graphing Functions

I did a search for other ways to do graphing with LiveCode. I quickly found a tutorial on the RunRev site: http://lessons.runrev.com/s/lessons/m/4071/l/7049-how-to-make-a-simple-line-graph

This is worth a look as it provides a clever way to create static line graphs based on a list of numbers in a field. However, it doesn't seem to create a running, dynamic line graph of the kind I am trying to show in this series of blog postings.

Also, there is also a commercial product called ChartMaker for LiveCode:
http://www.flexiblelearning.com/chartmaker/

This is a LiveCode extension, meaning that you can extend the functionality of LiveCode to include making charts. It isn't too expensive (about $76), but then again, it isn't free. I don't know anything about it other than what I've read on the company's Web site. But, my cursory review of the product doesn't lead me to believe it can create dynmanic graphs "on the fly" either.

So, I think we still need to learn how to do this on our own with scripting in LiveCode.

In my last post, we learned how to "connect the dots" by using the brush tool (a bitmap graphic tool), choosing a brush color and shape, then dragging the brush from point to point using x,y coordinates where x and y are 0 at the top left corner of the LiveCode window. Now we need to learn how to use these skills to graph functions where y depends on x. I think the simplest example is y=x, meaning that whatever x is, y will be the exactly the same. So, the pairs of coordinates would be the following:

0,0
1,1
2,2
3,3
4,4
And so on...

So, how do we program LiveCode to graph y=x? It's easy. Here's the script for a button "Graph Function":

on mouseUp
   choose brush tool
   set the brush to 32
   set the brushColor to orange -- could use an RGB triplet here
   set the dragSpeed to 0
   //Set the starting point for the x and y variables:
   put 0 into var_x
   put 0 into var_y
   put 0 into var_xprev
   put 0 into var_yprev
  
   repeat 250 times
      //add one to var_x:
      put var_x+1 into var_x
      //This is the function "y=x" scripted in LiveCode:
      put 3*var_x+50 into var_y     
      drag from var_xprev, var_yprev to var_x, var_y
      put var_x into var_xprev
      put var_y into var_yprev
   end repeat
   choose browse tool
end mouseUp

And here is the resulting "graph," a line that is draw starting from the top-left corner of the window down to the center of the window (I set the window size of the stack to 500 x 500):



Let's now analyze and explain this script. First, many of you who received an "A" in algebra many years ago are probably saying "But shouldn't the graph be drawn going up and towards the right?" Yes, that is why you got an "A"! We will deal with this little problem before this post ends. Just try to ignore this problem for now.

Lines 7 and 8 set the two x and y variables both to 0. (I've kept with good scripting conventions and labeled them var_x and var_y to make it clear in the script that they are variables.) These lines set the starting point for the graph.

As we consider lines 9 and 10, you need to remember how the drag function works in LiveCode. You have to drag between two points. And, remember from my previous post that to draw a graph, we had to make sure that the ending point of one line segment became the starting point for the next line segment (i.e. connecting the dots). So, lines 9 and 10 set up two other variables that will be used to keep track of the coordinates of the end point of the previous line segment. Jump down to lines 18 and 19. These two lines pass the contents of var_x and var_y to these two variables I've cleverly named var_xprev and var_yprev (where 'prev' is short for previous). So, lines 9 and 10 just set these two variables also to 0 so that we have two pairs of numbers for the very first line segment. But, let's not get ahead of ourselves.

Lines 12 to 20 comprise a repeating loop that repeats 250 times. (In later posts, we'll get more sophisticated in how long or how far to graph. However, another good option -- if you want to be daring -- is to change line 12 to "repeat until the mouseClick" which will repeat forever until the mouse is clicked.)

Line 14 adds one to var_x, or 1+0, making it equal to 1. This is the classic way of incrementing a variable in a repeating loop.

Line 16, believe it or not, is the way we script the function "y=x" in LiveCode:

put var_x into var_y

In other words, putting x into y is the same as saying make y equal to x. So, var_y and var_x are both now 1.

Line 17 drags the brush between the two points. So, this script actually draws 250 individual line segments. (If you wanted to speed things up, you could change line 14 to "put var_x+2 into var_x" and repeat the loop only 125 times.)

As already mentioned, lines 18 and 19 pass the contents of var_x and var_y to var_xprev and var_yprev.

In algebra textbooks, you will see this function written in what is called the slope-intercept form:

y=mx+b

where m is the slope of the line and b is the place where the line intersects the y axis (known as the y-intercept). So, I know you are saying, "Cool! Let's do some stuff by including m and b in our equation!" (Man, you are geeky.)

OK, let's change line 16 to the following:

put 3*var_x+50 into var_y

Let's also change the brush color to orange in line 4, so the new line is easier to distinguish from the first line. Here is what we get when we run the script by clicking on the button:



As you can tell, the line is much steeper. That's because the slope is now 3. Also notice how the line starts down 50 pixels. Also notice that something a little weird happens right at the start. That weirdness is caused by the fact that var_x and var_y are still starting at 0 because of lines 7 and 8. Actually, when x is 0, y should 50 because 3x will equal 0. So, this is another little problem we need to solve. We can easily solve it by first setting var_xprev and var_yprev to some number far off to the top left, such as -1000, -1000. Do that and the graph now looks fine:


The computer has drawn an orange line from -1000,-1000 to 0,50, but we just can't see it because it is off to the left of the current window.

Let's draw one more line, using the function "y=2x+1". We need to update line 16 to the following:

      put 2*var_x+1 into var_y

I'll change the brush color to red. Here is the resulting graph:


I used this example because so we could compare it to what we would see in an algebra textbook. Here is a nice figure of the graph of y=2x+1 from http://www.algebra-class.com/table-of-values.html:



Two things jump out at me. First, their red line slants upward from left to right, not downward. Second, the 0,0 origin is at the center of the graph (not the top-left point). The first is a problem that results from the fact that in LiveCode the y axis simply goes in the other direction of the traditional Cartesian coordinate system. That problem will be easily solved just by multiplying all y values by -1. This will essentially "flip" the y axis.

To deal with the second issue, we need to choose 250,250 (the center of the window) as our starting point, instead of 0,0. So, we need to offset both x and y by 250 pixels.

OK, let's see how to do this. Let's start by graphing our original function of y=x. So, to flip the y axis, here is the script for line 16:

      put -(var_x) into var_y

This just means to put the negative of whatever var_x is into var_y.

Lines 17-19 have to be modified to add 250 to var_x and var_y, because of the offset:

      drag from var_xprev, var_yprev to var_x+250, var_y+250
      put var_x+250 into var_xprev
      put var_y+250 into var_yprev

Make these two changes and here is the resulting graph (I also changed the brush color back to brown):



Let's now enter our second function from above, making sure again to multiple var_x by -1. This changes line 16 to:

      put -(3*var_x+50) into var_y

Here's the resulting graph (I changed the brush color to orange to show the second line):


Perfect!

Let's end this rather long blog posting by using LiveCode's vector tools to draw the x and y axes, making sure that they cross exactly at point 250,250 (also be sure to draw these axis lines with arrows at both ends, otherwise your algebra teacher will find and reprimand you; the option to add arrow heads can be found in the "basic properties" window of each line). Here is a resulting graph that any algebra teacher would be proud of:


Note, something very important and wonderful. You can now change the origin of the graph just by manipulating these two numbers (currently 250). So, if you wanted the graph's origin to be over 100 and down 300, you would change these numbers accordingly.

In the next posting, we'll continue this graphing exploration by graphing the function for a parabola and the sine and cosine functions. I also promise in my next post to provide a LiveCode stack you can download with all of the scripts we've covered.


Sunday, May 5, 2013

Graphing with LiveCode, Part 1: Colorful Addendum

It really bothered me how boring my last post was. So, here is a little example of what one could do with the skills described in my last post, coupled with a little knowledge of variables and random numbers.

Here is the script from a button titled appropriately enough "Draw Colorful Lines at Random":

global varX, varY, varXprev, varYprev, varRGB1, varRGB2, varRGB3

on mouseUp
   choose brush tool
   set the brush to 32
   set the dragSpeed to 0
   put 250 into varXprev
   put 250 into varYprev
  
   repeat until the mouseclick
      hide button "Draw Random Colorful Lines"
      hide button "Erase"
      put round(random(500)) into varX
      put round(random(500)) into varY
      put round(random(255)) into varRGB1
      put round(random(255)) into varRGB2
      put round(random(255)) into varRGB3
      set the brushColor to varRGB1, varRGB2, varRGB3
      drag from varXprev, varYprev to varX, varY
      put varX into varXprev
      put varY into varYprev
   end repeat
   choose browse tool
   show button "Erase"
end mouseUp

I hope you can quickly see that it is nothing more than a quickly revised script of the button "Draw Lines" from my previous post.

Here is a screenshot of the program after running for 60 seconds:

And, this static image, "avant-garde" as it is, is nothing compared to being mesmerized by watching the program run.

There, I feel better.

Saturday, May 4, 2013

Graphing with LiveCode, Part 1: Learning How to Draw Lines with Scripts

In my previous post, I casually mentioned that it would be cool to graph the changing rate at which unique random codes were being generated. Graphing is a powerful visual tool. But how would one actually do this in LiveCode?

First, unfortunately, there is no graphing tool or widget in LiveCode (at least not that I'm aware of). But, LiveCode has many graphical drawing tools. In fact, it has the two most common graphical types: bitmap (i.e. paint) and vector (i.e. drawing).  I'm assuming you know the difference between the two. If not, you might want to do a quick google search at this point to learn the difference. In short, bitmap graphics are merely the turning on or off of pixels on the screen, whereas vector-based graphics are "defined" as objects. For example, if you've ever used a graphics package where you create rectangles and ovals and then could stretch any of these by clicking and holding on one of the the object's handles, or if you could click on the object and continually choose different line widths, line colors, fill colors, etc. after first drawing the object, then you are using a vector-based tool. It's as though the object is defined as having so many sides or lines, with each line being straight or curved, and being such and such color and thickness, etc. In contrast, bitmap graphics are drawn on the screen with attributes that cannot be changed or manipulated, other than by doing things such as taking an "eraser" tool and slowly erasing the object, or selecting an area of the screen and choosing to cut it.

So, it's great that LiveCode has both. In the tools palette, the bitmap graphic tools are in the bottommost section (e.g. spray can, eraser, pencil, etc.) and the vector graphics tools are just above those (e.g. rectangle tool, oval tool, line tool, etc.):



If you are still fuzzy on the whole bitmap vs. vector graphics thing, I suggest you take 5 minutes to play with these tools now. Just open a new card and start drawing a bunch of graphics. You'll quickly deduce the difference between these two graphics families.

In this blog entry, I'm just going to show how to draw a simple line with the brush bitmap tool. We won't actually do any graphing in the mathematical sense until part 2. But, you have to first understand how to use these tools first in simple scripts. So, this post will be rather boring in that we won't try to do any mathematical graphing (something I'll define better next time). Let's just take a few minutes to learn how to use scripting techniques to draw lines on the screen.

Cartesian Coordinate System - LiveCode Style


OK, let's get into it. Consider the following code of a button titled "Draw Lines":

 on mouseUp
   choose brush tool
   set the brush to 32
   set the brushColor to brown
   set the dragSpeed to 0
   drag from 25,200 to 50,150
   drag from 50,150 to 75,175
   drag from 75,175 to 100,140
   choose browse tool
end mouseUp

This script is yet another example of the natural language-feel of LiveCode. Line 2 says to choose the brush tool from the various bitmap graphic tools.

Line three selects the brush shape that will be used.  There are 35 built-in shapes. According to the LiveCode dictionary: "A brushID is a built-in brush number between 1 and 35. (These brushes correspond to LiveCode's built-in patterns 101 to 135.) By default, the brush is set to 8 (a round brush)."

32 is a thin, square brush shape, and a good one for plotting line graphs. 28 is probably the thinnest brush to choose. Brushes 5-8 give different round sizes, whereas brushes 1-4 give similar sizes, but in a square shape.

Line four chooses the color that the brush will paint with -- you can also use an RGB triplet here instead (e.g. 127,127,255).

Line five sets the speed at which the brush will draw, with 0 being as fast as possible (0 is best thought of as instantaneous).

Lines 6-8 draw three lines and we need to understand them perfectly before going on. First, you need to understand the grid system of the LiveCode stack window. Each pixel in the window can be identified with a pair of numbers. The first indicates how far from the left edge to go and the second number indicates how far from the top edge to go. So, with the pair 25, 200, you start from the top left corner and go to the right 25 pixels, then down 200 pixels.

At this point I'm hoping you are having a flashback to your high school algebra days to remember something called the Cartesian Coordinate system (named after the famous mathematician and philosopher, René Descartes). This is simply the same sort of grid consisting of two lines -- the x-axis (horizontal) and the y-axis (vertical) -- crossing each other at right angles, usually drawn to resemble a big plus sign, with the origin -- 0,0 -- at the center. (These crisscrossing lines are just that "lines," in the formal mathematical sense, meaning that they extend infinitely in all four directions, symbolized by small arrow heads.) The LiveCode grid system is similar except that 0,0 is in the top-left corner of the screen meaning that as the vertical number (second of the pair) gets bigger, the further down you go. In contrast, as y gets bigger using the classic Cartesian grid, you go up. This little difference will become more important in my next blog entry.

So, line 6 tells the computer to go to point 25, 200 (i.e. starting at the top left corner, go over 25 and down 200), then drag the brush to point 50,150, leaving a line segment between the two points.

Line 7 starts at 50,150, then drags another line to point 75,175. Finally, line 8 starts at 75, 175 and drags a final line to point 100,140. So, all we are doing is connecting the dots. Here is what the 3 line segments look like in a stack of size 500 by 500:

Not too exciting, I realize. But, you should play with this code, drawing different lines all connected to each other just by changing the coordinates (the pair of numbers for each starting or ending point) of the drag command. To have one long jagged line created, just be sure that the starting point of the next line segment is exactly the same as the ending point of the previous line segment.

Now notice line 9 -- "choose browse tool" -- this is the tool represented by the left arrow in the top left corner of the tool palette. If you leave off this command, the brush tool remains chosen and you will have to manually choose the browse tool.

OK, I Drew Some Graphics, So How Do I Erase Them?


Now, notice the Erase button. That button does just what it says -- it will erase all bitmapped graphics drawn on the card. Here's the code for this button:

on mouseUp
   choose select tool
   drag from 0,0 to 500,500
   cut
   choose browse tool
end mouseUp

The select tool is the first bitmap tool in the tool palette represented by the dotted rectangle. By dragging from 0,0 to 500,500 with the select tool, you have actually chosen the entire stack window. The command "cut" does just that -- it cuts, or removes, whatever bitmapped graphics are in this area.

OK, that's enough for now. Take some time to play with these commands, perhaps being bold and playing with other bitmapped tools using this scripting approach. If you haven't noticed already, these scripts mimic what you would do manually with your mouse, selecting various tools and drawing with them. It's pretty cool that you can actually script out these choices and movements with LiveCode.

In my next blog entry, I take these bitmap graphic scripting skills to the next level by using them to graph any mathematical equation, including lines, parabolas, the sine curve, whatever. I know, you can hardly wait.

Note: I deliberately have not provided any LiveCode file with this blog post. I'll include later one stack with all of the codes described in all the postings associated with this topic.