Skip to content

Commit c5535bb

Browse files
committed
Refactored evaluate functionality into own package
1 parent a774b36 commit c5535bb

File tree

2 files changed

+182
-158
lines changed

2 files changed

+182
-158
lines changed

evaluate.m

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
(* Wolfram Language Package *)
2+
(* Created by the Wolfram Language Plugin for IntelliJ, see http://wlplugin.halirutan.de/ *)
3+
4+
(* :Title: evaluate *)
5+
(* :Context: evaluate` *)
6+
(* :Author: marcus *)
7+
(* :Date: 2025-09-26 *)
8+
9+
(* :Package Version: 0.1 *)
10+
(* :Mathematica Version: 14.0 *)
11+
(* :Copyright: (c) 2025 Lambda Feedback *)
12+
(* :Keywords: *)
13+
(* :Discussion: *)
14+
15+
(* For new style packages see: https://mathematica.stackexchange.com/a/176489) *)
16+
(* Declare package context *)
17+
Package["evaluate`"]
18+
19+
20+
(* Export functions *)
21+
PackageExport["EvaluationFunction"]
22+
23+
equalQNumeric[answer_, response_, params_] := Module[{tolerance},
24+
Print["Evaluating Equal Numeric"];
25+
tolerance = If[Lookup[params, "tolerance_is_absolute", False],
26+
Lookup[params, "tolerance", 0],
27+
Lookup[params, "tolerance", 0] * answer
28+
];
29+
error = Abs[answer - response];
30+
<|
31+
"error" -> error,
32+
"is_correct" -> TrueQ[error <= tolerance]
33+
|>
34+
]
35+
36+
equalQOther[answer_, response_, params_] := Module[{correctQ},
37+
Print["Evaluating Equal Other"];
38+
<|
39+
"error" -> Null,
40+
"is_correct" -> TrueQ[answer == response]
41+
|>
42+
];
43+
44+
(* Patternize: a function that takes an expression and a list of \
45+
named variables, and converts all unnamed symbols in the expression \
46+
into Optional[..] patterns *)
47+
48+
Options[PatternizeSymbol] = {Atomic -> False};
49+
50+
PatternizeSymbol[a_Symbol, namedVariables_, OptionsPattern[]] /;
51+
Not[MemberQ[namedVariables, a]] := \!\(\*
52+
TagBox[
53+
StyleBox[
54+
RowBox[{"If", "[",
55+
RowBox[{
56+
RowBox[{"OptionValue", "[", "Atomic", "]"}], ",",
57+
RowBox[{"(",
58+
RowBox[{"Optional", "[",
59+
RowBox[{"PatternTest", "[",
60+
RowBox[{
61+
RowBox[{"pattern", "[",
62+
RowBox[{"a", ",",
63+
RowBox[{"Blank", "[", "]"}]}], "]"}], ",", "AtomQ"}], "]"}], "]"}], ")"}], ",",
64+
RowBox[{"(",
65+
RowBox[{"Optional", "[",
66+
RowBox[{"pattern", "[",
67+
RowBox[{"a", ",",
68+
RowBox[{"Blank", "[", "]"}]}], "]"}], "]"}], ")"}]}], "]"}],
69+
ShowSpecialCharacters->False,
70+
ShowStringCharacters->True,
71+
NumberMarks->True],
72+
FullForm]\) /. pattern -> Pattern
73+
74+
PatternizeSymbol[a_, namedVariables_, OptionsPattern[]] := a
75+
76+
ComplexResolve[Optional[a_Symbol] + I Optional[b_Symbol]] :=
77+
Complex[a, b]
78+
79+
ComplexResolve[I Optional[b_Symbol]*Pi] := Complex[0, b]*Pi
80+
81+
ComplexResolve[Complex[0, Optional[b_Symbol]] + Optional[a_Symbol]] :=
82+
Complex[a, b]
83+
84+
ComplexResolve[a_] := a
85+
86+
DepatternizePattern[pattern_Optional] := pattern[[1, 1, 1]]
87+
88+
DepatternizePattern[pattern_] := pattern
89+
90+
ComplexResolve[Optional[a_Symbol] + I Optional[b_Symbol]] :=
91+
Complex[a, b]
92+
93+
ComplexResolve[I Optional[b_Symbol]*Pi] := Complex[0, b]*Pi
94+
95+
ComplexResolve[Complex[0, Optional[b_Symbol]] + Optional[a_Symbol]] :=
96+
Complex[a, b]
97+
98+
ComplexResolve[a_] := a
99+
100+
Options[Patternize] = {Atomic -> False};
101+
102+
Patternize[expression_, namedVariables_, OptionsPattern[]] :=
103+
Map[PatternizeSymbol[#, namedVariables,
104+
Atomic -> OptionValue[Atomic]] &,
105+
MapAll[ComplexResolve, expression], {-1}]
106+
107+
Depatternize[pattern_] := MapAll[DepatternizePattern, pattern]
108+
109+
(*StructureMatchQ: a function that checks whether a user's response \
110+
has the same structure as a given answer template, given a set of \
111+
named variables.*)
112+
113+
inertFunctionRules = {Sin -> fSin, Cos -> fCos, Tan -> fTan,
114+
Sec -> fSec, Csc -> fCsc, Cot -> fCot, ArcSin -> fArcSin,
115+
ArcCos -> fArcCos, ArcTan -> fArcTan, ArcSec -> fArcSec,
116+
ArcCsc -> fArcCsc, ArcCot -> fArcCot, Sinh -> fSinh, Cosh -> fCosh,
117+
Tanh -> fTanh, Sech -> fSech, Csch -> fCsch, Coth -> fCoth,
118+
ArcSinh -> fArcSinh, ArcCosh -> fArcCosh, ArcTanh -> fArcTanh,
119+
ArcSech -> fArcSech, ArcCsch -> fArcCsch, ArcCoth -> fArcCoth,
120+
Exp -> fExp, Log -> fLog};
121+
122+
Options[StructureMatchQ] = {Atomic -> False};
123+
124+
StructureMatchQ[response_, answerTemplate_, namedVariables_,
125+
OptionsPattern[]] :=
126+
Module[{response2, answerTemplate2},
127+
response2 = ReplaceAll[response, inertFunctionRules];
128+
answerTemplate2 = ReplaceAll[answerTemplate, inertFunctionRules];
129+
MatchQ[response2,
130+
Patternize[answerTemplate2, namedVariables,
131+
Atomic -> OptionValue[Atomic]]]]
132+
133+
equalQStructure[answer_, response_, params_] := Module[{namedVariables,correctQ},
134+
Print["Evaluating Structure"];
135+
namedVariables = ToExpression[Lookup[params,"named_variables",{}],TraditionalForm];
136+
correctQ = StructureMatchQ[
137+
ToExpression[ToString[response],TraditionalForm],
138+
ToExpression[ToString[answer],TraditionalForm],
139+
namedVariables];
140+
141+
<|
142+
"error" -> Null,
143+
"is_correct" -> correctQ
144+
|>
145+
]
146+
147+
(* The evaluation function itself *)
148+
149+
evalQ[type_, answer_, response_, params_] := Module[{},
150+
Which[
151+
type == "structure",
152+
equalQStructure[answer,response,params],
153+
NumericQ[answer],
154+
equalQNumeric[answer, response, params],
155+
True,
156+
equalQOther[answer, response, params]
157+
]
158+
];
159+
160+
EvaluationFunction[type_, answer_, response_, params_] := Module[{result, feedback},
161+
Print["Running Evaluation Function"];
162+
result = evalQ[type, answer, response, params];
163+
Print["Results"];
164+
Print[result];
165+
feedback = If[result["is_correct"],
166+
Lookup[params, "correct_response_feedback", "Correct!"],
167+
Lookup[params, "incorrect_response_feedback", "Incorrect!"]
168+
];
169+
<|
170+
"command" -> "eval",
171+
"result" -> <|
172+
"is_correct" -> result["is_correct"],
173+
"feedback" -> feedback,
174+
"error" -> result["error"]
175+
|>
176+
|>
177+
]

evaluation_function.wl

Lines changed: 5 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,8 @@
11
(* ::Package:: *)
22

3-
(* The basic evaluation function code*)
3+
(* The code that handles incoming messanges and passes them to evaluate or preview accordingly*)
44

5-
equalQNumeric[answer_, response_, params_] := Module[{tolerance},
6-
Print["Evaluating Equal Numeric"];
7-
tolerance = If[Lookup[params, "tolerance_is_absolute", False],
8-
Lookup[params, "tolerance", 0],
9-
Lookup[params, "tolerance", 0] * answer
10-
];
11-
error = Abs[answer - response];
12-
<|
13-
"error" -> error,
14-
"is_correct" -> TrueQ[error <= tolerance]
15-
|>
16-
]
17-
18-
equalQOther[answer_, response_, params_] := Module[{correctQ},
19-
Print["Evaluating Equal Other"];
20-
<|
21-
"error" -> Null,
22-
"is_correct" -> TrueQ[answer == response]
23-
|>
24-
];
25-
26-
(* Patternize: a function that takes an expression and a list of \
27-
named variables, and converts all unnamed symbols in the expression \
28-
into Optional[..] patterns *)
29-
30-
Options[PatternizeSymbol] = {Atomic -> False};
31-
32-
PatternizeSymbol[a_Symbol, namedVariables_, OptionsPattern[]] /;
33-
Not[MemberQ[namedVariables, a]] := \!\(\*
34-
TagBox[
35-
StyleBox[
36-
RowBox[{"If", "[",
37-
RowBox[{
38-
RowBox[{"OptionValue", "[", "Atomic", "]"}], ",",
39-
RowBox[{"(",
40-
RowBox[{"Optional", "[",
41-
RowBox[{"PatternTest", "[",
42-
RowBox[{
43-
RowBox[{"pattern", "[",
44-
RowBox[{"a", ",",
45-
RowBox[{"Blank", "[", "]"}]}], "]"}], ",", "AtomQ"}], "]"}], "]"}], ")"}], ",",
46-
RowBox[{"(",
47-
RowBox[{"Optional", "[",
48-
RowBox[{"pattern", "[",
49-
RowBox[{"a", ",",
50-
RowBox[{"Blank", "[", "]"}]}], "]"}], "]"}], ")"}]}], "]"}],
51-
ShowSpecialCharacters->False,
52-
ShowStringCharacters->True,
53-
NumberMarks->True],
54-
FullForm]\) /. pattern -> Pattern
55-
56-
PatternizeSymbol[a_, namedVariables_, OptionsPattern[]] := a
57-
58-
ComplexResolve[Optional[a_Symbol] + I Optional[b_Symbol]] :=
59-
Complex[a, b]
60-
61-
ComplexResolve[I Optional[b_Symbol]*Pi] := Complex[0, b]*Pi
62-
63-
ComplexResolve[Complex[0, Optional[b_Symbol]] + Optional[a_Symbol]] :=
64-
Complex[a, b]
65-
66-
ComplexResolve[a_] := a
67-
68-
DepatternizePattern[pattern_Optional] := pattern[[1, 1, 1]]
69-
70-
DepatternizePattern[pattern_] := pattern
71-
72-
ComplexResolve[Optional[a_Symbol] + I Optional[b_Symbol]] :=
73-
Complex[a, b]
74-
75-
ComplexResolve[I Optional[b_Symbol]*Pi] := Complex[0, b]*Pi
76-
77-
ComplexResolve[Complex[0, Optional[b_Symbol]] + Optional[a_Symbol]] :=
78-
Complex[a, b]
79-
80-
ComplexResolve[a_] := a
81-
82-
Options[Patternize] = {Atomic -> False};
83-
84-
Patternize[expression_, namedVariables_, OptionsPattern[]] :=
85-
Map[PatternizeSymbol[#, namedVariables,
86-
Atomic -> OptionValue[Atomic]] &,
87-
MapAll[ComplexResolve, expression], {-1}]
88-
89-
Depatternize[pattern_] := MapAll[DepatternizePattern, pattern]
90-
91-
(*StructureMatchQ: a function that checks whether a user's response \
92-
has the same structure as a given answer template, given a set of \
93-
named variables.*)
94-
95-
inertFunctionRules = {Sin -> fSin, Cos -> fCos, Tan -> fTan,
96-
Sec -> fSec, Csc -> fCsc, Cot -> fCot, ArcSin -> fArcSin,
97-
ArcCos -> fArcCos, ArcTan -> fArcTan, ArcSec -> fArcSec,
98-
ArcCsc -> fArcCsc, ArcCot -> fArcCot, Sinh -> fSinh, Cosh -> fCosh,
99-
Tanh -> fTanh, Sech -> fSech, Csch -> fCsch, Coth -> fCoth,
100-
ArcSinh -> fArcSinh, ArcCosh -> fArcCosh, ArcTanh -> fArcTanh,
101-
ArcSech -> fArcSech, ArcCsch -> fArcCsch, ArcCoth -> fArcCoth,
102-
Exp -> fExp, Log -> fLog};
103-
104-
Options[StructureMatchQ] = {Atomic -> False};
105-
106-
StructureMatchQ[response_, answerTemplate_, namedVariables_,
107-
OptionsPattern[]] :=
108-
Module[{response2, answerTemplate2},
109-
response2 = ReplaceAll[response, inertFunctionRules];
110-
answerTemplate2 = ReplaceAll[answerTemplate, inertFunctionRules];
111-
MatchQ[response2,
112-
Patternize[answerTemplate2, namedVariables,
113-
Atomic -> OptionValue[Atomic]]]]
114-
115-
equalQStructure[answer_, response_, params_] := Module[{namedVariables,correctQ},
116-
Print["Evaluating Structure"];
117-
namedVariables = ToExpression[Lookup[params,"named_variables",{}],TraditionalForm];
118-
correctQ = StructureMatchQ[
119-
ToExpression[ToString[response],TraditionalForm],
120-
ToExpression[ToString[answer],TraditionalForm],
121-
namedVariables];
122-
123-
<|
124-
"error" -> Null,
125-
"is_correct" -> correctQ
126-
|>
127-
]
128-
129-
(* The evaluation function itself *)
130-
131-
evalQ[type_, answer_, response_, params_] := Module[{},
132-
Which[
133-
type == "structure",
134-
equalQStructure[answer,response,params],
135-
NumericQ[answer],
136-
equalQNumeric[answer, response, params],
137-
True,
138-
equalQOther[answer, response, params]
139-
]
140-
];
141-
142-
EvaluationFunction[type_, answer_, response_, params_] := Module[{tolerance, correctQ, error},
143-
Print["Running Evaluation Function"];
144-
result = evalQ[type, answer, response, params];
145-
Print["Results"];
146-
Print[result];
147-
feedback = If[result["is_correct"],
148-
Lookup[params, "correct_response_feedback", "Correct!"],
149-
Lookup[params, "incorrect_response_feedback", "Incorrect!"]
150-
];
151-
<|
152-
"command" -> "eval",
153-
"result" -> <|
154-
"is_correct" -> result["is_correct"],
155-
"feedback" -> feedback,
156-
"error" -> result["error"]
157-
|>
158-
|>
159-
];
5+
<< "evaluate.m";
1606

1617
evalQuestionIO = Function[
1628
Module[{jsonData, result},
@@ -168,9 +14,10 @@ evalQuestionIO = Function[
16814
type = params["comparisonType"];
16915
Print["Evaluating Response Against Answer"];
17016
result = EvaluationFunction[type, answer, response, params];
17+
resultAssoc = result[[4]];
17118
Print["Response"];
172-
Print[result];
173-
Export[#2, result, "JSON", "Compact" -> True]
19+
Print[resultAssoc];
20+
Export[#2, resultAssoc, "JSON", "Compact" -> True]
17421
]
17522
];
17623

0 commit comments

Comments
 (0)