Features & Development

Problems with contextPiecewiseFunction.pl

Problems with contextPiecewiseFunction.pl

by Robin Cruz -
Number of replies: 5
I get an error message:

Error messages

No such package 'Value::InequalitySet' at line 675 of [PG]/macros/contextInequalities.pl Died within Inequalities::Inequality::new called at line 458 of [PG]/macros/contextInequalities.pl from within Inequalities::common::apply called at line 464 of [PG]/macros/contextInequalities.pl from within Inequalities::common::sub called at line 738 of [PG]/lib/Value.pm from within Value::binOp called at line 746 of [PG]/lib/Value.pm from within Value::_sub called at line 253 of [PG]/lib/Value/Interval.pm from within Value::Interval::contains called at line 497 of [PG]/macros/contextPiecewiseFunction.pl from within PiecewiseFunction::Function::eval called at line 73 of [TMPL]/Problems/setAlgebra_02_01_IntroFunctions/IntAlg_13_function.pg

When I tried this code:
loadMacros(
"PGstandard.pl",
"MathObjects.pl",
"contextLimitedNumeric.pl",
"contextPiecewiseFunction.pl"
);

TEXT(beginproblem);

######################################
# Setup

Context("PiecewiseFunction");

$m1 = random(2,5,1);
$b1 = non_zero_random(-6,6,1);
$m2 = random(-5,-2,1);
$b2 = random(1,6,1);
$x = random(-4,4,1);

$g = Formula("$m1 x + $b1 if x <= $x else $m2 x - $b2 if x > $x");
@in = (random($x-3,$x-1,1),random($x+1,$x+3,1),$x);
@slice = NchooseK(3,3);
@input = @in[@slice]; #There are more parts in my problem

######################################
# Main text

BEGIN_TEXT
The following function is defined by two equations. The equation in the
first row gives the output for values of $BITALIC x $EITALIC less than
$x. The equation in the second row gives the ouput for values
of $BITALIC x $EITALIC which are greater or equal to $x.
\[ g(x) = \{$g->TeX\} \]
Find the indicated valuea:
$PAR
a) \( g($input[0]) \) = \{ans_rule(15)\}}
END_TEXT

######################################
# Answers
Context("LimitedNumeric");

$ans_a = $g->eval(x=>$input[0])->reduce;
ANS($ans_a->cmp);

Thanks -- rac
In reply to Robin Cruz

Re: Problems with contextPiecewiseFunction.pl

by Davide Cervone -
Robin:

It turns out there was a bug in contextInequalities.pl that caused it to fail to maintain the context properly during some operations (that were being performed during the eval() operation at the bottom of the problem). I have fixed the error and committed the changes to the CVS archive.

There are a couple of other issues with your code, however. First, $g->eval(...) is no longer a Formula, so doesn't have a reduce() method. It is just a constant, so can't be reduced.

Second, the result of evaluating a Formula object will always be in the same context as the Formula itself, despite the current context. This is because the operations involved in the formula, and the types of values it produces, may not even be defined in the current context. (This is the type of error you observed here.) So your $ans_a will be in the PiecewiseFunction context, no the LimitedNumeric context.

There are several ways to get it into the current context. For example:

    $ans_a = Real($g->eval(x=>$input[0])->value);
or, perhaps better:
    $ans_a = $g->eval(x=>$input[0])->inContext(Context());

Finally, you probably should use \(x\) rather than $BITALIC x $EITALIC, since this will produce x in the same font and style as the rest of the mathematics.

Hope this helps.

Davide

In reply to Davide Cervone

Re: Problems with contextPiecewiseFunction.pl

by Robin Cruz -

OK, I'm almost there.  The answer checker is working with the piecewise function with the code you suggested, but the function is not displaying in the text part of the problem.  It displays a message in the problem:

"Couldn't find \end for begin{cases}"

Thanks for your help -- rac

In reply to Robin Cruz

Re: Problems with contextPiecewiseFunction.pl

by Davide Cervone -
This has to do with calling \{$g->TeX\} rather than using Context()->texStrings and Context()->normalStrings around your BEGIN_TEXT/END_TEXT block. It turns out that the TeX form of a PiecewiseFunction uses dollar signs, and the way BEGIN_TEXT/END_TEXT works is to do command substitution first, then variable substitution and then math substitution. That means that the \{$g->TeX\} inserts a string that includes dollar signs, and then the variable substitution pass is done, and those dollars are treated like variable references, which they aren't. And that messed up the TeX string, causing the error you saw. On the other hand, when Context()->texStrings is used, and you have\[g(x) = $g\], the TeX isn't inserted during the command substitution phase (there is no command to be peformed), but rather during the variable substitution phase, and so the dollars are not seen as additional variable references, and so everything is OK. That was how I was testing the PiecewiseFunctions, and so didn't catch the problem.

I have fixed the contextPiecewiseFunctions.pl file so that you can do it either way.

Davide

PS, you may also want to reduce your $g by adding

    $g = $g->reduce('(-x)-y'=>0,'(-x)*y'=>0);
at some point since your constant term in the first branch can be negative.

Finally, you may want to make your $x's in the text block be \($x\), since they can include negative signs, which will be incorrectly displayed as hyphens if they are just in plain text.

In reply to Davide Cervone

Re: Problems with contextPiecewiseFunction.pl

by Robin Cruz -

OK, my piecewise functions are looking pretty good now. Thanks.

