PREP 2014 Question Authoring - Archived

kronecker delta and other functions

kronecker delta and other functions

by Joel Trussell -
Number of replies: 16
In signal processing, we use discrete sequences, e.g., s(​n) = {..., 0,1,3,-2, 0 ...} , where the 1 is in position n=0. We can define the sequence using the Kronecker delta as
s(​n) = delta(​n) + 3*delta(n-1) - 2*delta(n-2)
1) can I define a Kronecker delta in Webwork? delta(​n) = 1 for n = 0 and 0 else
2) if so, can the students use that function in answers?
3) I don't know that it is necessary, but can I restrict the arguments of s(.) to integers? I think I can get around this by specifying the test points to be integers
4) we use the unit step function a great deal. And make the substitution (or equivalence) of step(x) = u(x). Given the restriction to integers, could the kronecker delta be defined in terms of the unit step? creating a narrow pulse about zero?
5) is there a "nice" way to indicate the zero position in a sequence like the one s(​n) = {..., 0,1,3,-2, 0 ...}? In Latex we can underline or use up-arrows.
6) what about the extension to the Dirac delta in the continuous domain? I thought I'd ask.
In reply to Joel Trussell

Re: kronecker delta and other functions

by Gavin LaRose -
Some answers:
  1. We can add functions to the context in a problem; this is discussed on this page in the problem techniques section of the WeBWorK documentation wiki. The subroutine
    sub delta {
    shift; my $x = shift;
    return ($x == 0 ? 1 : 0);
    }

    might do what you want.
  2. If we define the function as noted in (1), students will be able to use it.
  3. You can restrict formulas to be evaluated only at integers as discussed here. Note the comment about having a variable in the context that is only evaluated at integers, in the right column.
  4. The step function is discussed on this page in the problem techniques documents. I'm not sure if we can define the step or delta in terms of each other, or if we would want to.
  5. I'm not sure what you're asking for the sequence question. In problems you have access to LaTeX markup, so we could resort to that to indicate the zero element—though how this is done might depend on the definition of the sequence.
  6. The above might deal with delta(x), with x as a real.
Gavin
In reply to Joel Trussell

Re: kronecker delta and other functions

by Paul Pearson -
Hi Joel,

We do plan to show you how to do this later in the workshop.

1 - 2. You can define named functions and add them to the context so that both you and the students can use them by name.  The ways to do this are shown on the following webpages:

http://webwork.maa.org/wiki/AddingFunctions
http://webwork.maa.org/wiki/ScalingTranslating1

3. If you want to restrict the arguments of a function to integers, then you will want to compare the student answer to the correct answer only at integer test points in the domain.  To add a variable n and restrict its values to integers you can specify integer endpoints [-20,20] for the domain and a resolution of 1:

Context()->variables->add(n => ['Real', limits=>[-20,20], resolution=>1]);

4. The Heaviside step function is discussed in detail on the following page:

http://webwork.maa.org/wiki/HeavisideStep1

The trickiest part about using functions like this is setting the domain for function evaluation correctly when checking student answers.  We will discuss issues like this in more detail later in the workshop.

5. This needs more clarification.  What do you mean by nice?  Indicate position for what purpose?

6. Dirac delta might be more challenging, but should be doable.  Why don't you try to construct one yourself (using what you've learned from above) and submit your PG code to the forum for review.  I expect you will run into some challenges, but I think it would be good for everyone on the forum to see what challenges you're facing and to get suggestions from others about how to make things work.  

One trick I have used in the past is to define a named function in a way that is contrary to it's actual definition, such as setting the Dirac delta function to be Dirac(x) = sin(e*x/pi)+1.57*x^2.  Hypothetically, if the correct answer is 

$answer = Compute("5*Dirac(2*x)");

when a student enters "3*Dirac(2*x)" as an answer, webwork will internally evaluate this comparing the correct answer "5*(sin(e*2*x/pi)+1.57*(2*x)^2)" to the student answer "3*(sin(e*2*x/pi)+1.57*(2*x)^2)" at several randomly chosen test points and conclude that the student's answer is incorrect.

Alternatively, you could define Dirac(x) to be the actual Dirac delta function, but you would then have to specify very carefully what the test points for function evaluation should be (rather than relying on randomly selected test points).

Best regards,

Paul Pearson


In reply to Paul Pearson

Re: kronecker delta and other functions

