WeBWorK Main Forum

addToTeXPreamble

addToTeXPreamble

by Andrew Dabrowski -
Number of replies: 14
There is or was a function called "WeBWorK::PG::ImageGenerator::addToTeXPreamble" traces of which I have detected in cyberspace. I was hoping to be able to use this function to add "\newcommand" latex macros to my code.

That is, I was hopping to be able to write
WeBWorK::PG::ImageGenerator::addToTeXPreamble('\newcommand{test}{\mbox{Test Succeeded!}}');
and then be able to call this new macro from within a PGML section by
[` \test `]
Will this hope have to be abandoned?
In reply to Andrew Dabrowski

Re: addToTeXPreamble

by Alex Jordan -
Here is a workaround, if nothing better comes about.

$macro = '\newcommand{\test}{\mbox{Test Succeeded!}}';

BEGIN_PGML

Any math that uses the macro:
[`[$macro]1+1=2 \test`].

A second instance:
[`[$macro]1+1=2 \test`].

Any other math can omit this:
[`1+1=2`]

END_PGML

This will work onscreen with MathJax, onscreen with images, and in hardcopy, even in combination with other problems using the same macro name (with the same or even a different definition).

In reply to Alex Jordan

Re: addToTeXPreamble

by Andrew Dabrowski -
Maybe it's because I'm running WW 2.9, but PGML doesn't seem able to digest the latex macro. The following code

BEGIN_PGML

[` \newcommand{test}{\mbox{The Test worked.}}
\mbox{Macro defined above, called below.}
\test `]

[@ @]

END_PGML

yields
\newcommand{test}{\mbox{The Test worked.}} \mbox{Macro defined above, called below.} \test

It looks like PGML mostly ignored "\newcommand". (Except that it consumed the first letter of the argument. No idea why that happened - does PGML think \newcommand means drop first symbol?)
In reply to Andrew Dabrowski

Re: addToTeXPreamble

by Alex Jordan -
Is it just because you are missing a backslash?

\newcommand{\test}...

not

\newcommand{test}...
In reply to Alex Jordan

Re: addToTeXPreamble

by Michael Gage -
addToTeXPreamble is a method of the imageGenerator object, not a function, which affects how it's called.

It's use is described in the POD documentation here
as well as in the code for imageGenerator.

I haven't used it recently but I don't see any reason why it won't work as advertised for modifying presentation of mathematics symbols.  
In reply to Michael Gage

Re: addToTeXPreamble

by Andrew Dabrowski -
In reply to Andrew Dabrowski

Re: addToTeXPreamble

by Michael Gage -
errr.... according to the POD documentation page it's

$rh_envir->{imagegen}->addToTeXPreamble("\newcommand{\myVec}[#1]{\vec{#1}} ");
In reply to Michael Gage

Re: addToTeXPreamble

by Davide Cervone -
Note that this only affects mathematics in image mode, and the imagegen property is only available in that mode. So one would need to handle the other output modes separately.
In reply to Davide Cervone

Re: addToTeXPreamble

by Alex Jordan -
For another project, I recently had to investigate using LaTeX macros in pg files, and Davide points out a fundamental issue. Since you need to be considering images, MathJax, and print, (and anything else?), addToTeXPreamble alone is not going to be enough.

