The Wolfram Emerging Leaders Program: High School (WELP:HS) is a remote, semester-long program designed for exceptional graduates from the Wolfram High School Summer Research Program to continue to develop their skills. Students work in a small group over the course of a semester to do either a research-based project or a product development–based project under the guidance of expert mentors. Projects are centered around a topic at the intersection of the group’s interests.
​
This essay was written by:
◼
  • Anne Shuai
  • ◼
  • Nikhil Mani
  • ◼
  • Jenny Wang
  • In this paper, we created a study tool for students to use when practicing math problems. We designed functions to generate questions, check a student’s answer, and identify common mistakes in answers by students. This project aims to help students identify the mistakes they make in their problems, giving them a way to improve their math skills.

    Introduction

    As technology becomes more widely accepted into education, study tools such as online flashcards or study timers have become more common. We’ve used many of these forums and have noticed how practical and beneficial they can be. All of us wanted to create something that was both practical and applicable to the learning process. Thus, we wanted to use the Wolfram language to make something that students could actually use for practice.
    ​
    Although each of the aforementioned education tools is helpful in its own regard, we wanted to focus more specifically on math. Eventually, we settled on aiming to generate practice math problems and helpful hints if they were answered incorrectly.
    ​
    ​
    We were inspired by Marco Fleming’s previous WSRP project on Teaching Algebra by generating hints from wrong answers and wanted to see if we could create something similar but with more variety of questions.

    Approach

    Since we had to break down our work into three different people, we designated certain parts to each person. We focused on creating the form, generating the questions, and generating the hints. We decided to start with basic arithmetic problems since they’re relatively simple. This meant asking a question with the problem, having a user input, and deciding what to do with the user’s solution. Either the user would be correct, or we would try to find a commonly made mistake to apply by decomposing the original problem. If the latter were true, we’d provide the user with some sort of relevant hint. Then, we’d move on to more complex math problems and more complex mistakes.

    Generating Questions

    We began generating questions for the user to solve. We wanted to allow the user to pick between four different math question types– arithmetic, factoring, trigonometry, and fractions. It would then prompt the user to choose one of these questions to be asked. For each function question, the function would keep the correct variable stored locally such that the user’s inputted answer could be compared to it.
    Starting with arithmetic, we needed a basic expression with randomly generated numbers and operations. The expression would be set up in a number-operation-number order that used random numbers and either a plus sign, a minus sign, a multiplication sign, or a division sign in the middle.
    In[]:=
    aQuestion[]:=ToString[IntegerString@RandomInteger[{1,50}]<>RandomChoice[{"+","-","*","/"}]<>IntegerString@RandomInteger[{1,50}]]
    For factoring questions, we took a similar approach. In generating random questions, we picked a random integer from 1-9 and a random sign (+ or -) to plug into the standard factoring format of (x+a)(x+b). While simplistic, this approach worked out well.
    In[]:=
    faQuestion[]:=StringReplace["(x-a)(x+b)",{"a"->ToString@RandomInteger[{1,9}],"b"->ToString[RandomInteger[{1,9}]],"-"->ToString[RandomChoice[{"+","-"}]],"+"->ToString[RandomChoice[{"+","-"}]]}]
    With trigonometry questions, we randomized the function we wanted to focus on (Sin and Cos) as well as the angle in the same way as we did for arithmetic and factoring questions. The only difference here is we had to add a modifier to the angle, increasing it by n times in order to account for angles from 0 to 360 degrees.
    In[]:=
    tQuestion[]:=ToString[RandomChoice[{Sin,Cos}]]<>"["<>ToString[RandomInteger[{1,4}]*RandomChoice[{0,30,45,60,90}]]<>" Degree]"
    Fraction questions were generated in a similar way to arithmetic; only this time, the problem had to be set up already in the form of a fraction. They were written in the form of having an expression in the numerator as well as in the denominator, both of which were enclosed in parentheses.
    In[]:=
    frQuestion[]:=ToString[RandomChoice[{"("<>IntegerString@RandomInteger[{1,10}]<>RandomChoice[{"+","-","*"}]<>IntegerString@RandomInteger[{1,10}]<>")",IntegerString@RandomInteger[{1,10}]}]<>"/("<>IntegerString@RandomInteger[{1,10}]<>RandomChoice[{"+","-","*"}]<>IntegerString@RandomInteger[{1,10}]<>")"]

    Generating Hints

    Each of the questions had to have corresponding mistakes and hints as to how to fix them.

    Arithmetic Questions

    Starting with the basic arithmetic question types, we had relatively simple user mistakes. For instance, we included mistakes such as accidentally using the wrong sign/symbol .
    In[]:=
    aAddSubSwitchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"+"}],StringReplace[x,"+"->"-"],ContainsAny[Characters[x],{"-"}],StringReplace[x,"-"->"+"]]]​​aAddMultSwitchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"+"}],StringReplace[x,"+"->"*"],ContainsAny[Characters[x],{"*"}],StringReplace[x,"*"->"+"]]]​​aAddDivisSwitchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"+"}],StringReplace[x,"+"->"/"],ContainsAny[Characters[x],{"/"}],StringReplace[x,"/"->"+"]]]​​aSubDivisSwitchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"-"}],StringReplace[x,"-"->"/"],ContainsAny[Characters[x],{"/"}],StringReplace[x,"/"->"-"]]]​​aSubMultSwitchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"-"}],StringReplace[x,"-"->"*"],ContainsAny[Characters[x],{"*"}],StringReplace[x,"*"->"-"]]]​​aMultDivisSwitchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"*"}],StringReplace[x,"*"->"/"],ContainsAny[Characters[x],{"/"}],StringReplace[x,"/"->"*"]]]

    Factoring Questions

    In our experiences as tutors, the most common mistake that we find students making is switching their signs when factoring. This means factoring
    2
    x
    +2x+1
    as
    (x-1)(x+1)
    instead of
    2
    (x+1)
    .
    In[]:=
    faSwitchedSign[x_]:=Characters[StringReplace[ToString[Which[ContainsAny[Characters[x],{"+"}],StringReplace[x,"+"->"-"],ContainsAny[Characters[x],{"-"}],StringReplace[x,"-"->"+"]]]," "->""]]

    Trigonometry Questions

    We picked two main mistakes in trigonometry to focus on for this project. Our first was checking if the user switched the function that they were evaluating, such as evaluating Sin instead of Cos or vice versa. We also looked at the same mistake as the others in checking if they switched a sign.
    In[]:=
    tWrongTrigFunc[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"S","i","n"}],StringReplace[x,"Sin"->"Cos"],ContainsAny[Characters[x],{"C","o","s"}],StringReplace[x,"Cos"->"Sin"]]]
    In[]:=
    tWrongSign[x_]:=Module[{correctAnswer=CorrectAnswer[x]},Times[correctAnswer,-1]]

    Fraction Questions

    A common fraction mistake that we chose to check was when being prompted with a fraction of the form
    a+b
    x+y
    to do
    a+b
    x
    +
    a+b
    y
    ; essentially splitting the denominator up even though that disregards fraction rules.
    In[]:=
    frBad[x_]:=Module[{num=StringInsert["("<>StringTake[x,First[StringPosition[x,__~~"/"]]],")",-2],den=StringSplit[StringDelete[x,{StringTake[x,First[StringPosition[x,__~~"/"]]],"(",")"}],{"+","-","*"}],​​denOp=StringTake[x,Last[StringPosition[x,{"+","*","-"}]]]},​​ToExpression[StringJoin[Insert[Table[num<>den[[i]],{i,1,Length[den]}],denOp,2]]]]

    Creating Forms

    To generate the form, we used CloudDeploy to generate a link for a user to get to the practice problems. We tested many ways to get a form that asks questions and uses user input to decide what it displays. We used an addition/subtraction question in order to test these ways.
    In[]:=
    correctAnswer[x_]:=ToExpression[x]​​switchedSign[x_]:=ToExpression[Which[ContainsAny[Characters[x],{"+"}],StringReplace[x,"+"->"-"],ContainsAny[Characters[x],{"-"}],StringReplace[x,"-"->"+"]]]​​question[]:=ToString[IntegerString@RandomInteger[{1,10}]<>RandomChoice[{"+","-"}]<>IntegerString@RandomInteger[{1,10}]]

    FormPage

    The first way we tried was by using FormPage.
    In[]:=
    CloudDeploy[Module[{question=question[]},FormPage[{{"userAnswer","Enter a answer:"}->"Integer"},(Which[#userAnswer==switchedSign[question],"Try Again, You switched addition and subtraction",#userAnswer==correctAnswer[question],"That is correct",True,"Try Again"])&,AppearanceRules-><|"Title"->"WELP Project","Description"->"What is "<>question<>"?"|>]],Permissions->"Public"]
    However, when we tried to get the form to ask another question based on what the user had input, we couldn’t get the form to submit a response to the next question.

    AskFunction and Ask

    We then tried AskFunction and Ask. This ended up working even with multiple questions.
    In[]:=
    CloudDeploy[Module[{question=question[]},AskFunction[Ask[{"userAnswer","What is "<>question<>"?"}"Number"];If[Ask["userAnswer"]≠correctAnswer[question],If[Ask["userAnswer"]==switchedSign[question],AskConfirm["userAnswer","you said "<>question<>" = `value`. You have switched addition and subtraction. Do you want to try again?"]];AskDisplay["That's incorrect"],AskDisplay["That is correct"]]]],Permissions->"Public"]
    We, however, couldn’t figure out how to automatically generate questions without having to rerun the code. We tried using Delay. But when using Delay, it was found that when wanting to try to redo the question a different question would be shown due to the delay. We couldn’t come up with a solution to this so instead we deployed the form to a assigned link. This allowed for us to create a different question without us having to click a new link.
    In[]:=
    CloudDeploy[Module[{question=question[]},AskFunction[Ask[{"userAnswer","What is "<>question<>"?"}"Number"];If[Ask["userAnswer"]≠correctAnswer[question],If[Ask["userAnswer"]==switchedSign[question],AskConfirm["userAnswer","you said "<>question<>" = `value`. You have switched addition and subtraction. Do you want to try again?"]];AskDisplay["That's incorrect"],AskDisplay["That is correct"]]]],"Tutor",Permissions->"Public"]

    Putting It All Together

    We first created functions for each of the questions types that asked the question and checked whether the user input was correct. If the user input was correct, we displayed “That is correct”. If the user input was incorrect, we checked to see if the user input was due to a common mistake. If the user input was due to a common mistake, we displayed what the user imputed and the common mistake and asked if the user would like to try again. If the user was just incorrect, we displayed “That is incorrect” and also asked if the user wanted to try again.
    In[]:=
    arithmeticQuestion[x_]:=Module[{addMultSwitchedSign=aAddMultSwitchedSign[x],​​addDivisSwitchedSign=aAddDivisSwitchedSign[x],subMultSwitchedSign=aSubMultSwitchedSign[x],subDivisSwitchedSign=aSubDivisSwitchedSign[x],multDivisSwitchedSign=aMultDivisSwitchedSign[x],addSubSwitchedSign=aAddSubSwitchedSign[x],correctAnswer=aCorrectAnswer[x]},AskFunction[Ask[{"userAnswer","What is "<>x<>"?"}"String"];​​If[ToExpression[Ask["userAnswer"]]≠correctAnswer,If[ToExpression[Ask["userAnswer"]]==multDivisSwitchedSign||ToExpression[Ask["userAnswer"]]==addSubSwitchedSign||ToExpression[Ask["userAnswer"]]==subDivisSwitchedSign||ToExpression[Ask["userAnswer"]]==addMultSwitchedSign||ToExpression[Ask["userAnswer"]]==addDivisSwitchedSign||ToExpression[Ask["userAnswer"]]==subMultSwitchedSign,AskConfirm["userAnswer","You said "<>x<>" = `value`. You have used the wrong arithmetic sign. Do you want to try again?"]];​​AskConfirm["userAnswer","That's incorrect, Would you like to try again?"],AskDisplay["That is correct"]];"Thank you for trying"]];
    In[]:=
    trigQuestion[x_]:=Module{switchedSign=tWrongSign[x],switchedFunc=tWrongTrigFunc[x],correctAnswer=tCorrectAnswer[x]},AskFunctionAsk{"userAnswer","What is "<>x<>"?"}0->0,1->1,"√3/2"->
    3
    2
    ,"1/√2"->
    1
    2
    ,"1/2"->
    1
    2
    ,-1->-1,"-1/2"->
    1
    2
    ,"-√3/2"->-
    3
    2
    ,"-1/√2"->-
    1
    2
    ;​​If[Ask["userAnswer"]≠correctAnswer,If[Ask["userAnswer"]==switchedFunc,AskConfirm["userAnswer","You said "<>x<>" = `value`. You have switched Sin and Cos. Do you want to try again?"],If[Ask["userAnswer"]==switchedSign,AskConfirm["userAnswer","You said "<>x<>" = `value`. You have used the wrong quadrant. Do you want to try again?"]]];​​AskConfirm["userAnswer","That's incorrect, Would you like to try again?"],AskDisplay["That is correct"]];"Thank you for trying";
    This allowed for the code to be more organized and easier to read, as well as making it simple to add other question types.
    Then we asking the user what type of question they wanted to practice. The user is given the choice of “Arithmetic”, “Factoring”, “Trigonometry”, or “Fraction”. Each of these corresponds to the question function that’s for that type of question.
    You can use the quiz here!

    Conclusion

    All in all, we worked together to create a form using the Wolfram language to help users with math problems. It prompts the user with a question and compares the user’s input with the correct answer. We made four different types of math questions to practice (arithmetic, factoring, trigonometry, and fractions), each with its own corresponding mistakes. Despite issues we faced, such as with the link, we successfully completed our goal of an easy-to-use education tool. Although there are more areas for us to expand upon, our project in its current form can be used as a study tool for anyone wanting to practice math.

    Future Works

    ◼
  • Expanding to other types of questions, including but not limited to:
  • ◼
  • Geometry
  • ◼
  • Calculus
  • ◼
  • SAT
  • ◼
  • ACT
  • ◼
  • Making questions generate without having to rerun the code
  • ◼
  • Using LLMs like ChatGPT in helping to identify mistakes
  • CITE THIS NOTEBOOK

    Generating Hints for Practice Math Problems​
    by Wolfram Emerging Leaders Program​
    Wolfram Community, STAFF PICKS, January 3, 2024
    ​https://community.wolfram.com/groups/-/m/t/3095855