by Joel Trussell -
Great - so far - I got the function kdelta in and it can be evaluated. Since the problem is a DFT, I want to test the student's formula at all integers from [0] ..[$N-1]. I tried 
$X = Formula("0.5*$N*kdelta(k-$n_n) + 0.5*$N*kdelta($N-(k+$n_n))")->reduce;
$X ->{test_points} = [[0]..[$N-1]];  # test at all integers 0 to (N-1)
that doesn't work, in fact $X ->{test_points} = [[0],[$N-1]]; gives an error 
Can't evaluate formula on test point (0)

the entire problem is given below
 ##DESCRIPTION
##  Algebra problem: true or false for inequality 
##ENDDESCRIPTION

##KEYWORDS('algebra', 'inequality', 'fraction')

## DBsubject('Algebra')
## DBchapter('Fundamentals')
## DBsection('Real Numbers')
## Date('6/3/2002')
## Author('')
## Institution('')
## TitleText1('Precalculus')
## EditionText1('3')
## AuthorText1('Stewart, Redlin, Watson')
## Section1('1.1')
## Problem1('22')

########################################################################

DOCUMENT();      

loadMacros(
   "PGstandard.pl",     # Standard macros for PG language
   "MathObjects.pl",
   #"source.pl",        # allows code to be displayed on certain sites.
"PGcourse.pl",      # Customization file for the course
);

# DFT of periodic series

TEXT(beginproblem());

# Show which answers are correct and which ones are incorrect
$showPartialCorrectAnswers = 1;

##############################################################
#
#  Setup
#
#
Context("Numeric");
Context()->variables->add(n=> 'Real', k=>'Real');
Context()->functions->add(
    u => {
      class => 'Parser::Legacy::Numeric',
      perl => 'Parser::Legacy::Numeric::do_step'
    },
  );


package NewFunc;
# this next line makes the function a 
#   function from reals to reals
our @ISA = qw(Parser::Function::numeric);

sub kdelta {
shift; my $x = shift;
return ($x == 0 ? 1 :0);
}  # end subroutine

package main;

# Make it work on formulas as well as numbers
sub kdelta {Parser::Function->call('kdelta',@_)}

#  Add the new functions to the Context
Context()->functions->add(
  kdelta => {class => 'NewFunc',
           TeX => '\delta'}, );

$N = random(4,20,1); # period
$n_n = random(1,($N-1),1); # numerator of digital freq  n0/N
do {$n_n = random(1,($N-1),1);} until ($N % $n_n != 0);  # need mod function ( %) here
$n0 =  random(0,($N-1),1); # shift of sequence
$div= list_random(1,2,3,4,-2,-3,-4); # phase = pi/div
$theta = pi/$div;
$A = random(1,9,1); # amplitude

#$x = Formula("$A \( \cos(2 \pi \frac{$n_n}{$N} (n-$n0)-$theta) \)")->reduce;
$x = Formula("$A cos(2 pi ($n_n)/$N (n-$n0)-pi/$div) ")->reduce;
$X = Formula("0.5*$N*kdelta(k-$n_n) + 0.5*$N*kdelta($N-(k+$n_n))")->reduce;
$X ->{test_points} = [[0],[4],[$N-1]];  # test at all integers 0 to (N-1)


##############################################################
#
#  Text
#
#

Context()->texStrings;
BEGIN_TEXT
This problem is related to 4.x in the text. 
$PAR
Given the periodic sequence, $tk0, $tk1, $tkm1
\[ 
x(n) = $x,
\]
$PAR
find the discrete Fourier transform, \(X(k) \)
$BR
$BR  \( X(k) = \)   \{ $X ->ans_rule(40)\}


END_TEXT
Context()->normalStrings;

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


ANS($X->cmp());



ENDDOCUMENT();        

In reply to Joel Trussell

Re: kronecker delta and other functions

by Gavin LaRose -
Hi Joel,

A couple of thoughts:

  1. First, you have Context()->variables->add(n=>'Real', k=>'Real');, so there are actually three variables in your problem (the default, x, plus the two you added, n and k). So when you set the test points you need to specify all three (in alphabetical order). Thus I think your test_points declaration, $X ->{test_points} = [[0],[4],[$N-1]];, should specify three values per point: $X->{test_points} = [[0,0,0],[1,1,1],[2,2,2],[3,3,3],[$N-1,$N-1,$N-1]];.
  2. Similarly, where you had [[0]..[$N-1]] I think it will fail because the .. operator generates lists of incrementable values (like integers and letters). Here [0],[1] (etc.) are actually (references to) arrays of one element, for which there isn't an obvious increment.

