Лекция Стивена Вольфрама

ВНИМАНИЕ!!!

БЛОГ ПЕРЕЕХАЛ НА НОВЫЙ АДРЕС https://blog.wolframmathematica.ru

Онлайн машина вычисления знаний Wolfram|Alpha ®

Онлайн машина вычисления знаний Wolfram|Alpha ®

четверг, 29 ноября 2012 г.

Автоматическая генерация вариантов контрольных работ и ответов к ним в Mathematica
Автоматическая генерация вариантов контрольных работ и ответов к ним в Mathematica
Общее количество использованных в посте встроенных функций или символов: 84

Список имен используемых встроенных функций и символов в порядке их появления в коде:
RandomReal | List ({...}) | RandomInteger | RandomChoice | Power (^) | Sin | Cos | BesselJ | E (e) | Times (*, ×) | Thread | Rule (->, ->) | RandomSample | SetDelayed (:=) | Block | CompoundExpression (;) | Set (=) | While | Apply (@@) | SameQ (===) | Pattern (:) | Blank (_) | Dot (.) | Cross (×) | VectorAngle | Out (%) | Or (||, ∨) | Less (<) | Length | DeleteDuplicates | Map (/@) | Function (&) | Equal (==) | DeleteCases | Slot (#) | Transpose | Reduce | TraditionalForm | RawBoxes | RowBox | Piecewise | GridBox | ToBoxes | ReplaceAll (/.) | Subscript | Abs | Grid | Det | Join | Range | Plot | Pi (π) | D (∂) | Sort | Greater (>) | DiagonalMatrix | MatrixForm | Inverse | Part ([[…]]) | Cases | Integer | Infinity | Total | Flatten | Not (!, ¬) | FreeQ | Eigensystem | Table | Unequal (!=, ≠) | Span (;;) | All | Frame | ItemSize | Alignment | Center | ItemStyle | Bold | Column | Dividers | False | Left | Export | StringJoin (<>) | NotebookDirectory
Любой учитель в школе или преподаватель в ВУЗе сталкивается с проблемой проверки знаний учащихся по своему предмету. Стандартной проверкой знаний учащегося обычно служит некоторая контрольная работа или тест. Если вы работаете в старших классах школы или в вузе, то создание большого количества схожих вариантов одной контрольной работы потребует огромного количества времени, особенно если вы хотите снабдить каждого учащегося уникальным вариантом. Скажем, в обычной группе студентов ВУЗа около 25 человек, даже если один вариант контрольной работы будет содержать всего 4 задания, то потребуется создать уже 100 задач.
К тому же нужно помнить о том, что мы живем в век цифровых технологий... а значит вся информация, в том числе и варианты контрольных работ, быстро распространятся в интернете и следующие группы студентов (классы школьников) будут уже знать заранее все, что будет в контрольной, если, особенно, существует, скажем, всего 4 варианта некоторой контрольной работы, которые даются из года в год учащимся.
С помощью Mathematica вы можете решить описанные проблемы, генерируя качественные задания вместе с ответами к ним в нужном количестве. При этом вы будете уверены в том, что все задачи будут корректны, а ответы будут абсолютно точно верны.
В этом посте я продемонстрирую то, как можно создать произвольное количество вариантов некоторой контрольной работы, вместе с ответами к ней. Надеюсь, что пост окажется полезен для вас.
Генерация вариантов контрольной работы по линейной алгебре
Создадим вариант контрольной работы по линейной алгебре, который будет содержать 4 задачи:
1) для двух трехмерных векторов вычислить их скалярное и векторное произведения, а также найти угол между ними;
2) методом Гаусса решить систему 3-х линейных уравнений с 4 неизвестными;
3) вычислить определитель 3-го порядка;
4) найти собственные числа и векторы матрицы 3x3.
Построение алгоритмов для генерирования условий и ответов
Задача 1. Для двух векторов вычислить их скалярное и векторное произведения, а также найти угол между ними
Для генерации схожих вариантов заданий очень удобно использовать функции, которые дают последовательность произвольной длины псевдослучайных чисел, которые распределены равномерно.
Среди этих функций стоит отметить:
generatzia_kontrolnyh_i_otvetov_v_Mathematica_1.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_2.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_3.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_4.gif
Приведу несколько примеров работы с данными функциями.
Генерация матрицы 3x4 из случайных десятичных дробей:
In[1]:=
RandomReal[{-100, 1000}, {3, 4}]
Out[1]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_5.gif
Генерация последовательности из 10 точек с целочисленными координатами:
In[2]:=
RandomInteger[{12, 100}, {10, 2}]
Out[2]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_6.gif
Случайная последовательность из 20 функций:
In[3]:=
RandomChoice[{x, x^2, Sin[x], Cos[x], BesselJ[0, x], E^x, 1/x}, 20]
Out[3]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_7.gif
Случайные правила замены, описывающие распределение работ между людьми:
In[4]:=
Thread[RandomSample[{"Иванов", "Петров", "Сидоров", "Манухина", "Смирнова", "Пуненкова"}, 6] ->RandomSample[{"Помыть пол", "Стереть с доски", "Подмести пол", "Полить цветы", "Вынести мусор", "Сварить борщ"}, 6]]
Out[4]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_8.gif
Теперь можно приступить к генерации условия для задачи 1.
Нам нужны два трехмерных вектора. При этом, так как данное задание в целом простое с вычислительной точки зрения, то можно просто сгенерировать два вектора, координаты которых были бы, скажем, целыми числами из диапазона [-5, 5]:
In[5]:=
task[1] := RandomInteger[{-5, 5}, {2, 3}]
In[6]:=
task[1]
Out[6]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_9.gif
Так как генерация происходит случайно, то может случиться так, что векторы получатся одинаковыми, чтобы избежать этого немного модифицируем функцию  task[1]:
In[7]:=
task[1] := Block[{vectors, vectorsGenerator}, vectorsGenerator := RandomInteger[{-5, 5}, {2, 3}] ; vectors = vectorsGenerator ; While[SameQ @@ vectors, vectors = vectorsGenerator] ; vectors]
In[8]:=
task[1]
Out[8]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_10.gif
Здесь были использованы функции Apply в виде @@, которая изменяет головную часть выражения:
generatzia_kontrolnyh_i_otvetov_v_Mathematica_11.gif
А также функция обычного условного цикла While и функция  SameQ, которая проверяет идентичность двух выражений, обычно употребляется в виде  ==, т. е. SameQ[x, y] тоже что и x==y.
Теперь создадим функцию, которая будет генерировать ответ к заданию. Для этого нам потребуются функции:  Dot (часто употребляется в короткой форме a.b) для вычисления скалярного произведения векторов, Cross для вычисления векторного произведения и VectorAngle для вычисления наименьшего угла между векторами.
In[9]:=
answer[1][task_] := {Dot @@ task, Cross @@ task, VectorAngle @@ task}
Что ж, попробуем сгенерировать задание и получить ответ:
In[10]:=
task[1]
Out[10]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_12.gif
In[11]:=
answer[1][%]
Out[11]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_13.gif
Задача 2. Методом Гаусса решить систему 3-х линейных уравнений с 4 неизвестными.
С помощью функции RandomInteger сгенерируем основную матрицу системы и вектор свободных членов. При этом пусть коэффициенты при неизвестных будут целыми числами в интервале [-3, 3], а свободные члены — [-5, 5]:
In[12]:=
A := RandomInteger[{-3, 3}, {3, 4}]
In[13]:=
B := RandomInteger[{-5, 5}, 3]
In[14]:=
{A, B}
Out[14]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_14.gif
Ввиду случайной генерации основной матрицы системы, возможна ситуация, когда некоторая строка (или строки) или некоторый столбец (столбцы) будут состоять только из нулей или в матрице будет несколько одинаковых строк. Также нас не устроит, если все элементы столбца свободных членов будут нулями. Такие ситуации нас не устраивают, поэтому исключим такую возможность подобно тому, как мы делали это выше:
In[15]:=
A := Block[{A, AGenerator}, AGenerator := RandomInteger[{-3, 3}, {3, 4}] ; A = AGenerator ; While[Length[DeleteDuplicates[A]] <Length[A] || Or @@ ((DeleteCases[#, 0] == {}) &/@A) || Or @@ ((DeleteCases[#, 0] == {}) &/@Transpose[A]), A = AGenerator] ; A]
In[16]:=
B := Block[{B, BGenerator}, BGenerator := RandomInteger[{-5, 5}, 3] ; B = BGenerator ; While[DeleteCases[B, 0] == {}, B = BGenerator] ; B]
In[17]:=
{A, B}
Out[17]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_15.gif
Здесь были использованы функции:
generatzia_kontrolnyh_i_otvetov_v_Mathematica_16.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_17.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_18.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_19.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_20.gif
Теперь построим, собственно, систему линейных уравнений:
In[18]:=
system := Thread[A . {x[1], x[2], x[3], x[4]} == B]
In[19]:=
system
Out[19]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_21.gif
Здесь была использована функция Thread, которая позволяет “распространить” функцию над всеми списками, которые входят в ее тело в качестве аргументов, пример:
In[20]:=
{Thread[f[{a, b}]], Thread[f[{a, b}, {1, 2}]]}
Out[20]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_22.gif
Теперь попробуем найти решение системы, это можно сделать, например, с помощью функции Reduce:
In[21]:=
system
Out[21]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_23.gif
In[22]:=
Reduce[%, {x[1], x[2], x[3], x[4]}]
Out[22]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_24.gif
Создадим функцию, которая будет выдавать задание в привычном виде:
In[23]:=
task[2][system_] := TraditionalForm[RawBoxes[RowBox[{"", GridBox[Transpose[{ToBoxes/@(system/.x[i_] ->x_i)}]]}]]]
In[24]:=
task[2][system]
Out[24]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_25.gif
Во введенной функции были использованы следующие встроенные выражения: функция TraditionalForm, позволяющая представить выражение в привычной математической нотации и функции RawBoxes, RowBox, GridBox, ToBoxes с помощью которых осуществляется низкоуровневое форматирование выражений. Вообще говоря, в конечном счете (на самом низком уровне), любая конструкция в Mathematica является набором некоторых блоков (boxes), которые представляются функциями которые содержат всегда в своем названии слово Box.
Что ж, теперь сделаем последний шаг — создадим функцию, которая будет выдавать ответ в привычной форме:
In[25]:=
answer[2][system_] := TraditionalForm[Reduce[system, {x[1], x[2], x[3], x[4]}]/.x[i_] ->x_i]
Попробуем сгенерировать задание и получить ответ:
In[26]:=
system
Out[26]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_26.gif
In[27]:=
task[2][%]
Out[27]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_27.gif
In[28]:=
answer[2][%%]
Out[28]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_28.gif
Задача 3. Вычислить определитель 3-го порядка.
С помощью функции RandomInteger сгенерируем определитель третьего порядка с элементами, которые являются положительными целыми числами в интервале [1, 10]:
In[29]:=
det := RandomInteger[{1, 10}, {3, 3}]
In[30]:=
det
Out[30]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_29.gif
Наложим на генерируемую матрицу схожие ограничения, что мы вводили выше для основной матрицы системы, добавим еще одно условие — чтобы не было одинаковых столбцов (условия относительно 0 нам не нужны, так как числа берутся в интервале [1, 10]):
In[31]:=
det := Block[{det, detGenerator}, detGenerator := RandomInteger[{1, 10}, {3, 3}] ; det = detGenerator ; While[Length[DeleteDuplicates[A]] <Length[det] || Length[DeleteDuplicates[Transpose[A]]] <Length[Transpose[A]], det = detGenerator] ; det]
In[32]:=
det
Out[32]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_30.gif
Создадим функцию, которая будет выдавать задание в привычном виде (функция Grid позволяет сформировать таблицу):
In[33]:=
task[3][det_] := TraditionalForm[Abs[Grid[det]]]
In[34]:=
task[3][det]
Out[34]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_31.gif
Наконец, сделаем функцию, которая будет вычислять ответ (функция Det позволяет вычислить определить произвольной квадратной матрицы, как символьно, так и численно) и провем работоспособность наших функций на конкретном примере:
In[35]:=
answer[3][det_] := Det[det]
In[36]:=
det
Out[36]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_32.gif
In[37]:=
task[3][%]
Out[37]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_33.gif
In[38]:=
answer[3][%%]
Out[38]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_34.gif
Задача 4. Найти собственные числа и векторы матрицы 3x3.
Из линейной алгебры известно, что матрицы A и BAB-1 имеют одинаковые собственные числа и собственные векторы. Также известно, что если матрица A диагональная, то на ее диагонали стоят ее собственные числа. Используем эти факты для удобной и простой генерации матриц 3x3, которые будут иметь заданные “красивые” целые собственные числа в интервале [-5, 5] без нуля. Воспользуемся функцией RandomSample для генерации списка из трех собственных, различных между собой, чисел (функция Range[a, b, c] генерирует список чисел от a до b с шагом c):
In[39]:=
eigenvalues := RandomSample[Range[-5, -1] ~ Join ~ Range[1, 5], 3]
In[40]:=
eigenvalues
Out[40]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_35.gif
Здесь использована инфиксная форма работы с функцией Join, позволяющей объединять элементы двух и более списков в один. Вообще, инфиксная форма весьма удобна, она работает так:
x ~ f ~ y == f[x, y]
Вот несколько интересных примеров:
In[41]:=
Sin[x] ~ Plot ~ {x, 0, 2Pi}
Out[41]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_36.gif
In[42]:=
(Cos[x ^y]) ~ D ~ {{x, y}}
Out[42]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_37.gif
In[43]:=
Range[20] ~ Sort ~ (Cos[#1] >Sin[#2] &)
Out[43]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_38.gif
Теперь, построим матрицу, на диагонали которой будут стоять числа из данного списка, все элементы которой нули, это можно осуществить с помощью функции DiagonalMatrix:
In[44]:=
matrix := DiagonalMatrix[eigenvalues]
In[45]:=
matrix
Out[45]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_39.gif
In[46]:=
MatrixForm[%]
Out[46]//MatrixForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_40.gif
Для создания условия задания нам понадобится невырожденная матрица, размера 3x3 и обратная к ней, которую можно найти с помощью функции Inverse. Создадим функцию, которая бы выдавала список из матрицы B и обратной к ней:
In[47]:=
invertibleMatrix := Block[{invertibleMatrix, invertibleMatrixGenerator}, invertibleMatrixGenerator := RandomInteger[{-5, 5}, {3, 3}] ; invertibleMatrix = invertibleMatrixGenerator ; While[Det[invertibleMatrix] == 0, invertibleMatrix = invertibleMatrixGenerator] ; {invertibleMatrix, Inverse[invertibleMatrix]}]
In[48]:=
invertibleMatrix
Out[48]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_41.gif
Теперь мы имеем список из матрицы B и B-1) .
Попробуем найти матрицу BAB-1), которая будут иметь те же собственные числа и векторы, что и матрица A:
In[49]:=
matrix
Out[49]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_42.gif
In[50]:=
invertibleMatrix
Out[50]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_43.gif
In[51]:=
#1 . %% . #2& @@ %
Out[51]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_44.gif
Ясно, что матрица BAB-1 может быть в общем случае весьма “некрасивой” и неудобной в работе. Сделаем так, чтобы на выходе мы получали матрицу только из целых чисел, причем сумма их модулей не превышала бы 9*20=180 (т. е. чтобы каждое число было по модулю не более 20) и среди них не было бы 0:
In[52]:=
taskMatrix := Block[{evalues, iMatrix, taskMatrix}, evalues = matrix ; iMatrix = invertibleMatrix ; taskMatrix = (iMatrix[[1]] . evalues . iMatrix[[2]]) ; While[Length[Cases[taskMatrix, _Integer, Infinity]] <9 || Total[Abs[Flatten[taskMatrix]]] >180 || Not[FreeQ[taskMatrix, 0]], evalues = matrix ; iMatrix = invertibleMatrix ; taskMatrix = (iMatrix[[1]] . evalues . iMatrix[[2]]) ;] ; taskMatrix]
In[53]:=
taskMatrix
Out[53]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_45.gif
Здесь были использованы следующие функции:
generatzia_kontrolnyh_i_otvetov_v_Mathematica_46.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_47.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_48.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_49.gif
generatzia_kontrolnyh_i_otvetov_v_Mathematica_50.gif
Теперь создадим функцию, которая будет выдавать задание в привычном виде:
In[54]:=
task[4][matrix_] := TraditionalForm[MatrixForm[matrix]]
In[55]:=
task[4][taskMatrix]
Out[55]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_51.gif
Наконец, сделаем функцию, которая будет вычислять ответ (функция Eigensystem выдает список собственных чисел и векторов):
In[56]:=
answer[4][matrix_] := Transpose[Eigensystem[matrix]]
In[57]:=
taskMatrix
Out[57]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_52.gif
In[58]:=
task[4][%]
Out[58]//TraditionalForm=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_53.gif
In[59]:=
answer[4][%%]
Out[59]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_54.gif
Построение одного варианта контрольной работы
Используя созданные функции мы можем теперь создать один вариант контрольной работы:
In[60]:=
variant := {{#, answer[1][#]} &[task[1]], {task[2][#], answer[2][#]} &[system], {task[3][#], answer[3][#]} &[det], {task[4][#], answer[4][#]} &[taskMatrix]}
In[61]:=
variant
Out[61]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_55.gif
Генерация произвольного числа вариантов контрольной работы
Теперь создадим столько разных вариантов, сколько нам нужно, например 5:
In[62]:=
variants[n_] := Block[{variants, variantsGenerator}, variantsGenerator := Table[variant, {n}] ; variants = variantsGenerator ; While[Total[Length[DeleteDuplicates[#]] &/@Transpose[variants[[;;, ;;, 1]]]] != 4n, variants = variantsGenerator] ; variants]
In[63]:=
variants[5]
Out[63]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_56.gif
Формирование готового списка задач для учащихся и ответов для преподавателя
Каждый вариант состоит из списков по два элемента — условия и ответа.
Разобьем список вариантов на два списка, условий и ответов:
In[64]:=
controlWorkTasksAndAnswers[n_] := Block[{Variants}, Variants = Transpose[variants[n]] ; {Transpose[Variants[[;;, ;;, 1]]], Transpose[Variants[[;;, ;;, 2]]]}]
In[65]:=
controlWorkTasksAndAnswers[5]
Out[65]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_57.gif
Теперь представим варианты и ответы к ним в красивом, отформатированном виде.
Для начала сгенерируем некоторое количество вариантов, например 15:
In[66]:=
controlWork = controlWorkTasksAndAnswers[15] ;
Теперь подготовим варианты и ответы к ним:
In[67]:=
table["task"] = Grid[Table[{i} ~ Join ~ controlWork[[1, i]], {i, 1, Length[controlWork[[1]]]}], Frame->All, ItemSize-> {{1, 6, 12, 5, 6}}, Alignment-> {Center, Center}, ItemStyle-> {Bold, 14}]
Out[67]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_58.gif
In[68]:=
table["answer"] = Grid[Table[{i, Column[controlWork[[2, i]], Dividers->Center]}, {i, 1, Length[controlWork[[2]]]}], Frame-> {False, {{1}}}, ItemSize-> {{1, 25}, 8}, Alignment-> {Left, Center}, ItemStyle-> {Bold, 14}]
Out[68]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_59.gif
После этого вам остается только экспортировать полученные варианты и ответы к ним, например, в TIFF и распечатать. Это можно сделать с помощью функции Export (функция NotebookDirectory дает адрес директории в которой сохранен текущий документ Mathematica, так что соответствующие файлы будут созданы там же):
In[69]:=
Export[NotebookDirectory[] <>"linear_algebra_kw_tasks.tiff", table["task"]]
Out[69]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_60.gif
In[70]:=
Export[NotebookDirectory[] <>"linear_algebra_kw_answers.tiff", table["answer"]]
Out[70]=
generatzia_kontrolnyh_i_otvetov_v_Mathematica_61.gif
После генерации, в данном случае картинок, остается их распечатать и разрезать на варианты. Теперь вы можете генерировать произвольное число качественных вариантов вместе с ответами к ним, при этом как все задачи, так и все ответы будут корректны.
generatzia_kontrolnyh_i_otvetov_v_Mathematica_62.gif

Блог принадлежит “Русскоязычной поддержке Wolfram Mathematica
При любом использовании материалов блога, ссылка на блог обязательна.
SpikeyСоздано с помощью Wolfram Mathematica 8

1 комментарий:

  1. Спасибо. Очень подробно, доходчиво и наверняка будет кому-то полезно на практике.

    ОтветитьУдалить