PREP 2014 Question Authoring - Archived

substitute j for i

substitute j for i

by Joel Trussell -
Number of replies: 14
Since electrical engineers usually use j for sqrt(-1) (i is current) how do I make the substitution so our students can enter e**(j*w) ?
In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
There is a macro file contextComplexJ.pl that makes this change. See the comments in the file for more details. It gives a way to write a problem that has a variable that you can switch to make it work with either notation.
In reply to Davide Cervone

Re: substitute j for i

by Joel Trussell -
when I use the macro I can get the formulas to compile for both i and j cases
$complexJ =1;   # 0 => i, 1 => j
but when I check the answers, they check for i for both answers, BUT when I use j, the first answer gives an error 
"Can't generate enough valid points for comparison"
however the second answer is counted correct. 

any hints? 

the 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",
   ($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',w=>'Real');  
Context()->variables->remove(z); # only variables should be n and w
Context()->functions->add(
    u => {
      class => 'Parser::Legacy::Numeric',
      perl => 'Parser::Legacy::Numeric::do_step'
    },
  );

$n1_n = random(1,9,1); # numerator of positive sequence
$n1_d = random(($n1_n + 1),10,1); # denominator of positive sequence
$n2_d = random(1,8,1); # denominator of negative sequence
$n2_n = random(($n2_d + 1),10,1); # numerator of negative sequence

$xp = Formula("($n1_n/$n1_d)^n u(n)")->reduce;
$xn = Formula("($n2_n/$n2_d)^n u(-n)")->reduce;

$Xp = Formula("1/(1 - ($n1_n/$n1_d)*e**((-1)*j*w))")->reduce;
# $Xp->{test_points}=[[1,0],[1,pi/4],[1,pi/3],[1,pi/2],[1,3*pi/2]];
$Xn = Formula("1/(1 - ($n2_n/$n2_d)*e**(j*w))")->reduce;

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

Context()->texStrings;
BEGIN_TEXT
This problem is related to 4.x in the text. 
$PAR
Given the aperiodic sequence, 
\[ 
x(n) = $xp,
\]
$PAR
find the discrete time Fourier transform, \(X(\omega ) \)
$BR NOTE: use w for \(\omega \) and j for \(\sqrt{-1}\).
$BR
$BR \(X(\omega )= \)   \{ $Xp ->ans_rule(40)\}

$PAR
Given the aperiodic sequence,  num = $n2_n     denom = $n2_d
\[ 
y(n) = $xn,
\]
$PAR
find the discrete time Fourier transform, \(Y(\omega ) \)
$BR
$BR \(Y(\omega )= \)   \{ $Xn ->ans_rule(40)\}

END_TEXT
Context()->normalStrings;

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


ANS($Xp->cmp());
ANS($Xn->cmp());



ENDDOCUMENT();        

In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
The problem works for me, so I'm not sure what is happening for you.

In any case, I have rewritten the contextComplexJ.pl so that it can be used from PGcourse.pl to set the default that you would like for your course without having to modify the problems. (Along the lines of the contextAlternateIntervals.pl and contextAlternateDecimal.pl that I posted last week).

You can now control the way complex number are input and displayed separately, and can force student input to be in j notation without requiring that the problem be written using j notation.

The file is attached, and the documentation is given below. See in particular the section on setting the complex j as the default at the end. Hope that does the trick.


NAME

contextComplexJ.pl - Alters the Complex context to allow the use of j-notation in addition to (or in place of) i-notation for complex numbers.

DESCRIPTION

This macro file adds features to the Complex context that allow both i and j notation for complex numbers. There are flags that control which notation a student must use (a warning is given for the other type), and how complex numbers should be displayed (you can force either form to be used regardless of how they were entered).

USAGE

To use this file, first load it into your problem, then use the Complex context as usual. Both i and j notation will be allowed, and numbers will display in whichever format they were originally entered.
        loadMacros("contextComplexJ.pl");
        
        Context("Complex");
        
        $z1 = Compute("1+3i");
        $z2 = Compute("1+3j");    # equivalent to $z1;
        
        $z1 == $z2;               # true
There are two context flags that control the input and output of complex numbers.

enterComplex = "either" (or "i" or "j")

This specifies what formats the student is allowed to use to enter a complex number. A value of "either" allows either of the formats to be accepted, while the other two options produce error messages if the wrong form is used.

displayComplex = "either" (or "i" or "j")

This controls how complex numbers are displayed. When set to "either", the complex is displayed in whatever format was used to create it. When set to "i" or "j", the display is forced to be in the given format regardless of how it was entered.

By default, the Complex context has both flags set to "either", so the complex numbers remain in the format the student entered them, and either form can be used.

It is possible to set enterComplex and displayComplex to different values. For example.

        Context()->flags->set(
          enterComplex => "either",
          displayComplex => "i",
        );
would allow students to enter complex numbers in either format, but all numebrs would be displayed in standard form.

SETTING THE ALTERNATE FORM AS THE DEFAULT

If you want to force existing problems to allow (or force, or warn about) the j notation, then create a file named parserCustomization.pl in your course's templates/macros directory, and enter the following in it:
        loadMacros("contextComplexJ.pl");
        context::ComplexJ->Default("either","either");
This will alter all the standard Complex contexts to allow students to enter complex numbers in either format, and will display them using the form that was used to enter them.

You could also do

        loadMacros("contextComplexJ.pl");
        context::ComplexJ->Default("i","i");
to cause a warning message to appear when students enter the j format.

If you want to force students to enter the alternate format, use

        loadMacros("contextComplexJ.pl");
        context::ComplexJ->Default("j","j");
This will force the display of all complex numbers to use j notation (so even the ones created in the problem using standard form will show using j's), and will force students to enter their results using j's, though professors answers will still be allowed to be entered in either format (the Default() function converts the first "j" to "either", but arranges that the default flags for the answer checker are set to only allow students to enter complex numbers with j's). This allows you to force j notation in problems without having to rewrite them.
In reply to Davide Cervone

Re: substitute j for i

by Joel Trussell -
I can't get the i to work given my updated code - gives i not defined in this context, and the j works for the second answer but I get the same not enough valid points for the first answer. 

the ability to modify ALL old problems to accept j would be great. I really don't care if they use i or j  (we are heavy users of Matlab, which uses both, so they can handle it) I'll try that after I get this problem working

the code is in 
In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
It looks like you are not using the new copy of contextComplexJ.pl that I attached to my message above. I put a copy in your joel_test directory, so the problems in that directory will load the new one in preference to the one in pg/macros, and the problem now works for me as expected.
In reply to Davide Cervone

Re: substitute j for i

by Joel Trussell -
Davide, 

Great - it now works. I had no clue about what to do with the contextComplexJ.pl file you attached. (indeed I didn't see it at the end of the email where I was expecting it. Looking back, I found it and downloaded it.) Now my question is what to do with it. You say you put in in my folder. where is the folder and how do I put files in the folder and how are they accessed? are all of the *.pl files in the folder? Was this covered in the workshop and I just missed it?  Can you point me to the write for handling this? 

Feeling more than kinda dumb at the moment, so thanks for any extra patience. 
In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
Macro files can go in several different locations. The ones provided by the system are in pg/macros (where the location of pg depends on your installation, but typically is /opt/pg). There are also macro directories in the Problem Library, and you can consider those as system provided.

File you you provide (or that you want to use to override the system ones) go in your course's templates/macros folder. This makes those macros available on a course-wide basis, so they will be used by all problems that call on them that you assign to homework sets within your course. but no one else's courses will use them.

My expectation was that you would put the contextComplexJ.pl file in your course templates/macros directory to be used that way.

The other place you can put macro files is in the directory containing the PG files that use them. This is how the Workshop2 slides that I made work (the templates/local/setWorkshops2 directory contains all the custom macro files that are needed by the slides). So when I said I put the contextComplexJ.pl file in your directory, I means in the templates/local/joel_test directory in the PREP2014 course. That way your PG files in that directory would get the new contextComplexJ.pl file without my interfering with anyone else's use of contextComplexJ.pl in the PREP2014 course.

If you are doing your development on your own server, you will need to move the contextComplexJ.pl to your server and install it in one of the places that I mentioned above. You can use the File Manager (link in the sidebar) to do that. It will let you navigate to your course's templates/macros folder where you can use the "Upload" button below the file list to upload the macro file to your course. We did discuss that sort of thing briefly on the first day of the course, but it may have been too soon for you to realize the implications of it.
In reply to Davide Cervone

Re: substitute j for i

by Joel Trussell -
OK - I think I understand. I tried copying the contextComplexJ.pl file to my folder at NCSU. It didn't work with a file I modified. So I copied the ncsu file to my problem set at maa - problem 22. I thought I changed all the stuff I should change but that file doesn't recognize j in either the code or the answer. What did I miss? I thought I looked at the file names, and inserted the macro. 

# DESCRIPTION
# Problem from 'Mathematics: The Language of Electrical and Computer Engineering', Viniotis and Trussell, 3rd ed.
# WeBWorK problem written by Joel Trussell, <hjt@ncsu.edu>
# ENDDESCRIPTION

## DBsubject(Electrical Engineering)
## DBchapter(Complex Numbers and Functions)
## DBsection(Problems)
## Institution(North Carolina State University)
## Author(H. J. Trussell)
## TitleText1('Mathematics: The Language of Electrical and Computer Engineering')
## AuthorText1('Viniotis and Trussell')
## EditionText1('3')
## Problem1('4.29-4.32')

DOCUMENT();        # This should be the first executable line in the problem.

loadMacros(
"PGstandard.pl",
"contextComplexJ.pl",
"MathObjects.pl",
"PGcourse.pl",
);

TEXT(beginproblem());
$showPartialCorrectAnswers = 1;

$one = (random( 2, 4, 1 ) )**4;

Context("Complex");
Context()->flags->set(
  tolerance => 0.001,
  tolType => "absolute",
);
Context()->flags->set(
         enterComplex => "either",
        displayComplex => "either",
       );  # this should be the default

$root1 = (random( 2, 4, 1 ) )**4;

# first problem 1/3 root

$power1 = 3;
$root1 = (random( 2, 6, 1 ) );
$root1power = $root1**$power1;
$theta1 = list_random(0, pi/6, pi/4, pi/3, pi/2 );
$z1r = $root1**$power1*cos($theta1); 
$z1i = $root1**$power1*sin($theta1); 

$z1 = $z1r + $z1i* i; 
#$z1 = $root1**$power1*(cos($theta1) +sin($theta1)* i); 
$theta10 = $theta1/$power1;
$theta11 = $theta10 + 2*pi/3;
$theta12 = $theta10 + 4*pi/3;
$a = Compute("$root1 (cos($theta10) + sin($theta10)i)");
$b = Compute("$root1 (cos($theta11) + sin($theta11)i)");
$c = Compute("$root1 (cos($theta12) + sin($theta12)i)");

# second problem 1/4 root

$power2 = 4;
$root2 = (random( 2, 6, 1 ) );
$root2power = $root2**$power2;
do {$theta2 = list_random(0, pi/6, pi/4, pi/3, pi/2 )} until ($theta2 != $theta1);
$z2r = $root2**$power2*cos($theta2); 
$z2i = $root2**$power2*sin($theta2); 

$z2 = $z2r + $z2i* i; 
#$z1 = $root1**$power1*(cos($theta1) +sin($theta1)* i); 
$theta20 = $theta2/$power2;
$theta21 = $theta20 + 2*pi/$power2;
$theta22 = $theta20 + 4*pi/$power2;
$theta23 = $theta20 + 6*pi/$power2;
$d = Compute("$root2 (cos($theta20) + sin($theta20)i)");
$e = Compute("$root2 (cos($theta21) + sin($theta21)i)");
$f = Compute("$root2 (cos($theta22) + sin($theta22)i)");
$g = Compute("$root2 (cos($theta23) + sin($theta23)i)");

# third problem 1/5 root

$power3 = 5;
$root3 = (random( 2, 5, 1 ) );
$root3power = $root3**$power3;
do {$theta3 = list_random(0, pi/6, pi/4, pi/3, pi/2 )} until (($theta3 != $theta2) & ($theta3 != $theta1));
$z3r = $root3**$power3*cos($theta3); 
$z3i = $root3**$power3*sin($theta3); 

$z3 = $z3r + $z3i* i; 
$theta30 = $theta3/$power3;
$theta31 = $theta30 + 2*pi/$power3;
$theta32 = $theta30 + 4*pi/$power3;
$theta33 = $theta30 + 6*pi/$power3;
$theta34 = $theta30 + 8*pi/$power3;
$m = Compute("$root3 (cos($theta30) + sin($theta30)i)");
$n = Compute("$root3 (cos($theta31) + sin($theta31)i)");
$o = Compute("$root3 (cos($theta32) + sin($theta32)i)");
$p = Compute("$root3 (cos($theta33) + sin($theta33)i)");
$q = Compute("$root3 (cos($theta34) + sin($theta34)i)");


BEGIN_TEXT
This problem is related to Problems 4.29-4.32 in the text.

$PAR
Find all the values of the following. $BR
NOTE: the answer requires entering complex numbers. Use i (NOT j) for sqrt(-1). You may use either Cartesian or exponential notation.
$PAR
(1) \( ($z1r + j $z1i)^\frac{1}{$power1} \) 
$BR 
Place all answers in the following blank, separated by commas:
$BR 
\{ans_rule(80)\}
$PAR 
(2) \( ($z2r + j $z2i)^\frac{1}{$power2} \) 
$BR 
Place all answers in the following blank, separated by commas:
$BR 
\{ans_rule(80)\}
$PAR 
(3) \( ($z3r + j $z3i)^\frac{1}{$power3} \) 
$BR 
Place all answers in the following blank, separated by commas:
$BR 
\{ans_rule(80)\} 
END_TEXT


#$a = Compute("$one^(1/4) (cos(pi/4) +sin(pi/4) i)");
#$ar = Re($a);
#$ai = Im($a);
#$b = Compute("$one^(1/4) (cos(3pi/4) +sin(3pi/4) i)");
#$c = Compute("$one^(1/4) (cos(5pi/4) +sin(5pi/4) i)");
#$d = Compute("$one^(1/4) (cos(7pi/4) +sin(7pi/4) i)");

#$f = Compute("cos(2pi/5) +sin(2pi/5) i");
#$g = Compute("cos(4pi/5) +sin(4pi/5) i");
#$h = Compute("cos(6pi/5) +sin(6pi/5) i");
#$j = Compute("cos(8pi/5) +sin(8pi/5) i");

#$k = Compute("cos(pi/8) +sin(pi/8) i");
#$l = Compute("cos(5pi/8) +sin(5pi/8) i");
#$m = Compute("cos(9pi/8) +sin(9pi/8) i");
#$n = Compute("cos(13pi/8) +sin(13pi/8) i");

ANS(List($a, $b, $c)->cmp);
ANS(List($d, $e, $f, $g)->cmp);
ANS(List($m, $n, $o, $p, $q)->cmp);

if($theta3!=0) {
$piby = round((1/$theta3)*pi);
$z0den = $piby*$power3;
$z1num = $piby*2 + 1;
$z2num = $piby*2*2 + 1;
$z3num = $piby*2*3 + 1;
$z4num = $piby*2*4 + 1;

SOLUTION(EV3(<<'END_SOLUTION'));
$PAR
$BBOLD  SOLUTION $EBOLD
$PAR
In general, to find the roots to \( (|a|e^{j\theta})^{1/n} \), first convert the complex number into exponential form, then extract the magnitude \( |a| \) and phase \( \theta \)
$PAR
The \( k \) roots then take the form 
$PAR
\( z_k = |a|^{1/n}(e^{j(\theta + 2\pi})^{1/n} = |a|^{1/n}e^{j\theta/n}e^{j\frac{2\pi k}{n}} = |a|^{1/n}e^{j\frac{\theta + 2\pi k}{n}} \) for \( k = 0,1,\ldots,n-1 \)
$PAR
Therefore, for question (3), we have \( |a| = \sqrt{$z3r^2 + $z3i^2} = $root3power \), so \( |a|^{\frac{1}{$power3}} = $root3 \), and \( \theta = \pi/$piby \). Check the Cartesian form to determine \( \theta \), noting that pure real numbers give 0 or \( \pi \), and pure imaginary ones give \( \pm \pi/2 \). For other complex numbers of the form \( a + bi \), use \( \tan^{-1}(b/a) \).
$PAR
Plugging in for \( z_k \), we have
$PAR
\( z_0 = $root3 e^{j\frac{\pi/$piby}{$power3}} = $root3 e^{j\frac{\pi}{$z0den}} \)
$PAR
\( z_1 = $root3 e^{j\frac{\pi}{$z0den}} e^{j\frac{2\pi 1}{$power3}} = $root3 e^{j\frac{$z1num\pi}{$z0den}} \)
$PAR
\( z_2 = $root3 e^{j\frac{\pi}{$z0den}} e^{j\frac{2\pi 2}{$power3}} = $root3 e^{j\frac{$z2num\pi}{$z0den}} \)
$PAR
\( z_3 = $root3 e^{j\frac{\pi}{$z0den}} e^{j\frac{2\pi 3}{$power3}} = $root3 e^{j\frac{$z3num\pi}{$z0den}} \)
$PAR
\( z_4 = $root3 e^{j\frac{\pi}{$z0den}} e^{j\frac{2\pi 4}{$power3}} = $root3 e^{j\frac{$z4num\pi}{$z0den}} \)
$PAR
Questions (1) and (2) are solved in a similar fashion.
END_SOLUTION
}

else {

SOLUTION(EV3(<<'END_SOLUTION'));
$PAR
$BBOLD  SOLUTION $EBOLD
$PAR
In general, to find the roots to \( (|a|e^{j\theta})^{1/n} \), first convert the complex number into exponential form, then extract the magnitude \( |a| \) and phase \( \theta \)
$PAR
The \( k \) roots then take the form 
$PAR
\( z_k = |a|^{1/n}(e^{j(\theta + 2\pi})^{1/n} = |a|^{1/n}e^{j\theta/n}e^{j\frac{2\pi k}{n}} = |a|^{1/n}e^{j\frac{\theta + 2\pi k}{n}} \) for \( k = 0,1,\ldots,n-1 \)
$PAR
Therefore, for question (3), we have \( |a| = \sqrt{$z3r^2 + $z3i^2} = $root3power \), so \( |a|^{\frac{1}{$power3}} = $root3 \), and \( \theta = 0 \). Check the Cartesian form to determine \( \theta \), noting that pure real numbers give 0 or \( \pi \), and pure imaginary ones give \( \pm \pi/2 \). For other complex numbers of the form \( a + bi \), use \( \tan^{-1}(b/a) \).
$PAR
Plugging in for \( z_k \), we have
$PAR
\( z_0 = $root3 e^{j\frac{0}{$power3}} = $root3 \)
$PAR
\( z_1 = $root3 e^{j\frac{0}{$power3}} e^{j\frac{2\pi 1}{$power3}} = $root3 e^{j\frac{2\pi}{$power3}} \)
$PAR
\( z_2 = $root3 e^{j\frac{0}{$power3}} e^{j\frac{2\pi 2}{$power3}} = $root3 e^{j\frac{4\pi}{$power3}} \)
$PAR
\( z_3 = $root3 e^{j\frac{0}{$power3}} e^{j\frac{2\pi 3}{$power3}} = $root3 e^{j\frac{6\pi}{$power3}} \)
$PAR
\( z_4 = $root3 e^{j\frac{0}{$power3}} e^{j\frac{2\pi 4}{$power3}} = $root3 e^{j\frac{8\pi}{$power3}} \)
$PAR
Questions (1) and (2) are solved in a similar fashion.
END_SOLUTION
}

ENDDOCUMENT();        # This should be the last executable line in the problem.
In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
Make sure you load MathObjects.pl BEFORE contextComplexJ.pl, since the ComplexJ needs math objects in order to function properly.
In reply to Davide Cervone

Re: substitute j for i

by Joel Trussell -
That works on both servers - thanks - this is the sort of thing that I'd never find. 
thanks
In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
Sometimes the order does matter. But I should adjust the contextComplex.pl file to load MathObjects.pl itself. It didn't occur to me that the order would matter when I wrote it. That's what you testers are for! :-)
In reply to Davide Cervone

Re: substitute j for i

by Joel Trussell -
in a previous interchange - you mentioned putting the "contextComplexJ.pl" in the PGcourse.pl file. that seems to mean that I include all my preferences in the PGcourse file - e.g.,  the entire code 
loadMacros(
"contextComplexJ.pl",
);
Context("Complex");
# modified to use j for i = sqrt(-1)
Context()->flags->set(
  enterComplex => "either",  # input either i or j
  displayComplex => "j",  # display only j
);

is run during the loadMacros operation. 
Since part of the code is Context("Complex"); then I should not use
that in the *.pg code that defines my problem - right?  So I have to "know" 
that my PGcourse.pl sets the context to Complex. This maybe fine since most
of what we do is complex, but you have mentioned that I was declaring 
complex in problems that didn't need it. What is the downside to living in the context Complex? 
In reply to Joel Trussell

Re: substitute j for i

by Davide Cervone -
No, this is not the way you do it. As you point out, this would set the context to Complex, and if the problem set that again your changes would be lost. You want the problem to set the context, so this isn't the way to make the change.

I give the documentation for contextComplexJ.pl above, and you should look at the section called "SETTING THE ALTERNATE FORM AS THE DEFAULT". That tells you what you need to add to PGcourse.pl. (That section actually suggests using a different file, parserCustomization.pl, which is loaded whenever MathObjects.pl is loaded. So does not rely on PGcourse.pl, which is not included in all PG files.)

So I'd follow the examples in the documentation and use

    loadMacros("contextComplexJ.pl");
    context::ComplexJ->Default("j","j");
to force students to enter numbers using j-notion and print all results using j-notation (see the note at the end of the documentation above), or
    loadMacros("contextComplexJ.pl");
    context::ComplexJ->Default("either","j");
to allow students to enter either format, but show results using j-notation.