This last brings up a couple of things about Perl that we didn't really discuss in the workshop:

  • @a = (0,'a',1,3) is an array of four elements, with $a[1] = 'a', etc., but
  • $a = ['a',1,4,9] is a reference to an array. The square brackets in Perl create the array reference. The same thing can be obtained by setting @b = ('a',1,4,9) and then $a = \@b to set $a as a reference to the array @b. A similar thing can be done by taking $a = [@b], but this then makes $a a reference to a copy of @b (so that if we then change one, we don't change the other).
  • Elements of the referenced array are obtained with $a->[index] (so that $a-&gt[2] from above is equal to 4). Note that this is the same operator we use to invoke a method of an object.
  • Similarly, %c = ( a=>1, b=>5 ); is a hash (dict in python and other languages), while
  • $d = { a=>1, b=>5 } is a reference to a hash. Elements of the reference are also obtained with the -> operator: $d->{b} is equal to 5, in the same way $c{b} from above would be equal to 5. (Note that this is the same syntax as things like $X->{test_points}, which suggests, correctly, that what is really going on there is that we are accessing values in a hash reference.)

Gavin

In reply to Gavin LaRose

Re: kronecker delta and other functions

by Joel Trussell -
I sorta under stand the use of @a. in your examples
 $P = []; for ($m=0; $m[$m] = [$m,$m]; } $X ->{test_points} = $P;
and
 $X->{tet_points} = []; for ($m=0; $m{test_points}[$m] = [$m,$m]; }
How does PG know to stop at $N-1?
 

In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
Sorry, the system ate part of the examples. I wasn't careful enough about less-than signs, and so they got interpreted as HTML tags (up to the next greater-than sign). I've updated the examples. So look here again.
In reply to Davide Cervone

Re: kronecker delta and other functions

by Joel Trussell -
I'm trying to implement a DSP problem for my colleagues at NCSU. I've run into a problem where things looked OK until I tried to check the functions. It appears that after making the substitution/equivalence u(t) = step, I can't evaluate the function. 

I get the error

ERRORS from evaluating PG file:
Undefined subroutine &main::u called at line 135 of (eval 11115)
the line in the code is
135		for ($k = -2;$k<=2;$k++) {$ut[$k+2]=u($k);}
I originally did a quick and dirty kroneker delta definition
#parserFunction("kdelta(​n)" => "u(n+0.1)-u(n-0.1)"); #kronecker delta approximation
which worked - i.e., I could evaluate kdelta OK, but when I tried to evaluate u(​n) I got the error.

The entire code is below

##DESCRIPTION
##  Algebra problem: true or false for inequality
##ENDDESCRIPTION

##KEYWORDS('algebra', 'inequality', 'fraction')

## DBsubject('Algebra')
## DBchapter('Fundamentals')
## DBsection('Real Numbers')
## Date('6/3/2002')
## Author('')
## Institution('')
## TitleText1('Precalculus')
## EditionText1('3')
## AuthorText1('Stewart, Redlin, Watson')
## Section1('1.1')
## Problem1('22')

########################################################################

DOCUMENT();

# modified to use j for i = sqrt(-1)
$complexJ =1;   # 0 => i, 1 => j
$I = ($complexJ)? 'j': 'i';

loadMacros(
   "PGstandard.pl",     # Standard macros for PG language
   "MathObjects.pl",
   "AnswerFormatHelp.pl",
   ($complexJ) ? "contextComplexJ.pl"  : "",
#"source.pl",        # allows code to be displayed on certain sites.
"PGcourse.pl",      # Customization file for the course
);

# DTFT of aperiodic series geometric series

TEXT(beginproblem());

# Show which answers are correct and which ones are incorrect
$showPartialCorrectAnswers = 1;

##############################################################
#
#  Setup
#
#
Context("Complex");
Context()->variables->add(n=> 'Real');
Context()->variables->remove(z); # only variables should be n
Context()->functions->add(
    u => {
      class => 'Parser::Legacy::Numeric',
      perl => 'Parser::Legacy::Numeric::do_step'
    },
  );

# tried this and include ParserFunction.pl
#parserFunction("kdelta(​n)" => "u(n+0.1)-u(n-0.1)"); #kronecker delta approximation
#    this works if the student and answer checker evaluates functions at integers

# use kdelta defined by LaRose

package NewFunc;
# this next line makes the function a
#   function from reals to reals
our @ISA = qw(Parser::Function::numeric);

sub kdelta {
shift; my $x = shift;
return ($x == 0 ? 1 :0);
}  # end subroutine

package main;

# Make it work on formulas as well as numbers
sub kdelta {Parser::Function->call('kdelta',@_)}

#  Add the new functions to the Context
Context()->functions->add(
  kdelta => {class => 'NewFunc',
           TeX => '\delta'}, );


$a = non_zero_random(-2,2,1); # nonzero offset
$n0 = random(-6,-3,1); # lower_limit
$n0inc = random(3,5,1); # range of formula 1
$n1 = $n0 + $n0inc; # upper limit of formula 1

$n2 = random($n1+1,$n1+5,1); # lower_limit of formula 2
$n2inc = random(3,5,1); # range of formula 2
$n3 = $n2 + $n2inc; # upper limit of formula 2
$lower_lim = $n0-1;
$upper_lim = $n3+1;
$lower_lim_p1 = $lower_lim +1;  # need for text index
$D =  random(2,8,1); # denominator of fraction in f1
$Nx = $upper_lim - $lower_lim +1;  # number of samples for x(​n)

# compute limits for y(​n) = x(-n+n0)
$n1y = -$n3 +$n0;  # should be negative
$n3y = -$n1 + $n0;  #should be positive
$maxlim = max(-$n1y,$n3y); #  make limits symmetric
$lower_limy = -$maxlim;
$upper_limy = $maxlim;
$lower_limy_p1 = $lower_limy +1;  # need for text index

$Ny = $upper_limy - $lower_limy +1;  # number of samples for y(​n)


$f1 = Formula("$a+ n/$D")->reduce; # formula 1
$f2 = Formula("1")->reduce; # formula 2

$f3 = Formula("($a+n/$D)*(u(n-$n0)-u(n-$n1-1)) +u(n-$n2)-u(n-$n3-1)")->reduce; #answer
$f3->{test_points} = [[$n0-1], [$n0], [$n0+1], [$n1-1], [$n1], [$n1+1],[$n2-1], [$n2], [$n2+1],[$n3-1], [$n0], [$n3+1]];

# alternative answer
$f4 = Formula("($a+n/$D)*(u(n-$n0)-u(n-$n1-1)) +kdelta(n-$n2)+kdelta(n-$n2+1)+kdelta(n-$n2+2)+kdelta(n-$n2+3)+kdelta(n-$n2+4)")->reduce;
$f4->{test_points} = [[$n0-1], [$n0], [$n0+1], [$n1-1], [$n1], [$n1+1],[$n2-1], [$n2], [$n2+1],[$n3-1], [$n0], [$n3+1]];

#for ($k = $n0;$k<=($n3);$k++) {$xcheck1[$k] = $f3 -> eval(n =>$k);}
#for ($k = $n0;$k<=($n3);$k++) {$xcheck2[$k] = $f4 -> eval(n =>$k);}

# Compute x(​n)
for ($k = 0;$k<=$Nx-1;$k++) {$x[$k]=0;}
for ($k = 1;$k<=($n0inc+1);$k++) {$x[$k] = $f1 -> eval(n =>($n0+$k-1));}
for ($k = 1+$n2-$n0;$k<=($n2inc+$n2-$n0+1);$k++) {$x[$k] = 1;}

# compute y(​n)
$yindx0 = $upper_limy;
$yindx_start = $yindx0 - $upper_lim+$n0;
for ($k = 0;$k<=$Ny-1;$k++) {$y[$k]=0;}
for ($k = 0;$k<=$Nx-1;$k++) {$y[$yindx_start+$k] = $x[$Nx-1 -$k];}

for ($k = 0;$k<=3;$k++) {$d[$k]=kdelta(2-$k);}
for ($k = -2;$k<=2;$k++) {$ut[$k+2]=u($k);}

##############################################################
#
#  Text
#
#

Context()->texStrings;
BEGIN_TEXT
This problem is related to 2.1 in the text.
$PAR
Given the discrete-time signal, $n0, $n1, $n2, $n3, $d[1], $d[2], $d[3], $ut[1],$ut[1]
\[
x(​n) = \left\lbrace \begin{array}{ l l } $f1 & \mbox{ if } $n0 \leq n \leq $n1 \\
1 & \mbox{ if } $n2 \leq n \leq $n3 \\

0 & \mbox{ else. }  \end{array} \right.
\]
$PAR
(a) determine the values for \(  $lower_lim \leq n  \leq $upper_lim \)
$BR
Enter the values as a vector of the form: \( < x($lower_lim),x($lower_lim_p1), ... , x($upper_lim) \)> $BR
 \{ ans_rule(60)\}  \{ AnswerFormatHelp("vectors") \} $BR
(b) for \( y(​n) = x(-n+$n0) \), determine the values for  \(  $lower_limy \leq n  \leq $upper_limy \)
$BR
Enter the values as a vector of the form: \( < y($lower_limy),y($lower_limy_p1), ... , y($upper_limy) \)> $BR
 \{ Real($n2) ->ans_rule(60)\}  \{ AnswerFormatHelp("vectors") \} $BR

$PAR
(c) rewrite \( x(​n) \) in terms of \( \delta(​n) \) and \( u(​n) \)
$BR
Use delta(​n) for \( \delta(​n) \)
$BR \(x(​n)= \)   \{ Real($n3) ->ans_rule(80)\} \{ AnswerFormatHelp("formulas") \}

END_TEXT
Context()->normalStrings;

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


#ANS($xvalues->cmp(ordered=>1));
ANS(Vector(@x)->cmp());
ANS(Vector(@y)->cmp());
ANS(Real(Formula($f3))->cmp());


ENDDOCUMENT();
In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
The problem is actually what it says in the error message: the subroutine u() is undefined. Note that adding a function to a Context does not make it available to use in Perl expressions, only in strings passed to MathObject constructors like Compute(). Because you are wanting to use u() as a function in Perl, you need to give it a definition in Perl. Something like
sub u {Parser::Legacy::Numeric::do_step(@_)}
should do it. (Note that your kdelta function does something like that in order to get kdelta() defined for use in Perl directly.)

While I'm here, should note that there are several other issues in your code. Some things I see right away are:

  1. The statement
    ANS(Real(Formula($f3))->cmp());
    
    should be
    ANS($f3->cmp);
    
    since $f3 is already a formula, and can't be turned into a Real (doing so just returns the formula again).

Your vectors aren't in Vector context, so your students won't be able to enter them (the angle brackets aren't defined in the Complex context.

I'm not sure why you are in Complex context anyway, since nothing here is complex. Perhaps you just want to be able to process complex answers if the students type them?

The TeX code for your vectors would be better if you used \langle and \rangle rather than < and >, as these will format better. (You could have used MathObject to format that for you, I suppose.)

There is a \begin{cases}...\end{cases} environment that could be used to format the expression for x() more easily.

Hope that helps.

In reply to Davide Cervone

Re: kronecker delta and other functions

by Joel Trussell -
1) thanks - left over from previous debug try
2) I added the Context("Vector") right before the BEGIN_TEXT. I had it n earlier and checked the input but took it out later for some reason and didn't recheck the input. 3) granted but so many of the DSP problems are complex - originally I thought I could have the answer as an ordered list. But I couldn't figure out how to convert the array x to a list, so I did Vector and changed at the point where I needed it for input.
4)I tried this but it seems using the < rather than \langle makes it easier for the students to know what to type.
5) thanks - I'll check that

