I'll go through your questions in sequence with some answers, and let others give a better answer as they can.

**(1)**
*When you create a math object, is it essentially a compiled object that can be used but not changed?...*

This is a good question. My read of the documentation for the Matrix MathObject is that there isn't an obvious way to change entries in a defined Matrix object. That said, `$mat->data`

"returns a reference to the array of data that represents the object," which should readily allow changing things. I haven't tested this, but it seems it should work to do something along the lines of

$mat = Matrix( [[1,2], [3,4]] ); $dat = $mat->data; $dat->[1]->[1] = -4; $newMat = Matrix( $dat );

to create a new matrix `[[1,2], [3,-4]]`

.

**(2)** *In the attached example, the call to ans_array leave a button with a pi on it...*

I believe the pi button is a trigger for an equation editor, "DragMath," that is enabled in the WeBWorK configuration files. Its location is probably determined by theme and related configuration; this is probably a question for Mike Gage.

**(3),(4)** *When a(n in)correct answer is input, it is marked as correct. However only the (1,1) entry has a green(red) highlight...*

I think this is a stylesheet bug. I thought Jason Aubrey had fixed it at some point, but it seems not to be fixed in the version of WeBWorK running on this server.

**(5)** *...It would be nice to have a Context('rational')...*

Context('RationalFunction') might be what you want: see contextRationalFunction.pl POD docs. Davide is the expert on this type of thing.

Gavin

I have been able to turn off the DragMath feature in an individual problem using the following code line near the start of my problem.

$envir{DragMath} = 0;

But I think this version of WebWork is not using DragMath but MathView so here is what Mike Gage and I thought should turn this feature off in an individual problem.

$envir{MathView} = 0;

Hopefully this should hide this feature on this problem. I will test it now to be sure.

Ok, so this code does work for DragMath, but it is not successful yet for MathView.

Perhaps someone else has figured this one out. I will post again if I get it working.

**When you create a math object, is it essentially a compiled object that can be used but not changed? For example, can you change an entry within a matrix?**

For most objects, it usually makes more sense to create a new one than to change the existing one, so there aren't methods for changing the data. A Matrix is an exception, and should have a method for assigning an entry's value. I thought there was one, but looking at the code I see it is listed in the "to do" section. Argh!

It is possible to write an assignment function (though it won't be a method of the object itself) that you can use the modify the matrix. Gavin has suggested taking the data from the original matrix and modifying, then making a new matrix from that. This is a nice idea, but there are some issues with his approach.

He suggests the following code:

$mat = Matrix( [[1,2], [3,4]] ); $dat = $mat->data; $dat->[1]->[1] = -4; $newMat = Matrix( $dat );which sets

`$dat`

to the internal data used to maintain `$mat`

. While this is a reference to an array, the elements of the array are not array references for the rows, they are MathObjects for the rows. That means `$dat->[1]`

is a MathObject, not an array reference, so you can't do `$dat->[1]->[1]`

. It is actually a reference to a Matrix object (one dimension smaller, in this case, a linear array representing a row of the original matrix)
You *could* do `$dat->[1]->data->[1]`

and change that to -4, but even that is not a good idea for two reasons. First, the entries in the Matrix are MathObject Reals, and this assigns it a Perl real. Nothing goes wrong here, but things may go wrong trying to use the matrix later when WeBWorK tries to treat the real as a MathObject Real (e.g., trying to call its `TeX`

method).

That could be fixed by assigning it `Real(-4)`

, but there is a second problem. The `$dat`

variable is not a *copy* of the data stored by `$mat`

, it actually *is* the data stored by `$mat`

, so when you modify it, you are actually modifying `$mat`

(`$dat`

is a pointer to the same array that `$mat`

holds internally, so changes to that array or its elements change `$mat`

). You will find that after running this code, `$mat`

will be the matrix given by `[[1,2],[3,-4]]`

.

(This does bring up a third issue, which is that the indices in the `data`

array start at 0, not 1, so changing the 1,1 entry is actually changing the second entry in the second row, which may not be what Gavin meant to do.)

Passing `$dat`

to `Matrix()`

does cause `$newMat`

to copy the data, and so from here on out `$newMat`

will be separate from `$mat`

, but `$dat`

is still tied to `$mat`

.

You could use this approach to modify the original `$mat`

, however. For example

$mat = Matrix( [[1,2], [3,4]] ); $mat->data->[0]->data->[0] = Real(5);would make

`$mat`

be the matrix `[[5,2],[3,4]]`

. I will give you an `assign()`

in a separate reply that works on this principle.
** If not, is there some type casting that might put it back to a perl array?**

Every MathObject has a `value()`

method that returns its defining data in a non-MathObject form (more or less). For a Matrix, it gives an array of array references much like the one you use in your PG code. So

$M = Matrix([1,2],[3,4]); @M = $M->value;makes

`@M`

be the array `([1,2],[3,4])`

(the only difference is that the numbers are now MathObject Reals, not perl reals). You could then modify the `@M`

array, and make a new Matrix from the result:
$M = Matrix([1,2],[3,4]); @M = $M->value; $M[0][1] = 8; $N = Matrix(@M);This makes

`$N`

equivalent to `Matrix([1,8],[3,4])`

.
Note that `$M`

and `@M`

are separate names, and don't interfere with each other (both the original Matrix and the array are still available, with `$M`

referring to the Matrix, and `$M[]`

referring to the array).