Now: I wanted to graph a piecewise function.  It does not seem to be working.  Note that I have used "Formula" to create functions to graph and they work just fine, but if the function is a piecewise function I get the error message:

Error messages

Error in plot_functions: Error in parsing: -4*x+(-12) if -4 <= x < -3 else -1.33333*x+(-4) if -3 <= x < 0 else 2*x+(-4) if 0 <= x < 2 else 1.5*x+(-3) if 2 <= x <= 4 for x in [-5,5] using color:red and weight:3
at line 344 of [PG]/macros/PGgraphmacros.pl Died within main::plot_functions called at line 292 of [PG]/macros/PGgraphmacros.pl from within main::add_functions called at line 65 of [TMPL]/Problems/setAlgebra_02_02_AlgebraOfFunctions/IntAlg_11_functOperation.pg

Error details

 Problem11 ERROR caught by Translator while processing problem file:Problems/setAlgebra_02_02_AlgebraOfFunctions/IntAlg_11_functOperation.pg **************** Error in plot_functions: Error in parsing: -4*x+(-12) if -4 <= x < -3 else -1.33333*x+(-4) if -3 <= x < 0 else 2*x+(-4) if 0 <= x < 2 else 1.5*x+(-3) if 2 <= x <= 4 for x in [-5,5] using color:red and weight:3 
at line 344 of [PG]/macros/PGgraphmacros.pl Died within main::plot_functions called at line 292 of [PG]/macros/PGgraphmacros.pl from within main::add_functions called at line 65 of [TMPL]/Problems/setAlgebra_02_02_AlgebraOfFunctions/IntAlg_11_functOperation.pg

---------------------------------------------------------------------------------

Here's the code:

loadMacros(
  "PGstandard.pl",
  "MathObjects.pl",
  "PGnauGraphics.pl",
  "contextPiecewiseFunction.pl"
);

TEXT(beginproblem);

######################################
#  Setup

#----define the function pieces

@fxnum = (random(-5,-4,1),random(-3,-2,1),
         random(-1,0,1),random(1,2,1),random(3,4,1));
@fynum = (random(-4,4,1),random(-4,4,1),
         random(-4,4,1),random(-4,4,1),random(-4,4,1));

$i = 0;
do {
   $m = ($fynum[$i+1]-$fynum[$i])/($fxnum[$i+1]-$fxnum[$i]);
   $f_parts[$i] = Formula("$m*x + ($fynum[$i]-$m*$fxnum[$i])");
   $i=$i+1;
} until ($i>3);

#--------Define f---------
Context("PiecewiseFunction");

$f = PiecewiseFunction("[$fxnum[0],$fxnum[1])" => $f_parts[0],
                       "[$fxnum[1],$fxnum[2])" => $f_parts[1],
                       "[$fxnum[2],$fxnum[3])" => $f_parts[2],
                       "[$fxnum[3],$fxnum[4]]" => $f_parts[3]);
   
#----make the graph

$xmin = -5;
$ymin = -2;
$xmax = 5;
$ymax = 6;

$graph = init_graph_no_labels($xmin,$ymin,$xmax,$ymax,
                              axes =>[0,0],
                              grid =>[$xmax-$xmin,$ymax-$ymin]);
$f_graph = FEQ("$f for x in [$xmin,$xmax] using color:red and weight:3");
add_functions( $graph,$f_graph);

$input = random($fxnum[0],$fxnum[4],1);
######################################
#  Main text

BEGIN_TEXT
\{ Plot($graph, tex_size => 600) \}
$PAR
\( f($input) =\) \{ans_rule(20)\}
END_TEXT

######################################
#  Answers

Context("Numeric");
$f_value = $f->eval(x=>$input)->inContext(Context());
$ans_a = $f_value;
ANS($ans_a->cmp);

--rac

In reply to Robin Cruz

Re: Problems with contextPiecewiseFunction.pl

by Davide Cervone -
In order to use MathObject Formulas with the graphics routines, you need to use lower-level graphics calls rather than add_functions() and the other top-level plotting commands. This is because those routines use the old algebra parser rather than the MathObject parser to evaluate the mathematical formula to plot, and it doesn't know anything about things like "if" and "else".

But it's not that hard to do. Rather than

   $f_graph = FEQ("$f for x in [$xmin,$xmax] using color:red and weight:3");
   add_functions( $graph,$f_graph);
use
   $f_graph = new Fun($f->perlFunction,$graph);
   $f_graph->steps(10); $f_graph->color("red"); $f_graph->weight(3);
Here steps is chosen so that the corners of your function will be guaranteed to be plotted (otherwise you can get rounded-off corners). Since the function is linear in between the points, you can let the plotting routine do the interpolation between the grid lines. This speeds up the plotting.

Note, however, that your piecewise function will not be defined on the complete range that you have specified of -5 to 5 (since $fxnum[4] can be at most 4). That means you will get an error when trying to plot values higher than that. So you should probably make sure your function is defined over a wider range. Say

    $f = PiecewiseFunction(
      "[-6,$fxnum[0])" => $fynum[0],
      "[$fxnum[0],$fxnum[1])" => $f_parts[0],
      "[$fxnum[1],$fxnum[2])" => $f_parts[1],
      "[$fxnum[2],$fxnum[3])" => $f_parts[2],
      "[$fxnum[3],$fxnum[4])" => $f_parts[3],
      "[$fxnum[4],6]" => $fynum[4],
    );
which has the function being constant below $fxnum[0] and above $fxnum[4].

That should do it for you.

Davide