I'm having a problem with the formula in the 3rd answer. So I tried to compute the values using a couple of different formulas, $f3 and $f4. When I tried to evaluate the formulas, I get the error

ERRORS from evaluating PG file:
Can't take u of 0 at line 120 of (eval 2543)
120		for ($k = $n0;$k<=($n3);$k++) {$xcheck1[$k] = $f3 -> eval(n =>$k);}
What's wrong here? If I have the formula right, then I could use it to compute the values of x(​​n) more easily than either the double for loop that I use now, or the cases.

Here is the code - I REALLY appreciate the help.

DOCUMENT();

# modified to use j for i = sqrt(-1)
$complexJ =1;   # 0 => i, 1 => j
$I = ($complexJ)? 'j': 'i';

loadMacros(
   "PGstandard.pl",     # Standard macros for PG language
   "MathObjects.pl",
   "AnswerFormatHelp.pl",
   ($complexJ) ? "contextComplexJ.pl"  : "",
#"source.pl",        # allows code to be displayed on certain sites.
"PGcourse.pl",      # Customization file for the course
);

# DTFT of aperiodic series geometric series

TEXT(beginproblem());

# Show which answers are correct and which ones are incorrect
$showPartialCorrectAnswers = 1;

##############################################################
#
#  Setup
#
#
Context("Complex");
Context()->variables->add(n=> 'Real');
Context()->variables->remove(z); # only variables should be n
Context()->functions->add(
    u => {
      class => 'Parser::Legacy::Numeric',
      perl => 'Parser::Legacy::Numeric::do_step'
    },
  );