Note also that you can pass the array into `Matrix`

directly, and don't have to de-reference each of its entries, as you have done in your code. So
`$M = Matrix(@M);`

and `@M = $M->value`

undo each other (one converts an array to a Matrix, the other converts a Matrix to an array).

This makes it possible to simplify your code a bit. You could simply do

$N = Matrix(@R);rather than writing out the array element by element again. You can also use

`$R`

rather than `$N`

to make the association more direct. Similarly, you could use `$M = Matrix(@M)`

and then use
```
\[ M = $M \]
```

in the BEGIN_TEXT/END_TEXT block rather than writing out the TeX code by hand. The Matrix `$M`

will write the TeX code for you. This is one of the nice things about using MathObejcts -- you don't have to write both a Perl version and a TeX version of the same thing. Alternatively, if you don't want to create the `$M`

variable, you could use
```
\[ M = \{ Matrix(@M) \} \]
```

directly in the text block.
I'll answer the other parts separately. This has already gotten too long.

Thanks for clarifying the data that are returned by `$MathObject->data`

. This does bring up one question I have bumped into with `$MathObject->value`

, albeit with Vectors, not Matrices.

I've found that the value method doesn't always work as expected depending on how a Vector is instantiated. In particular, I've had trouble in the past getting the expected array when creating a vector with something like `$vec = $a*i + $b*j + $c*j`

(this may have been when $a, $b and $c were formulas). Is that (a) faulty memory on my part, (b) a known issue, or (c) now fixed?

If needed I can try and find more specifically what I was doing when I ran into the issue.

Thanks,

Gavin

`$a`

, `$b`

, and `$c`

are all reals, then there should be no problem. It is the case where one ore more is a Formula that things are different. In that case, `$vec`

will be a Formula object, not a Vector, and so the `value()`

method just returns the Formula itself. A Vector-valued Formula is still a Formula, not a Vector, and Formulas do work differently.While it is true that more could be done with Formulas, you are now moving into the situation where you need a CAS. For example, if your vector-valued formula were from

`$u x $v`

, it is more difficult to obtain the individual coordinates. And if `$v`

above were the formula `$M*$w`

for a matrix `$M`

and vector `$w`

, it gets even uglier. I don't foresee MathObjects being able to take coordinates of Formula objects in general. This is just beyond its design scope.

Davide

I think the issue you're referring to also occurs for things like

Compute("<t,t^2,sin(t)>")->value;

that construct a vector of functions in a different way. The prior discussion you are alluding to is

http://webwork.maa.org/moodle/mod/forum/discuss.php?d=2284

