Linear Equations in Two Variables, Version C

Kenneth M. Levasseur
Department of Mathematical Sciences
University of Massachusetts Lowell
Lowell, MA 01854
Kenneth_Levasseur@uml.edu

This is the third of a series of notebooks that  develop a function in various ways

Previous Definition, Initialization Cells

Let's start by defining EquationOfLine completely as we had in the previous Notebook.  The following cell has been designated as an initialization cell  (see the little I inside the top of the cell bracket?).  This is done by selecting a cell and then selecting "Initialization Cell" from the Cell|Cell Properties submenu.  Whenever you evaluate a cell in any notebook, Mathematica goes throught the notebook looking for initialization cells.  If it finds any of them, it asks whether you want to evaluate them first.  Normally you would answer "yes."   The things that you normally put into an initialization cell are definitions that are necessary to perform the operations in the notebook.  In this case, it's just a convenience.  If we neglected to evaluate the cell below and jumped to creating equations of lines, our results wouldn't be as expected since EquationOfLine wouldn't have been defined.

You have the option of creating an "AutoLoad Package" containing just the contents of initializaiton cells to accompany any notebook having such cells.  If the notebook is "xyz.nb"  the autoload package will automatically be called "xyz.m" .     Whenever initialization cells in the .nb file are altered, the .m file is automatically updated.   Autoload packages are not really necessary in a small example like this, but are very useful when you create true packages and contexts, as will be described in LinearEquationsD.nb.

EquationOfLine[m_,b_]:=(y==m x +b);

EquationOfLine[m_,{s_,t_}]:=Simplify[(y-t)==m(x-s)];

EquationOfLine[{s_,t_},{u_,v_}]:=EquationOfLine[((v-t)/(u-s)),{s,t}];

EquationOfLine[{s_,t_},{s_,v_}]:=(x==s);

EquationOfLine::usage="EquationOfLine[a,b] returns the equation of the line relating variables x and y where a and b are either \n
		a slope and intercept\n
		a slope and point  or \n
		two points point and point.\n";

A Message

The limitation that was mentioned in the previous Notebook was that if the two points provided as arguements are identical, the result isn't really correct.

EquationOfLine[{1,2},{1,2}]

It's true that the line provided does go through the point, but so do an infinite number of other lines.   Our decision as to how to handle this case depends of how we envision the future usage of the function.  The definition below will make it the horizontal line through the point.    Since the choice is arbitrary, we should provide the user with a message to warn of possible unexpected results.   This is done by first defining a message

EquationOfLine::notunique="Two identical points do not define a unique line.  Horizontal line is chosen as the result.";

Now we will define EquationOfLine for this case.

EquationOfLine[{s_,t_},{s_,t_}]:=
	(Message[EquationOfLine::notunique];
		 y==t);

EquationOfLine[{1,2},{1,2}]

If you are aware of this situation and don't want to see the message, do this:

Off[EquationOfLine::notunique]

Now the message is suppressed whenever it would normally be displayed.

EquationOfLine[{1,2},{1,2}]

You can turn it back on too.

On[EquationOfLine::notunique]

Modules

As a function definition becomes  more complicated, it becomes convenient to make the definition within a Module.  This stage is often reached when you want to introduce an option, which we will do next.  In general, whenever a procedure becomes complicated to the point where local (temporary) variables become necessary you should consider a Module.  A second similar constrution, Block, may be used, but we will concentrate on Module here.

?Module

The first argument to Module is a list of local variables.  These local variables can be initialized using values of the global variables and, if Module is part of a function, the arguments to that function.  You can't use the values of other local variables in these initializations - this must be done within the second argument, which is normally a CompoundExpression ((Subscript[expr, 1]);(Subscript[expr, 2]);...;(Subscript[expr, n]))