# tried this and include ParserFunction.pl
#parserFunction("kdelta(​​n)" => "u(n+0.1)-u(n-0.1)"); #kronecker delta approximation
#    this works if the student and answer checker evaluates functions at integers

# use kdelta defined by LaRose

package NewFunc;
# this next line makes the function a
#   function from reals to reals
our @ISA = qw(Parser::Function::numeric);

sub kdelta {
shift; my $x = shift;
return ($x == 0 ? 1 :0);
}  # end subroutine

package main;

# Make it work on formulas as well as numbers
sub kdelta {Parser::Function->call('kdelta',@_)}
sub u {Parser::Legacy::Numeric::do_step(@_)}
#  Add the new functions to the Context
Context()->functions->add(
  kdelta => {class => 'NewFunc',
           TeX => '\delta'}, );


$a = non_zero_random(-2,2,1); # nonzero offset
$n0 = random(-6,-3,1); # lower_limit
$n0inc = random(3,5,1); # range of formula 1
$n1 = $n0 + $n0inc; # upper limit of formula 1

$n2 = random($n1+1,$n1+5,1); # lower_limit of formula 2
$n2inc = random(3,5,1); # range of formula 2
$n3 = $n2 + $n2inc; # upper limit of formula 2
$lower_lim = $n0-1;
$upper_lim = $n3+1;
$lower_lim_p1 = $lower_lim +1;  # need for text index
$D =  random(2,8,1); # denominator of fraction in f1
$Nx = $upper_lim - $lower_lim +1;  # number of samples for x(​n)