My solution was basically what I posted earlier, inserting the \newcommand into each instance of math where it is necessary. (My project inserts such things using automation, so it's not as tedious as it sounds.)

By the time you work out how to handle all the multiple output modes, it may end up being more work than just doing something like what I posted. Not to mention, who knows what future output modes might come into play? Directly using the macro code seems safe for such things, while a mode-by-mode approach might not have longevity.

The next thing that occurs to me would be to somehow modify the output of [`...`] and friends within a PG block to automatically insert the macros, but I wouldn't want to mess with tweaking PGML to do that.
In reply to Alex Jordan

Re: addToTeXPreamble

by Davide Cervone -
Here is an approach that I think should work. Start the problem with
$macros = join("",
  "\newcommand{\myMacro}{\mbox{This is myMacro!}}",
);

if ($displayMode eq "HTML_dpng") {
  $rh_envir->{imagegen}->addToTeXPreamble($macros);
} else {
  TEXT(MODES(
    TeX => "{".$macros,
    HTML => qq{
\($macros\)
}, )); } and use \myMacro in the problem as needed. At the end of the problem, add
TEXT("}") if $displayMode eq "TeX";
This should create the macros in the way needed by the various output modes (at least for hardcopy, MathJax, and Image modes), and localizes the macros to the given problem (except for MathJax mode in the library browser since macros in MathJax are global to the page).

One could, of course, create commands like

BeginTeXMacros(
   "\newcommand{\myMacro}{\mbox{This is myMacro}}",
);
...
EndTeXMacros();
that hide the mechanics of it, and load them from a local macro file if you want to do this in many problems.

Of course, the image-mode output does suffer from the same caching issue that we see below, so I would recommend doing development using MathJax mode instead.

In reply to Michael Gage

Re: addToTeXPreamble

by Andrew Dabrowski -
Stupid I am, but I don't want you to think I'm lazy: I actually did see that page before starting this thread, but that call doesn't seem to work. The following code

$rh_envir->{imagegen}->addToTeXPreamble("\newcommand{\test}{\mbox{The test succeeded!}}");

BEGIN_PGML

[` \test `]

END_PGML
results in nothing being printed. (And I am viewing the problem in image mode.) At least it doesn't produce an error, so there's hope.

Btw, what is $rh_envir exactly? Is it more than just a reference to %envir? It's not well documented.

And just to satisfy my curiosity, why doesn't the call
WeBWorK::PG::ImageGenerator::addToTeXPreamble()
work? Is WeBWorK shielded from .pg files?
In reply to Andrew Dabrowski

Re: addToTeXPreamble

by Michael Gage -
OK.

Did it work with the example given on the page (which modifies the manner of printing vectors)?  I believe that is the original use case that John Jones wrote it for.

I can't troubleshoot the macro right this minute and as Alex points out this macro, written before MathJax mode existed, may no longer be the best way to handle this situation.  I think I can answer your last two questions however.

$rh_envir (the rh is supposed to stand for reference-to-a-hash) is an anonymous hash passed into the PG environment. It is then unpacked into a regular hash (named) %envir in the file pg/macros/PG.pl so as to be more conveniently available.

Some of the macro files (and some PG problems) use $rh_envir directly, possibly because it is less likely that the contents have been modified from within a PG problem, or possibly for no particular reason -- just that it is available.

addTeXPreamble("TeXcommand_here") is a method which means that it requires an object in order to get its job done. For example it has to store this TeX command somewhere and the object gives it the information needed as to where to store it.   The image generator object (which knows how to use this method) is $rh_envir->{imagegen} and one of these image generator objects is created for each PG problem.  

Since perl shows you how things work "under the hood" it demystifies the concept of  "object method" somewhat.   

$rh_evir->{imagegen}>addTeXPreamble("TeXcommand_here") translates into a subroutine call of the 
form WeBWorK::PG::ImageGenerator::addToTeXPreamble()($rh_envir->{imagegen}, "TeXcommand_here").  Methods are merely subroutines whose first step is to accept a "$self" object. 

If a subroutine in a package starts with 
my $self = shift;  it's a method and called by $obj->subroutine_name() syntax.  If it doesn't it's a function and called via subroutine_name() (with the package name prepended if necessary). 

In reply to Andrew Dabrowski

Re: addToTeXPreamble

by Davide Cervone -
Note that the images of mathematics generated by WeBWorK are cached so that if the math has already been processed once, it doesn't have to be generated again. The caching is based on the TeX string, so if a TeX string has already generated an image, that image is used again the next time that TeX string is encountered.

If you have tried several times to get your problem to work, then the image cached from the first time will be used the second and subsequent times, so if the first one failed, you aren't actually getting the results from the second run but from the first one.

It appears that the caching doesn't take the preamble into account, so you either have to run the command-line script that flushes the cache, or you need to change the expression to one that isn't cached in order to get a fresh image for the second run.

The macro definition does work for me, so I am assuming that the cache is what is leading you to believe that it isn't. On the other hand, this does suggest a potential problem, since images cached without your preamble can be used, so you don't really know that your macro will be defined. On the other hand, the TeX strings that matter are the ones that actually use the macro, so they are not likely to be cached, except in the debugging case like you are seeing here.