Here is a function that finds the smallest eigenvalue of a square matrix (you don't need to know what that means!- just look at the programming construction.)

SmallestEValue[A_]:=Module[{dims=Dimensions[A], squareQ,evals},
		squareQ=Length[dims]==2 &&Apply[Equal,dims];
		If[squareQ,evals=Eigenvalues[A];Sort[evals,(Abs[#1]<=Abs[#2])&]//First]]

Notice how the there are three local variable, one of which is initialized using the single argument of the function, while the other two are just declared.  squareQ needs the value of dims so it can't be initialized right away and evals is only computed if squareQ is true.

r1=SmallestEValue[{{1,2,0},{2,1,2},{0,2,1}}]

r2=SmallestEValue[{{1,2,0},{2,1,2}}]

In computing r2, the argument provided to SmallestEValue isn't a square matrix and so no visible output is produced, but the actual output is Null.

FullForm[r2]

Since the names dims, squareQ and evals are defined within the Module, they don't have Global values.  This is important in order to avoid "Name Collisions."

?dims

Options, Side Effects & Computational Results

Visualization of a computed result is often a desirable objective.  In the case of EquationOfLine, one might like to view the graph of the equation that is computed.   It would be tempting to make the output of this function a graphics object, but a drawback to that plan is that a graphic cannot be processed mathematically as an equation can.  For this reason, the better approach to make the graphic result an optional side-effect.

Many of the built-in functions in Mathematica have options.  One such example is EngineeringForm.  This is how you get the name of its options and thier default values.

Options[EngineeringForm]

Basic usage of EngineeringForm

EngineeringForm[N[100!]]

Same number displayed with a couple of options reset.

EngineeringForm[N[100!],NumberSigns->{"-","+"},NumberMultiplier->"*"]

Designing your own options isn't too difficult.  The usual way to define an option is to define the option names together with their default values.  Let's assume that as a default, we don't want to see a graph of our line.  That will be our only option at this time.

Options[EquationOfLine]={PlotLine->False}

Now we will define what will be done with EquationOfLine if an option is included among the arguments.  This is the usual form recommended for handling options - I was told this by someone at Wolfram.  Other mechanisms are also possible.

The way the option is handled here is that after the first two arguments, all other arguments that take the form of a rule are considered part of the sequence opts in the code below.  To decide how to handle the PlotLine option, a list of rules is created joining {opts} and the list Options[EquationOfLine]. These rules act on the expression PlotLine and the result here is called plotQ.  The first rule that takes the form PlotLine->Something  will assign the value Something  to plotQ.  Notice that there will always be at least one such rule because of the value of Options[EquationOfLine].  The rest of the module then is completed using that value of plotQ.

Note:  Since Graphics in Mathematica 6 are no longer side effects themselves, the change that was made in this definition was to Print the Plot.   This seems to works fine.

EquationOfLine[a_,b_,opts___?OptionQ]:=
	Module[{plotQ=PlotLine/.Flatten[{{opts},Options[EquationOfLine]}],equation},
		equation=EquationOfLine[a,b];
		If[plotQ,yexpression=y/.First[Solve[equation,y]];Print[Plot[yexpression,{x,-10,10},PlotRange->{{-10,10},{-10,10}}]]];
		equation]

EquationOfLine[-1/2,{3,-4}]

EquationOfLine[-1/2,{3,-4},PlotLine->True]

More Tests

Testing your function is important.  You should try to "break it" by trying to think of inputs that other users might try.

EquationOfLine[5,-1,PlotLine->True]

You should be able to provide the default and things should still work.

EquationOfLine[5,-1,PlotLine->False]

Undefined option values should revert to the default

EquationOfLine[5,-1,PlotLine->DontKnow]

EquationOfLine[2,{1,-3},PlotLine->True]

EquationOfLine[{1,5},{2,5},PlotLine->True]

Limitations

Vertical Lines

This can be fixed with a little bit more coding

EquationOfLine[{1,5},{1,-3},PlotLine->True]

Symbolic input

This can also be fixed with slightly more advanced programming

EquationOfLine[m,{7,0},PlotLine->True]

Range of plot is rigid

The range of the plot isn't adaptive and so the line might not appear in the graph.  This was my choice initially  and could be fixed, possibly with another option

EquationOfLine[1,100,PlotLine->True]

Can't change default value of option

One major structural deficiency in with the way EquationOfLine is defined here is that you can't reset the default of PlotLine as you should be able to.

SetOptions[EquationOfLine,PlotLine->True]

We should get a plot from this now.

EquationOfLine[{1,5},{-1,3}]

We will take care of this problem in LinearEquationsD.nb