# compute limits for y(​n) = x(-n+n0)
$n1y = -$n3 +$n0;  # should be negative
$n3y = -$n1 + $n0;  #should be positive
$maxlim = max(-$n1y,$n3y); #  make limits symmetric
$lower_limy = -$maxlim;
$upper_limy = $maxlim;
$lower_limy_p1 = $lower_limy +1;  # need for text index

$Ny = $upper_limy - $lower_limy +1;  # number of samples for y(​n)


$f1 = Formula("$a+ n/$D")->reduce; # formula 1
$f2 = Formula("1")->reduce; # formula 2

$f3 = Formula("($a+n/$D)*(u(n-$n0)-u(n-$n1-1)) +u(n-$n2)-u(n-$n3-1)")->reduce; #answer
$f3->{test_points} = [[$n0-1], [$n0], [$n0+1], [$n1-1], [$n1], [$n1+1],[$n2-1], [$n2], [$n2+1],[$n3-1], [$n0], [$n3+1]];

# alternative answer
$f4 = Formula("($a+n/$D)*(u(n-$n0)-u(n-$n1-1)) +kdelta(n-$n2)+kdelta(n-$n2+1)+kdelta(n-$n2+2)+kdelta(n-$n2+3)+kdelta(n-$n2+4)")->reduce;
$f4->{test_points} = [[$n0-1], [$n0], [$n0+1], [$n1-1], [$n1], [$n1+1],[$n2-1], [$n2], [$n2+1],[$n3-1], [$n0], [$n3+1]];

for ($k = $n0;$k<=($n3);$k++) {$xcheck1[$k] = $f3 -> eval(n =>$k);}
#for ($k = $n0;$k<=($n3);$k++) {$xcheck2[$k] = $f4 -> eval(n =>$k);}

# Compute x(​n)
for ($k = 0;$k<=$Nx-1;$k++) {$x[$k]=0;}
for ($k = 1;$k<=($n0inc+1);$k++) {$x[$k] = $f1 -> eval(n =>($n0+$k-1));}
for ($k = 1+$n2-$n0;$k<=($n2inc+$n2-$n0+1);$k++) {$x[$k] = 1;}

