math-exercises 3.0.209 → 3.0.211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/exercises/math/functions/continuity/index.d.ts +2 -0
- package/lib/exercises/math/functions/continuity/index.d.ts.map +1 -1
- package/lib/exercises/math/functions/continuity/index.js +2 -0
- package/lib/exercises/math/functions/continuity/pyContinuityBalayageInstructionCompletion.d.ts +11 -0
- package/lib/exercises/math/functions/continuity/pyContinuityBalayageInstructionCompletion.d.ts.map +1 -0
- package/lib/exercises/math/functions/continuity/pyContinuityBalayageInstructionCompletion.js +276 -0
- package/lib/exercises/math/functions/continuity/pyContinuityDichotomyInstructionCompletion.d.ts +10 -0
- package/lib/exercises/math/functions/continuity/pyContinuityDichotomyInstructionCompletion.d.ts.map +1 -0
- package/lib/exercises/math/functions/continuity/pyContinuityDichotomyInstructionCompletion.js +265 -0
- package/lib/exercises/math/integration/algorithms/index.d.ts +2 -0
- package/lib/exercises/math/integration/algorithms/index.d.ts.map +1 -0
- package/lib/exercises/math/integration/algorithms/index.js +1 -0
- package/lib/exercises/math/integration/algorithms/pyIntegrationInstructionCompletion.d.ts +10 -0
- package/lib/exercises/math/integration/algorithms/pyIntegrationInstructionCompletion.d.ts.map +1 -0
- package/lib/exercises/math/integration/algorithms/pyIntegrationInstructionCompletion.js +273 -0
- package/lib/exercises/math/integration/index.d.ts +1 -0
- package/lib/exercises/math/integration/index.d.ts.map +1 -1
- package/lib/exercises/math/integration/index.js +1 -0
- package/lib/exercises/math/limits/algorithms/index.d.ts +2 -0
- package/lib/exercises/math/limits/algorithms/index.d.ts.map +1 -0
- package/lib/exercises/math/limits/algorithms/index.js +1 -0
- package/lib/exercises/math/limits/algorithms/pyLimitProgramExecution.d.ts +17 -0
- package/lib/exercises/math/limits/algorithms/pyLimitProgramExecution.d.ts.map +1 -0
- package/lib/exercises/math/limits/algorithms/pyLimitProgramExecution.js +353 -0
- package/lib/exercises/math/limits/index.d.ts +1 -0
- package/lib/exercises/math/limits/index.d.ts.map +1 -1
- package/lib/exercises/math/limits/index.js +1 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/tests/singleExo.test.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { addValidProp, shuffleProps, tryToAddWrongProp, } from "../../../../exercises/exercise.js";
|
|
2
|
+
import { getDistinctQuestions } from "../../../../exercises/utils/getDistinctQuestions.js";
|
|
3
|
+
import { randint } from "../../../../math/utils/random/randint.js";
|
|
4
|
+
import { NodeConstructor, } from "../../../../tree/nodes/nodeConstructor.js";
|
|
5
|
+
import { power } from "../../../../tree/nodes/operators/powerNode.js";
|
|
6
|
+
import { ClosureType } from "../../../../tree/nodes/sets/closure.js";
|
|
7
|
+
import { IntervalNode } from "../../../../tree/nodes/sets/intervalNode.js";
|
|
8
|
+
import { random } from "../../../../utils/alea/random.js";
|
|
9
|
+
const codify = (strPython) => {
|
|
10
|
+
return `\`\`\`python
|
|
11
|
+
${strPython}
|
|
12
|
+
\`\`\``;
|
|
13
|
+
};
|
|
14
|
+
const codifyChunk = (strPython) => {
|
|
15
|
+
return `\`${strPython}\``;
|
|
16
|
+
};
|
|
17
|
+
const createStrPythonForNode = (node) => {
|
|
18
|
+
return node.toMathString().replaceAll("^", "**");
|
|
19
|
+
};
|
|
20
|
+
const getHydrated = (identifiers) => {
|
|
21
|
+
const { nodeIdsInterval, nodeIdsDistanceMax } = identifiers;
|
|
22
|
+
const nodeInterval = NodeConstructor.fromIdentifiers(nodeIdsInterval);
|
|
23
|
+
const nodeDistanceMax = NodeConstructor.fromIdentifiers(nodeIdsDistanceMax);
|
|
24
|
+
return {
|
|
25
|
+
nodeInterval,
|
|
26
|
+
nodeDistanceMax,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
const _getStrPythonProgram = (identifiers) => {
|
|
30
|
+
const { nodeInterval, nodeDistanceMax } = getHydrated(identifiers);
|
|
31
|
+
const [strIntervalBoundA, strIntervalBoundB] = [
|
|
32
|
+
nodeInterval.a,
|
|
33
|
+
nodeInterval.b,
|
|
34
|
+
].map(createStrPythonForNode);
|
|
35
|
+
const strDistanceMax = createStrPythonForNode(nodeDistanceMax);
|
|
36
|
+
return `def integral(f,a,b, precision):
|
|
37
|
+
k = 1
|
|
38
|
+
while True:
|
|
39
|
+
sr,sR = rectangles(f,a,b,k)
|
|
40
|
+
if(sR-sr < precision): #
|
|
41
|
+
return sr,sR
|
|
42
|
+
else:
|
|
43
|
+
k = k + 1 #
|
|
44
|
+
|
|
45
|
+
def rectangles(f,a,b,n):
|
|
46
|
+
sr, sR = 0,0 #
|
|
47
|
+
l = (b-a)/n #
|
|
48
|
+
for i in range(n): #
|
|
49
|
+
sr = sr + f(a + l * i) * l #
|
|
50
|
+
sR = sR + f(a + l * (i+1)) * l #
|
|
51
|
+
return sr,sR
|
|
52
|
+
|
|
53
|
+
sr,sR = integral(f,${strIntervalBoundA}, ${strIntervalBoundB},${strDistanceMax}) #
|
|
54
|
+
print(sr, "<=", I, "<=", sR)`;
|
|
55
|
+
};
|
|
56
|
+
const getStrPythonProgramComplete = (identifiers) => {
|
|
57
|
+
const identifiersTweaked = {
|
|
58
|
+
...identifiers,
|
|
59
|
+
keyIncomplete: "",
|
|
60
|
+
};
|
|
61
|
+
return getStrPythonProgramIncomplete(identifiersTweaked);
|
|
62
|
+
};
|
|
63
|
+
const getStrPythonProgramIncomplete = (identifiers) => {
|
|
64
|
+
const { keyIncomplete } = identifiers;
|
|
65
|
+
const { strIntegralCondition, strIntegralElse, strRectanglesInitialization, strRectanglesL, strRectanglesLoop, strRectanglesSMin, strRectanglesSMax, strCallIntegral, } = Object.fromEntries(Object.entries(getDictStrCompletion(identifiers)).map(([key, str]) => key === keyIncomplete ? [key, "..."] : [key, str]));
|
|
66
|
+
return `def integral(f,a,b, precision):
|
|
67
|
+
k = 1
|
|
68
|
+
while True:
|
|
69
|
+
sr,sR = rectangles(f,a,b,k)
|
|
70
|
+
${strIntegralCondition}
|
|
71
|
+
return sr,sR
|
|
72
|
+
else:
|
|
73
|
+
${strIntegralElse}
|
|
74
|
+
|
|
75
|
+
def rectangles(f,a,b,n):
|
|
76
|
+
${strRectanglesInitialization}
|
|
77
|
+
${strRectanglesL}
|
|
78
|
+
${strRectanglesLoop}
|
|
79
|
+
${strRectanglesSMin}
|
|
80
|
+
${strRectanglesSMax}
|
|
81
|
+
return sr,sR
|
|
82
|
+
|
|
83
|
+
${strCallIntegral}
|
|
84
|
+
print(sr, "<=", I, "<=", sR)`;
|
|
85
|
+
};
|
|
86
|
+
const getDictStrCompletion = (identifiers) => {
|
|
87
|
+
const { nodeInterval, nodeDistanceMax } = getHydrated(identifiers);
|
|
88
|
+
const [strIntervalBoundA, strIntervalBoundB] = [
|
|
89
|
+
nodeInterval.a,
|
|
90
|
+
nodeInterval.b,
|
|
91
|
+
].map(createStrPythonForNode);
|
|
92
|
+
const strDistanceMax = createStrPythonForNode(nodeDistanceMax);
|
|
93
|
+
return {
|
|
94
|
+
strIntegralCondition: `if(sR-sr < precision):`,
|
|
95
|
+
strIntegralElse: `k = k + 1`,
|
|
96
|
+
strRectanglesInitialization: `sr, sR = 0,0`,
|
|
97
|
+
strRectanglesL: `l = (b-a)/n`,
|
|
98
|
+
strRectanglesLoop: `for i in range(n):`,
|
|
99
|
+
strRectanglesSMin: `sr = sr + f(a + l * i) * l`,
|
|
100
|
+
strRectanglesSMax: `sR = sR + f(a + l * (i+1)) * l`,
|
|
101
|
+
strCallIntegral: `sr,sR = integral(f,${strIntervalBoundA}, ${strIntervalBoundB},${strDistanceMax})`,
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
const getInstruction = (identifiers) => {
|
|
105
|
+
const { nodeInterval, nodeDistanceMax } = getHydrated(identifiers);
|
|
106
|
+
return `On considère une fonction $f$ positive et strictement croissante,
|
|
107
|
+
dont on veut calculer $I$, l'intégrale de $f$ sur l'intervalle $${nodeInterval.toTex()}$
|
|
108
|
+
en utilisant la méthode des rectangles, avec une précision de $${nodeDistanceMax.toTex()}$.
|
|
109
|
+
|
|
110
|
+
Dans le programme suivant,
|
|
111
|
+
on suppose que l'on dispose d'une fonction ${codifyChunk("f")}
|
|
112
|
+
telle que ${codifyChunk("f(x)")} retourne $f(x)$.
|
|
113
|
+
|
|
114
|
+
Par quoi faut-il remplacer les pointillés dans le programme suivant pour qu'il affiche l'encadrement par les deux sommes de $n$ rectangles,
|
|
115
|
+
$n$ étant le nombre de rectangles à partir duquel l'écart entre les deux sommes
|
|
116
|
+
est strictement inférieur à $${nodeDistanceMax.toTex()}$ ?
|
|
117
|
+
|
|
118
|
+
${codify(getStrPythonProgramIncomplete(identifiers))}
|
|
119
|
+
|
|
120
|
+
`;
|
|
121
|
+
};
|
|
122
|
+
const getAnswer = (identifiers) => {
|
|
123
|
+
const { keyIncomplete } = identifiers;
|
|
124
|
+
const dictStrCompletion = getDictStrCompletion(identifiers);
|
|
125
|
+
return codifyChunk(dictStrCompletion[keyIncomplete]);
|
|
126
|
+
};
|
|
127
|
+
const getHint = (identifiers) => {
|
|
128
|
+
const { keyIncomplete } = identifiers;
|
|
129
|
+
switch (keyIncomplete) {
|
|
130
|
+
case "strIntegralCondition":
|
|
131
|
+
return `Écris en Python "Si la différence de la somme des rectangles au-dessus de la courbe de $f$ avec la somme des rectangles au-dessous de la courbe de $f$ est inférieure à $precision$ alors".`;
|
|
132
|
+
case "strIntegralElse":
|
|
133
|
+
return `Si la condition n'est pas remplie, on augmente le nombre de rectangles de $1$.`;
|
|
134
|
+
case "strRectanglesInitialization":
|
|
135
|
+
return `Les sommes doivent être initialisées.`;
|
|
136
|
+
case "strRectanglesL":
|
|
137
|
+
return `Quelle est la largeur d'un rectangle ?`;
|
|
138
|
+
case "strRectanglesLoop":
|
|
139
|
+
return `Pour calculer les sommes, on part de la borne inférieure d'intégration et on se décale petit à petit.`;
|
|
140
|
+
case "strRectanglesSMin":
|
|
141
|
+
return `Pour calculer la somme des aires des rectangles au-dessous de la courbe, à chaque itération, on ajoute l'aire du rectangle "à gauche".`;
|
|
142
|
+
case "strRectanglesSMax":
|
|
143
|
+
return `Pour calculer la somme des aires des rectangles au-dessus de la courbe, à chaque itération, on ajoute l'aire du rectangle "à droite".`;
|
|
144
|
+
default:
|
|
145
|
+
throw new Error("Unsupported keyIncomplete: " + keyIncomplete);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const getCorrection = (identifiers) => {
|
|
149
|
+
return `Voici le programme complet :
|
|
150
|
+
|
|
151
|
+
${codify(getStrPythonProgramComplete(identifiers))}
|
|
152
|
+
|
|
153
|
+
`;
|
|
154
|
+
};
|
|
155
|
+
const getPropositions = (n, { answer, ...identifiers }) => {
|
|
156
|
+
const propositions = [];
|
|
157
|
+
addValidProp(propositions, answer, "raw");
|
|
158
|
+
const { keyIncomplete } = identifiers;
|
|
159
|
+
switch (keyIncomplete) {
|
|
160
|
+
case "strIntegralCondition":
|
|
161
|
+
{
|
|
162
|
+
[
|
|
163
|
+
"if(sr-sR < precision):",
|
|
164
|
+
"if(sR-sr > precision):",
|
|
165
|
+
"if(sr-sR > precision):",
|
|
166
|
+
].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
case "strIntegralElse":
|
|
170
|
+
{
|
|
171
|
+
["k + 1", "n = n + 1", "n + 1"].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
172
|
+
}
|
|
173
|
+
break;
|
|
174
|
+
case "strRectanglesInitialization":
|
|
175
|
+
{
|
|
176
|
+
[
|
|
177
|
+
"sr, sR = 1,1",
|
|
178
|
+
"sr,sR = f(a), f(a + (b-a)/n)",
|
|
179
|
+
"sr,sR = a, a + (b-a)/n",
|
|
180
|
+
].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
case "strRectanglesL":
|
|
184
|
+
{
|
|
185
|
+
["l = b-a", "l = (b-a)*n", "l = b-a/n"].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
case "strRectanglesLoop":
|
|
189
|
+
{
|
|
190
|
+
[
|
|
191
|
+
"for i in range(l):",
|
|
192
|
+
"for i in range(n+1):",
|
|
193
|
+
"for i in range(n-1):",
|
|
194
|
+
].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
195
|
+
}
|
|
196
|
+
break;
|
|
197
|
+
case "strRectanglesSMin":
|
|
198
|
+
{
|
|
199
|
+
[
|
|
200
|
+
"sr = sr + f(a + i) * l",
|
|
201
|
+
"sr = sr + f(a + l * i)",
|
|
202
|
+
"sr = sr + f(a + l) * i",
|
|
203
|
+
].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
case "strRectanglesSMax":
|
|
207
|
+
{
|
|
208
|
+
[
|
|
209
|
+
"sR = f(a + l * (i+1)) * l",
|
|
210
|
+
"sR = sR + f(a + l * (i+1))",
|
|
211
|
+
"sR = sR + f(a + (l+1) * i) * (l+1)",
|
|
212
|
+
].forEach((str) => tryToAddWrongProp(propositions, codifyChunk(str), "raw"));
|
|
213
|
+
}
|
|
214
|
+
break;
|
|
215
|
+
default:
|
|
216
|
+
throw new Error("Unsupported keyIncomplete: " + keyIncomplete);
|
|
217
|
+
}
|
|
218
|
+
return shuffleProps(propositions, n);
|
|
219
|
+
};
|
|
220
|
+
const createRandomIdentifiers = () => {
|
|
221
|
+
const nodeDistanceMax = power(10, randint(-3, 0));
|
|
222
|
+
const keyIncomplete = random([
|
|
223
|
+
"strIntegralCondition",
|
|
224
|
+
"strIntegralElse",
|
|
225
|
+
"strRectanglesInitialization",
|
|
226
|
+
"strRectanglesL",
|
|
227
|
+
"strRectanglesLoop",
|
|
228
|
+
"strRectanglesSMin",
|
|
229
|
+
"strRectanglesSMax",
|
|
230
|
+
// "strCallIntegral",
|
|
231
|
+
]);
|
|
232
|
+
const nodeInterval = (() => {
|
|
233
|
+
const a = randint(-5, 5);
|
|
234
|
+
const b = a + randint(1, 5);
|
|
235
|
+
return new IntervalNode(a.toTree(), b.toTree(), ClosureType.FF);
|
|
236
|
+
})();
|
|
237
|
+
const identifiers = {
|
|
238
|
+
nodeIdsInterval: nodeInterval.toIdentifiers(),
|
|
239
|
+
nodeIdsDistanceMax: nodeDistanceMax.toIdentifiers(),
|
|
240
|
+
keyIncomplete,
|
|
241
|
+
};
|
|
242
|
+
return identifiers;
|
|
243
|
+
};
|
|
244
|
+
const getPyIntegrationInstructionCompletionQuestion = () => {
|
|
245
|
+
const identifiers = createRandomIdentifiers();
|
|
246
|
+
return getQuestionFromIdentifiers(identifiers);
|
|
247
|
+
};
|
|
248
|
+
const getQuestionFromIdentifiers = (identifiers, opts) => {
|
|
249
|
+
const question = {
|
|
250
|
+
answer: getAnswer(identifiers, opts),
|
|
251
|
+
instruction: getInstruction(identifiers, opts),
|
|
252
|
+
keys: [],
|
|
253
|
+
answerFormat: "tex",
|
|
254
|
+
identifiers,
|
|
255
|
+
hint: getHint(identifiers, opts),
|
|
256
|
+
correction: getCorrection(identifiers, opts),
|
|
257
|
+
options: opts,
|
|
258
|
+
};
|
|
259
|
+
return question;
|
|
260
|
+
};
|
|
261
|
+
export const pyIntegrationInstructionCompletion = {
|
|
262
|
+
id: "pyIntegrationInstructionCompletion",
|
|
263
|
+
label: "Compléter un algorithme pour obtenir un encadrement d'une intégrale",
|
|
264
|
+
isSingleStep: true,
|
|
265
|
+
generator: (nb, opts) => getDistinctQuestions(() => getPyIntegrationInstructionCompletionQuestion(opts), nb),
|
|
266
|
+
qcmTimer: 60,
|
|
267
|
+
freeTimer: 60,
|
|
268
|
+
getPropositions,
|
|
269
|
+
subject: "Mathématiques",
|
|
270
|
+
getQuestionFromIdentifiers,
|
|
271
|
+
hasHintAndCorrection: true,
|
|
272
|
+
answerType: "QCU",
|
|
273
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/exercises/math/integration/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,0DAA0D,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/exercises/math/integration/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,0DAA0D,CAAC;AAEzE,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/exercises/math/limits/algorithms/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./pyLimitProgramExecution.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Exercise } from "../../../../exercises/exercise.js";
|
|
2
|
+
import { NodeIdentifiers } from "../../../../tree/nodes/nodeConstructor.js";
|
|
3
|
+
type Identifiers = {
|
|
4
|
+
abscissaType: string;
|
|
5
|
+
imageType: string;
|
|
6
|
+
nodeIdsF: NodeIdentifiers;
|
|
7
|
+
nodeIdsAbscissa: NodeIdentifiers;
|
|
8
|
+
nodeIdsImage: NodeIdentifiers;
|
|
9
|
+
nodeIdsPrecision?: NodeIdentifiers;
|
|
10
|
+
};
|
|
11
|
+
type Options = {
|
|
12
|
+
abscissaType: string;
|
|
13
|
+
imageType: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const pyLimitProgramExecution: Exercise<Identifiers, Options>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=pyLimitProgramExecution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pyLimitProgramExecution.d.ts","sourceRoot":"","sources":["../../../../../src/exercises/math/limits/algorithms/pyLimitProgramExecution.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EAgBT,MAAM,6BAA6B,CAAC;AAKrC,OAAO,EAEL,eAAe,EAChB,MAAM,qCAAqC,CAAC;AA4B7C,KAAK,WAAW,GAAG;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,EAAE,eAAe,CAAC;IAC9B,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACpC,CAAC;AA8VF,KAAK,OAAO,GAAG;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AA+BF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAiBlE,CAAC"}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { addValidProp, tryToAddWrongProp, shuffleProps, GeneratorOptionTarget, GeneratorOptionType, } from "../../../../exercises/exercise.js";
|
|
2
|
+
import { getDistinctQuestions } from "../../../../exercises/utils/getDistinctQuestions.js";
|
|
3
|
+
import { defaultArrayedOptsWhereNeeded } from "../../../../exercises/utils/options/arrayedOptions.js";
|
|
4
|
+
import { randint } from "../../../../math/utils/random/randint.js";
|
|
5
|
+
import { NodeConstructor, } from "../../../../tree/nodes/nodeConstructor.js";
|
|
6
|
+
import { MinusInfinityNode, PlusInfinityNode, } from "../../../../tree/nodes/numbers/infiniteNode.js";
|
|
7
|
+
import { add } from "../../../../tree/nodes/operators/addNode.js";
|
|
8
|
+
import { frac } from "../../../../tree/nodes/operators/fractionNode.js";
|
|
9
|
+
import { multiply } from "../../../../tree/nodes/operators/multiplyNode.js";
|
|
10
|
+
import { square } from "../../../../tree/nodes/operators/powerNode.js";
|
|
11
|
+
import { substract } from "../../../../tree/nodes/operators/substractNode.js";
|
|
12
|
+
import { VariableNode } from "../../../../tree/nodes/variables/variableNode.js";
|
|
13
|
+
import { random } from "../../../../utils/alea/random.js";
|
|
14
|
+
import { getCartesiansProducts } from "../../../../utils/arrays/cartesianProducts.js";
|
|
15
|
+
const codify = (strPython) => {
|
|
16
|
+
return `\`\`\`python
|
|
17
|
+
${strPython}
|
|
18
|
+
\`\`\``;
|
|
19
|
+
};
|
|
20
|
+
const codifyChunk = (strPython) => {
|
|
21
|
+
return `\`${strPython}\``;
|
|
22
|
+
};
|
|
23
|
+
const createStrPythonForNode = (node) => {
|
|
24
|
+
return node.toMathString().replaceAll("^", "**");
|
|
25
|
+
};
|
|
26
|
+
const getHydrated = (identifiers) => {
|
|
27
|
+
const { nodeIdsF, nodeIdsAbscissa, nodeIdsPrecision, nodeIdsImage } = identifiers;
|
|
28
|
+
const [nodeF, nodeAbsissa, nodeImage] = [
|
|
29
|
+
nodeIdsF,
|
|
30
|
+
nodeIdsAbscissa,
|
|
31
|
+
nodeIdsImage,
|
|
32
|
+
].map((nodeIds) => NodeConstructor.fromIdentifiers(nodeIds));
|
|
33
|
+
const nodePrecision = nodeIdsPrecision &&
|
|
34
|
+
NodeConstructor.fromIdentifiers(nodeIdsPrecision);
|
|
35
|
+
return {
|
|
36
|
+
nodeF,
|
|
37
|
+
nodeAbsissa,
|
|
38
|
+
nodeImage,
|
|
39
|
+
nodePrecision,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const getStrPythonProgram = (identifiers) => {
|
|
43
|
+
const { abscissaType, imageType } = identifiers;
|
|
44
|
+
const { nodeF, nodeAbsissa, nodeImage, nodePrecision } = getHydrated(identifiers);
|
|
45
|
+
const [strAbscissa, strImage] = [nodeAbsissa, nodeImage].map((node) => createStrPythonForNode(node));
|
|
46
|
+
const strPrecision = nodePrecision && createStrPythonForNode(nodePrecision);
|
|
47
|
+
return `def f(x):
|
|
48
|
+
return ${createStrPythonForNode(nodeF)}
|
|
49
|
+
|
|
50
|
+
${(() => {
|
|
51
|
+
switch (abscissaType) {
|
|
52
|
+
case "$-\\infty$":
|
|
53
|
+
switch (imageType) {
|
|
54
|
+
case "$-\\infty$":
|
|
55
|
+
case "$+\\infty$":
|
|
56
|
+
return `x = 0
|
|
57
|
+
while abs(f(x)) < 10000 :
|
|
58
|
+
x = x - 10`;
|
|
59
|
+
case "$x \\in \\mathbb{R}$":
|
|
60
|
+
return `x = 0
|
|
61
|
+
while abs(f(x) - ${strImage}) > ${strPrecision} :
|
|
62
|
+
x = x - 10`;
|
|
63
|
+
default:
|
|
64
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
65
|
+
}
|
|
66
|
+
case "$+\\infty$": {
|
|
67
|
+
switch (imageType) {
|
|
68
|
+
case "$-\\infty$":
|
|
69
|
+
case "$+\\infty$":
|
|
70
|
+
return `x = 0
|
|
71
|
+
while abs(f(x)) < 10000 :
|
|
72
|
+
x = x + 10`;
|
|
73
|
+
case "$x \\in \\mathbb{R}$":
|
|
74
|
+
return `x = 0
|
|
75
|
+
while abs(f(x) - ${strImage}) > ${strPrecision} :
|
|
76
|
+
x = x + 10`;
|
|
77
|
+
default:
|
|
78
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
case "$x \\in \\mathbb{R}$": {
|
|
82
|
+
switch (imageType) {
|
|
83
|
+
case "$-\\infty$":
|
|
84
|
+
case "$+\\infty$":
|
|
85
|
+
return `x = ${strAbscissa} + 1
|
|
86
|
+
while abs(f(x)) < 10000 :
|
|
87
|
+
x = x - 0.01`;
|
|
88
|
+
default:
|
|
89
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
default:
|
|
93
|
+
throw new Error("Unsupported abscissaType: " + abscissaType);
|
|
94
|
+
}
|
|
95
|
+
})()}`;
|
|
96
|
+
};
|
|
97
|
+
const getXValueForPythonProgram = (identifiers) => {
|
|
98
|
+
const { abscissaType, imageType } = identifiers;
|
|
99
|
+
const { nodeF, nodeAbsissa, nodeImage, nodePrecision } = getHydrated(identifiers);
|
|
100
|
+
switch (abscissaType) {
|
|
101
|
+
case "$-\\infty$":
|
|
102
|
+
switch (imageType) {
|
|
103
|
+
case "$-\\infty$":
|
|
104
|
+
case "$+\\infty$": {
|
|
105
|
+
let x = 0;
|
|
106
|
+
while (Math.abs(nodeF.evaluate({ x })) < 10000) {
|
|
107
|
+
x = x - 10;
|
|
108
|
+
}
|
|
109
|
+
return x;
|
|
110
|
+
}
|
|
111
|
+
case "$x \\in \\mathbb{R}$": {
|
|
112
|
+
let x = 0;
|
|
113
|
+
while (Math.abs(nodeF.evaluate({ x }) - nodeImage.evaluate()) >
|
|
114
|
+
nodePrecision.evaluate()) {
|
|
115
|
+
x = x - 10;
|
|
116
|
+
}
|
|
117
|
+
return x;
|
|
118
|
+
}
|
|
119
|
+
default:
|
|
120
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
121
|
+
}
|
|
122
|
+
case "$+\\infty$":
|
|
123
|
+
switch (imageType) {
|
|
124
|
+
case "$-\\infty$":
|
|
125
|
+
case "$+\\infty$": {
|
|
126
|
+
let x = 0;
|
|
127
|
+
while (Math.abs(nodeF.evaluate({ x })) < 10000) {
|
|
128
|
+
x = x - 10;
|
|
129
|
+
}
|
|
130
|
+
return x;
|
|
131
|
+
}
|
|
132
|
+
case "$x \\in \\mathbb{R}$": {
|
|
133
|
+
let x = 0;
|
|
134
|
+
while (Math.abs(nodeF.evaluate({ x }) - nodeImage.evaluate()) >
|
|
135
|
+
nodePrecision.evaluate()) {
|
|
136
|
+
x = x - 10;
|
|
137
|
+
}
|
|
138
|
+
return x;
|
|
139
|
+
}
|
|
140
|
+
default:
|
|
141
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
142
|
+
}
|
|
143
|
+
case "$x \\in \\mathbb{R}$": {
|
|
144
|
+
switch (imageType) {
|
|
145
|
+
case "$-\\infty$":
|
|
146
|
+
case "$+\\infty$": {
|
|
147
|
+
let x = nodeAbsissa.evaluate() + 1;
|
|
148
|
+
while (Math.abs(nodeF.evaluate({ x })) < 10000) {
|
|
149
|
+
x = x - 0.01;
|
|
150
|
+
}
|
|
151
|
+
return x;
|
|
152
|
+
}
|
|
153
|
+
default:
|
|
154
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
default:
|
|
158
|
+
throw new Error("Unsupported abscissaType: " + abscissaType);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const getInstruction = (identifiers) => {
|
|
162
|
+
return `On considère le script suivant en langage Python. Quelle valeur contient la variable $x$ après son exécution ?
|
|
163
|
+
|
|
164
|
+
${codify(getStrPythonProgram(identifiers))}
|
|
165
|
+
|
|
166
|
+
`;
|
|
167
|
+
};
|
|
168
|
+
const getAnswer = (identifiers) => {
|
|
169
|
+
return codifyChunk(createStrPythonForNode(getXValueForPythonProgram(identifiers).toTree()));
|
|
170
|
+
};
|
|
171
|
+
const getHint = (_identifiers) => {
|
|
172
|
+
return "Trouve la valeur qui semble la plus probable dans la liste des valeurs proposées.";
|
|
173
|
+
};
|
|
174
|
+
const getCorrection = (identifiers) => {
|
|
175
|
+
return `La valeur de $x$ quand on exécute le script est $${getAnswer(identifiers)}$.`;
|
|
176
|
+
};
|
|
177
|
+
const getPropositions = (n, { answer, ...identifiers }) => {
|
|
178
|
+
const propositions = [];
|
|
179
|
+
addValidProp(propositions, getAnswer(identifiers), "raw");
|
|
180
|
+
const { nodeAbsissa } = getHydrated(identifiers);
|
|
181
|
+
const x = getXValueForPythonProgram(identifiers);
|
|
182
|
+
if (nodeAbsissa.toTex() === "+\\infty") {
|
|
183
|
+
[
|
|
184
|
+
(-8000).toTree(),
|
|
185
|
+
(-4290).toTree(),
|
|
186
|
+
(-19800).toTree(),
|
|
187
|
+
randint(-50, 50, [0]).toTree(),
|
|
188
|
+
].forEach((node) => {
|
|
189
|
+
tryToAddWrongProp(propositions, codifyChunk(createStrPythonForNode(node)), "raw");
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
else if (nodeAbsissa.toTex() === "-\\infty") {
|
|
193
|
+
[
|
|
194
|
+
(+8000).toTree(),
|
|
195
|
+
(+4290).toTree(),
|
|
196
|
+
(+19800).toTree(),
|
|
197
|
+
randint(-50, 50, [0]).toTree(),
|
|
198
|
+
].forEach((node) => {
|
|
199
|
+
tryToAddWrongProp(propositions, codifyChunk(createStrPythonForNode(node)), "raw");
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
[(8000).toTree(), (-8000).toTree(), (-x).toTree()].forEach((node) => {
|
|
204
|
+
tryToAddWrongProp(propositions, codifyChunk(createStrPythonForNode(node)), "raw");
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return shuffleProps(propositions, n);
|
|
208
|
+
};
|
|
209
|
+
const getPyLimitProgramExecutionQuestion = (optsIn) => {
|
|
210
|
+
const arrayedOpts = defaultArrayedOptsWhereNeeded(optsIn, arrayedOptsDefault);
|
|
211
|
+
const pool = getCartesiansProducts([
|
|
212
|
+
arrayedOpts.abscissaType,
|
|
213
|
+
arrayedOpts.imageType,
|
|
214
|
+
]).filter(([abscissaType, imageType]) => {
|
|
215
|
+
return !(abscissaType === "$x \\in \\mathbb{R}$" &&
|
|
216
|
+
imageType === "$x \\in \\mathbb{R}$");
|
|
217
|
+
});
|
|
218
|
+
const [abscissaType, imageType] = random(pool);
|
|
219
|
+
const [nodeF, nodeAbsissa, nodeImage, nodePrecision] = (() => {
|
|
220
|
+
const nodeVarX = new VariableNode("x");
|
|
221
|
+
switch (abscissaType) {
|
|
222
|
+
case "$-\\infty$":
|
|
223
|
+
case "$+\\infty$": {
|
|
224
|
+
const nodeAbsissa = abscissaType === "$-\\infty$" ? PlusInfinityNode : MinusInfinityNode;
|
|
225
|
+
const [nodeF, nodeImage, nodePrecision] = (() => {
|
|
226
|
+
switch (imageType) {
|
|
227
|
+
case "$-\\infty$": {
|
|
228
|
+
const nodePrecision = random([0.1, 0.01, 0.001]).toTree();
|
|
229
|
+
const nodeF = (() => {
|
|
230
|
+
const [a, b, c, d] = [...Array(4).keys()].reduce((acc, _i) => {
|
|
231
|
+
acc = [...acc, randint(1, 10, acc)];
|
|
232
|
+
return acc;
|
|
233
|
+
}, []);
|
|
234
|
+
const nodeNum = add(multiply(-a, square(nodeVarX)), b);
|
|
235
|
+
const nodeDen = add(multiply(c, nodeVarX), d);
|
|
236
|
+
return frac(nodeNum, nodeDen);
|
|
237
|
+
})();
|
|
238
|
+
const nodeImage = MinusInfinityNode;
|
|
239
|
+
return [nodeF, nodeImage, nodePrecision];
|
|
240
|
+
}
|
|
241
|
+
case "$x \\in \\mathbb{R}$": {
|
|
242
|
+
const nodeImage = randint(-50, 51).toTree();
|
|
243
|
+
const a = randint(-9, 10, [0]);
|
|
244
|
+
const nodeF = add(nodeImage, frac(a, nodeVarX));
|
|
245
|
+
return [nodeF, nodeImage, undefined];
|
|
246
|
+
}
|
|
247
|
+
case "$+\\infty$": {
|
|
248
|
+
const nodePrecision = random([0.1, 0.01, 0.001]).toTree();
|
|
249
|
+
const nodeF = (() => {
|
|
250
|
+
const [a, b, c, d] = [...Array(4).keys()].reduce((acc, _i) => {
|
|
251
|
+
acc = [...acc, randint(1, 10, acc)];
|
|
252
|
+
return acc;
|
|
253
|
+
}, []);
|
|
254
|
+
const nodeNum = add(multiply(+a, square(nodeVarX)), b);
|
|
255
|
+
const nodeDen = add(multiply(c, nodeVarX), d);
|
|
256
|
+
return frac(nodeNum, nodeDen);
|
|
257
|
+
})();
|
|
258
|
+
const nodeImage = MinusInfinityNode;
|
|
259
|
+
return [nodeF, nodeImage, nodePrecision];
|
|
260
|
+
}
|
|
261
|
+
default:
|
|
262
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
263
|
+
}
|
|
264
|
+
})();
|
|
265
|
+
return [nodeF, nodeAbsissa, nodeImage, nodePrecision];
|
|
266
|
+
}
|
|
267
|
+
case "$x \\in \\mathbb{R}$": {
|
|
268
|
+
const nodeAbsissa = randint(-50, 51).toTree();
|
|
269
|
+
const [nodeF, nodeImage] = (() => {
|
|
270
|
+
switch (imageType) {
|
|
271
|
+
case "$-\\infty$": {
|
|
272
|
+
const a = randint(-9, 0);
|
|
273
|
+
const nodeF = frac(a, square(substract(nodeVarX, nodeAbsissa)));
|
|
274
|
+
const nodeImage = MinusInfinityNode;
|
|
275
|
+
return [nodeF, nodeImage];
|
|
276
|
+
}
|
|
277
|
+
case "$+\\infty$": {
|
|
278
|
+
const a = randint(1, 10);
|
|
279
|
+
const nodeF = frac(a, square(substract(nodeVarX, nodeAbsissa)));
|
|
280
|
+
const nodeImage = PlusInfinityNode;
|
|
281
|
+
return [nodeF, nodeImage];
|
|
282
|
+
}
|
|
283
|
+
default:
|
|
284
|
+
throw new Error("Unsupported imageType: " + imageType);
|
|
285
|
+
}
|
|
286
|
+
})();
|
|
287
|
+
return [nodeF, nodeAbsissa, nodeImage, undefined];
|
|
288
|
+
}
|
|
289
|
+
default:
|
|
290
|
+
throw new Error("Unsupported abscissaType: " + abscissaType);
|
|
291
|
+
}
|
|
292
|
+
})();
|
|
293
|
+
const identifiers = {
|
|
294
|
+
abscissaType,
|
|
295
|
+
imageType,
|
|
296
|
+
nodeIdsF: nodeF.toIdentifiers(),
|
|
297
|
+
nodeIdsAbscissa: nodeAbsissa.toIdentifiers(),
|
|
298
|
+
nodeIdsImage: nodeImage.toIdentifiers(),
|
|
299
|
+
nodeIdsPrecision: nodePrecision?.toIdentifiers(),
|
|
300
|
+
};
|
|
301
|
+
return getQuestionFromIdentifiers(identifiers);
|
|
302
|
+
};
|
|
303
|
+
const getQuestionFromIdentifiers = (identifiers) => {
|
|
304
|
+
const question = {
|
|
305
|
+
instruction: getInstruction(identifiers),
|
|
306
|
+
answer: getAnswer(identifiers),
|
|
307
|
+
hint: getHint(identifiers),
|
|
308
|
+
correction: getCorrection(identifiers),
|
|
309
|
+
keys: [],
|
|
310
|
+
answerFormat: "raw",
|
|
311
|
+
identifiers,
|
|
312
|
+
};
|
|
313
|
+
return question;
|
|
314
|
+
};
|
|
315
|
+
const arrayedOptsDefault = {
|
|
316
|
+
abscissaType: ["$-\\infty$", "$x \\in \\mathbb{R}$", "$+\\infty$"],
|
|
317
|
+
imageType: ["$-\\infty$", "$+\\infty$"],
|
|
318
|
+
};
|
|
319
|
+
const options = [
|
|
320
|
+
{
|
|
321
|
+
id: "abscissaType",
|
|
322
|
+
label: "Type d'abscisse",
|
|
323
|
+
target: GeneratorOptionTarget.generation,
|
|
324
|
+
type: GeneratorOptionType.multiselect,
|
|
325
|
+
values: ["$-\\infty$", "$x \\in \\mathbb{R}$", "$+\\infty$"],
|
|
326
|
+
defaultValue: arrayedOptsDefault.abscissaType,
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
id: "imageType",
|
|
330
|
+
label: "Type d'image",
|
|
331
|
+
target: GeneratorOptionTarget.generation,
|
|
332
|
+
type: GeneratorOptionType.multiselect,
|
|
333
|
+
values: ["$-\\infty$", "$x \\in \\mathbb{R}$", "$+\\infty$"],
|
|
334
|
+
defaultValue: arrayedOptsDefault.imageType,
|
|
335
|
+
},
|
|
336
|
+
];
|
|
337
|
+
export const pyLimitProgramExecution = {
|
|
338
|
+
id: "pyLimitProgramExecution",
|
|
339
|
+
label: "Exécuter un script Python de manifestation d'une limite de fonction",
|
|
340
|
+
isSingleStep: true,
|
|
341
|
+
generator: (nb, opts) => getDistinctQuestions(() => getPyLimitProgramExecutionQuestion(opts), nb),
|
|
342
|
+
options,
|
|
343
|
+
qcmTimer: 60,
|
|
344
|
+
freeTimer: 60,
|
|
345
|
+
getPropositions,
|
|
346
|
+
getInstruction,
|
|
347
|
+
getHint,
|
|
348
|
+
getCorrection,
|
|
349
|
+
subject: "Mathématiques",
|
|
350
|
+
getQuestionFromIdentifiers,
|
|
351
|
+
hasHintAndCorrection: true,
|
|
352
|
+
answerType: "QCU",
|
|
353
|
+
};
|