Notice that at the end of that discussion I gave a total "hack" of an answer that should probably never be used (so please don't read that part ).

Best regards,

Paul

`value()`

method does break up the object into its components, so
($f1,$f2,$f3) = Compute("<t,t^2,sin(t)>")->value;will make

`$f1`

be `t`

, `$f2`

would be `t^2`

, and `$f3`

would be `sin(t)`

.
This is useful when you are using objects you have created itself, but it would not be wise to use this on student answers, since there is no guarantee that they will have entered a vector in this way (and not as a vector expression). I suppose one could test the class of the top-level node of the expression tree, but it is not clear what you would do if it weren't a Vector.

Davide

**The call to**`ans_array`

leave a button with a pi on it over the (1,2) entry.As others have pointed out, this is a link to the MathView editor. It is relatively new, and there are still kinks being worked out. Personally, I think the icon is too big, and I'd like a user-preference for turing it off, but it is what it is. There is a course-wide preference for it in the configuration manager. In the slides for my talk, I did a sneaky thing to make the icon never appear, but I would like to see it at least be removed when the input item loses focus.

**Only the first entry is highlighted in red or green for correct/incorrect.**Yes, that is true. The coloring of the entry blanks is also relatively new, and MathObjects long predates that. Mike has been making lots of new changes to the core PG functions to help make things like the coloring of answer blanks work better. I understand there is support for groups of answer blanks.

The answer array has only one answer checker, but several blanks, and really only one of them is officially tied to the answer checker (and so it get the color). The Matrix object takes care of looking for the other ones when the answer is checked. But PG doesn't know about the other ones, so doesn't know to color them, and MathObjects doesn't know about colored blanks (since it was written before they were available), so we have the present unhappy situation of bad coloring for answer arrays.

This is something I need to fix, and that means learning Mikes new features for answer grouping. This is on the list of things to do, but hasn't been done yet.

**It would be nice to have a Context('rational')**I'm not sure exactly what you are after. If you are after rational numbers (i.e., fractions), then there is already a

`contextFraction.pl`

that implements that. If you are after rational functions, Gavin already pointed you to a context for that. If neither of these is what you are after, can you be more precise about what you are looking for?
`assign`

function that you can use to modify the entries in a Matrix. The simplest form is the following:
sub assign { my $self = shift; my $index = shift; my $x = shift; my $i = shift(@$index) - 1; if (scalar(@$index)) {assign($self->{data}[$i],$index,$x)} else {$self->{data}[$i] = Value::makeValue($x)} }This takes three arguments, the Matrix to modify, an array reference of the indices of the entry to change, and the value to place at that entry. Note that the indices are shifted, so [1,1] refers to the first entry (not [0,0] as needed in Perl).

For example

$M = Matrix([1,2],[3,4]); assign($M,[2,1],10);leaves

`$M`

as the matrix `[[1,2][10,4]]`

.
Note that Matrix objects are more general than just *n* x *m* matrices; they can be any dimension (1 or 3 or whatever). For example

$M1 = Matrix([1,2,3]); # 1-dimensional, basically a vector $M3 = Matrix([[1,2],[3,4]],[[5,6],[7,8]]); # 3D matrixThis

`assign()`

function works no matter what the dimension. For example, you could use
assign($M3,[2,1,1],-50);to replace the 5 in

`$M3`

by -50.
The assignment function operates recursively by pulling off the first index, *i* from the list and applying `assign()`

to a sub-matrix (the *i*-th entry in its list of data). When it gets to the last entry, it replaces the element with the given value.

Note that this means you could replace not just a single entry, but an entire sub-matrix. For example, in a 2D matrix, you could replace a whole row, as in

assign($M,[1],[10,20]);to replace the first row by the row

`[10,20]`

.
Of course, the assignment function really should be more sophisticated and do some error checking to make sure that you are replacing an entry with something compatible (i.e., an entry with a single number, or a row with another row of the correct size).

Here's a modified version that gives you the idea

sub assign { my $self = shift; my $index = shift; my $x = shift; my $i = shift(@$index) - 1; Value->Error('Entry doesn't exist: %d",%i) unless defined $self->{data}[$i]; if (scalar(@$index)) { assign($self->{data}[$i],$index,$x); } else { $x = Value::makeValue($x); my $a = $self->{data}[$i]; Value->Error("Entry type should be %s not %s",$a->type,$x->type) unless $a->type eq $x->type; if ($a->type eq 'Matrix') { my ($da,$dx) = (join('x',$a->dimensions),join('x',$x->dimensions)); Value->Error("Entry dimension should be %s not %s",$da,$dx) unless $da eq $dx; } $self->{data}[$i] = $x; } }Anyway, hope these help.

Is contextFraction what you want?

http://webwork.maa.org/pod/pg_TRUNK/macros/contextFraction.pl.html or

http://webwork.maa.org/viewvc/system/trunk/pg/macros/contextFraction.pl?view=markup

Gavin