# compute y(​n)
$yindx0 = $upper_limy;
$yindx_start = $yindx0 - $upper_lim+$n0;
for ($k = 0;$k<=$Ny-1;$k++) {$y[$k]=0;}
for ($k = 0;$k<=$Nx-1;$k++) {$y[$yindx_start+$k] = $x[$Nx-1 -$k];}

for ($k = 0;$k<=3;$k++) {$d[$k]=kdelta(2-$k);}
for ($k = -2;$k<=2;$k++) {$ut[$k+2]=u($k);}
$u0 = u(0);

##############################################################
#
#  Text
#
#
Context("Vector");
Context()->texStrings;
BEGIN_TEXT
This problem is related to 2.1 in the text.
$PAR
Given the discrete-time signal, $n0, $n1, $n2, $n3, $d[1], $d[2], $d[3], $ut[0], $ut[1], $ut[2], $ut[3], $ut[4], $u0
\[
x(​n) = \left\lbrace \begin{array}{ l l } $f1 & \mbox{ if } $n0 \leq n \leq $n1 \\
1 & \mbox{ if } $n2 \leq n \leq $n3 \\

0 & \mbox{ else. }  \end{array} \right.
\]
$PAR
(a) determine the values for \(  $lower_lim \leq n  \leq $upper_lim \)
$BR
Enter the values as a vector of the form: \( < x($lower_lim),x($lower_lim_p1), ... , x($upper_lim) \)> $BR
 \{ ans_rule(60)\}  \{ AnswerFormatHelp("vectors") \} $BR
(b) for \( y(​n) = x(-n+$n0) \), determine the values for  \(  $lower_limy \leq n  \leq $upper_limy \)
$BR
Enter the values as a vector of the form: \( \langle y($lower_limy),y($lower_limy_p1), ... , y($upper_limy) \rangle \) $BR
 \{ Real($n2) ->ans_rule(60)\}  \{ AnswerFormatHelp("vectors") \} $BR

$PAR
(c) rewrite \( x(​n) \) in terms of \( \delta(​n) \) and \( u(​n) \)
$BR
Use delta(​n) for \( \delta(​n) \)
$BR \(x(​n)= \)   \{ Real($n3) ->ans_rule(80)\} \{ AnswerFormatHelp("formulas") \}

END_TEXT
Context()->normalStrings;

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


#ANS($xvalues->cmp(ordered=>1));
ANS(Vector(@x)->cmp());
ANS(Vector(@y)->cmp());
ANS($f3->cmp());


ENDDOCUMENT(); 
In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
The problem is that you really haven't added u() to the context properly. I noticed that yesterday, but decided not to go into it since you weren't using eval() at the time, and it would complicate my answer.

Functions in MathObjets are a bit complicated. There are different classes of functions (real-valued with one real input, real-valud with two real inputs, complex-valued with complex inputs, and so on). The class property in the function definition in the Context refers to a class that implements one of those categories of functions, and it is set up to check the parameters (both number and type) for that class. Within that class, there are methods for each of the functions of that class. So in Parser::Function::numeric, which implements single-input real-valued functions, there are methods for sin(x), ln(x), etc.

When you add a function like

    Context()->functions->add(sin => {class => "Parser::Function::numeric"});
That means that ties the sin() function to the method named sin in the class Parser::Function::numeric. When a MathObject Formula uses sin(x) and you call it's eval() method, the sin method of Parser::Function::numeric is called to determine the its value.

In your case, you did

Context()->functions->add(
    u => {
      class => 'Parser::Legacy::Numeric',
      perl => 'Parser::Legacy::Numeric::do_step'
    },
  );
which ties u() to the class Parser::Legacy::Numeric. That class is defined in pg/lib/Parser/Legacy/Numeric.pm, which does
Context()->functions->add(
$context->functions->add(
  step => {class => 'Parser::Legacy::Numeric', perl => 'Parser::Legacy::Numeric::do_step'},
  fact => {class => 'Parser::Legacy::Numeric', perl => 'Parser::Legacy::Numeric::do_fact'},
);
  );
I assume this is where you took your definition from. Note, however, that the function name was step in that case, so the method of Parser::Legacy::Numeric that is called is named step. When you replace the name step with u that changes the method that will be called to u as well. But Parser::Legacy::Numeric doesn't have a method called u, and so the attempt to evaluate it fails. MathObjects traps the error and reports the generic message that it can't evaluate u() at the given input.

So to do this properly, you need to use a class that actually has a method u. You can't add u to Parser::Legacy::Numeric (or rather you shouldn't, since it is global to the httpd child process that evaluated your problem, and changes you make in your problem would be carried over to the next one that the child handles). So you need to make your own subclass and add u to that.

Fortunately, you already have an appropriate class since you already have one for the kdelta function, and u() is a function of the same category (real-valued with one real input). So you can add u to that class and tie your Context function to that class.

package NewFunc;
# this next line makes the function a  function from reals to reals
our @ISA = ("Parser::Function::numeric");

sub kdelta {
  shift; my $x = shift;
  return ($x == 0 ? 1 :0);
}

sub u {
  shift; my $x = shift;
  return ($x >= 0 ? 1 : 0);
}

package main;

# Make it work in Perl code
sub kdelta {Parser::Function->call('kdelta',@_)}
sub u {Parser::Function->call('u',@_)}

#  Add the new functions to the Context
Context()->functions->add(
  kdelta => {class => 'NewFunc', TeX => '\delta'}, 
  u => {class => 'NewFunc'}
);
(Make use you remove the earlier definition for u).

Once you do this, you should be able to both call u(x) from within your Perl code, and be able to use eval() on formulas that include u().

You might ask how the answer checker can evaluate the function if veal() wasn't working. This is because the answer checker doesn't actually use eval(). Instead, it converts the formula into a Perl expression directly (using the perl method), and uses that to evaluate the function. This is more efficient if you need to evaluate the function at multiple points, which is why it is done that way. Because your original definition for u included a perl definition, the translation to perl used that rather than the default call to the u method in the Parser::Legacy::Numeric class. So answer checking worked as expected.

Hope that clarifies the situation.

In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
I thought I could have the answer as an ordered list. But I couldn't figure out how to convert the array x to a list,

You could have used

    ANS(List(@x)->cmp(ordered=>1));
to get your ordered list rather than use a vector. I think that is probably a better solution.
In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
Note that once you fix the definition of u(), you will get a new error from your problem. In this case, it will complain about using an array index that is -6 (or some negative number depending on your seed). That came from
    for ($k = $n0;$k eval(n =>$k);}
since $n0 was -6 for me. You probably need $xcheck1[$k-$n0] instead.

On the other hand, it might be easier to use

    push(@xcheck1,$f3->eval(n => $k));
instead, and not have to worry about the indices for the array. In fact, you could do
    foreach $k ($n0..$n3) {push(@xcheck1,$f3->eval(n=>$k)}
to simplify the for loop, or
  @xcheck1 = map {$f3->eval(n => $_)} ($n0..$n3);
to make it even easier.
In reply to Davide Cervone

Re: kronecker delta and other functions

by Joel Trussell -
In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
This is because the definition of the step function in PGauxiliaryFiles.pl is step(x) = 1 if x > 0 otherwise 0, so step(x) is 0 on (-infinity,0] and 1 on (0,infinity). If you prefer the intervals to be (-infinity,0) and [1,infinity), you will need to provide your own version of the step function rather than the one from PGauxiliaryFunctions.pl.
In reply to Davide Cervone

Re: kronecker delta and other functions

by Joel Trussell -
on page 
http://webwork.maa.org/wiki/Available_Functions#.U_eY-GOTKgc

I see 

This function is available by default for some problems, and may or may not be enabled for others (for authoring information see step functions):

  • step(x) The step function (0 if x < 0, 1 if x is greater than or equal to 0.) 
should this be corrected? 

so I should use 
parserFunction("u(​n)" => "1-step(-n)");


In reply to Joel Trussell

Re: kronecker delta and other functions

by Davide Cervone -
should this be corrected?

Yes, the page is not consistent with the code.

so I should use parserFunction("u(​n)" => "1-step(-n)");

Note that this requires step() to be defined in the context, which is not the case for the Numeric context. So you could either use the LegacyNumeric context (which also defines frac(), and corresponds to the functions defined in the original num_cmp() answer checker), or import the step function from that context:

    Context("Numeric");
    Context()->functions->redefine("step",from=>"LegacyNumeric");
    parserFunction("u(​n)" => "1-step(-n)");
Note that this means step() will also be available to students in their answers, but it is uniquely anyone will try that. If you want to prevent it, then use the mechanism of defining u() that I described above.

Hope that does the trick.