// Numbas version: finer_feedback_settings {"name": "Find characteristic polynomial, eigenvalues and eigenvectors of a 2x2 matrix", "extensions": ["linear-algebra", "linalg2"], "custom_part_types": [{"source": {"pk": 2, "author": {"name": "Christian Lawson-Perfect", "pk": 7}, "edit_page": "/part_type/2/edit"}, "name": "List of numbers", "short_name": "list-of-numbers", "description": "

The answer is a comma-separated list of numbers.

\n

The list is marked correct if each number occurs the same number of times as in the expected answer, and no extra numbers are present.

\n

You can optionally treat the answer as a set, so the number of occurrences doesn't matter, only whether each number is included or not.

", "help_url": "", "input_widget": "string", "input_options": {"correctAnswer": "join(\n if(settings[\"correctAnswerFractions\"],\n map(let([a,b],rational_approximation(x), string(a/b)),x,settings[\"correctAnswer\"])\n ,\n settings[\"correctAnswer\"]\n ),\n settings[\"separator\"] + \" \"\n)", "hint": {"static": false, "value": "if(settings[\"show_input_hint\"],\n \"Enter a list of numbers separated by {settings['separator']}.\",\n \"\"\n)"}, "allowEmpty": {"static": true, "value": true}}, "can_be_gap": true, "can_be_step": true, "marking_script": "bits:\nlet(b,filter(x<>\"\",x,split(studentAnswer,settings[\"separator\"])),\n if(isSet,list(set(b)),b)\n)\n\nexpected_numbers:\nlet(l,settings[\"correctAnswer\"] as \"list\",\n if(isSet,list(set(l)),l)\n)\n\nvalid_numbers:\nif(all(map(not isnan(x),x,interpreted_answer)),\n true,\n let(index,filter(isnan(interpreted_answer[x]),x,0..len(interpreted_answer)-1)[0], wrong, bits[index],\n warn(wrong+\" is not a valid number\");\n fail(wrong+\" is not a valid number.\")\n )\n )\n\nis_sorted:\nassert(sort(interpreted_answer)=interpreted_answer,\n multiply_credit(0.5,\"Not in order\")\n )\n\nincluded:\nmap(\n let(\n num_student,len(filter(x=y,y,interpreted_answer)),\n num_expected,len(filter(x=y,y,expected_numbers)),\n switch(\n num_student=num_expected,\n true,\n num_studentThe separate items in the student's answer

", "definition": "let(b,filter(x<>\"\",x,split(studentAnswer,settings[\"separator\"])),\n if(isSet,list(set(b)),b)\n)"}, {"name": "expected_numbers", "description": "", "definition": "let(l,settings[\"correctAnswer\"] as \"list\",\n if(isSet,list(set(l)),l)\n)"}, {"name": "valid_numbers", "description": "

Is every number in the student's list valid?

", "definition": "if(all(map(not isnan(x),x,interpreted_answer)),\n true,\n let(index,filter(isnan(interpreted_answer[x]),x,0..len(interpreted_answer)-1)[0], wrong, bits[index],\n warn(wrong+\" is not a valid number\");\n fail(wrong+\" is not a valid number.\")\n )\n )"}, {"name": "is_sorted", "description": "

Are the student's answers in ascending order?

", "definition": "assert(sort(interpreted_answer)=interpreted_answer,\n multiply_credit(0.5,\"Not in order\")\n )"}, {"name": "included", "description": "

Is each number in the expected answer present in the student's list the correct number of times?

", "definition": "map(\n let(\n num_student,len(filter(x=y,y,interpreted_answer)),\n num_expected,len(filter(x=y,y,expected_numbers)),\n switch(\n num_student=num_expected,\n true,\n num_studentHas every number been included the right number of times?

", "definition": "all(included)"}, {"name": "no_extras", "description": "

True if the student's list doesn't contain any numbers that aren't in the expected answer.

", "definition": "if(all(map(x in expected_numbers, x, interpreted_answer)),\n true\n ,\n incorrect(\"Your answer contains \"+extra_numbers[0]+\" but should not.\");\n false\n )"}, {"name": "interpreted_answer", "description": "A value representing the student's answer to this part.", "definition": "if(lower(studentAnswer) in [\"empty\",\"\u2205\"],[],\n map(\n if(settings[\"allowFractions\"],parsenumber_or_fraction(x,notationStyles), parsenumber(x,notationStyles))\n ,x\n ,bits\n )\n)"}, {"name": "mark", "description": "This is the main marking note. It should award credit and provide feedback based on the student's answer.", "definition": "if(studentanswer=\"\",fail(\"You have not entered an answer\"),false);\napply(valid_numbers);\napply(included);\napply(no_extras);\ncorrectif(all_included and no_extras)"}, {"name": "notationStyles", "description": "", "definition": "[\"en\"]"}, {"name": "isSet", "description": "

Should the answer be considered as a set, so the number of times an element occurs doesn't matter?

", "definition": "settings[\"isSet\"]"}, {"name": "extra_numbers", "description": "

Numbers included in the student's answer that are not in the expected list.

", "definition": "filter(not (x in expected_numbers),x,interpreted_answer)"}], "settings": [{"name": "correctAnswer", "label": "Correct answer", "help_url": "", "hint": "The list of numbers that the student should enter. The order does not matter.", "input_type": "code", "default_value": "", "evaluate": true}, {"name": "allowFractions", "label": "Allow the student to enter fractions?", "help_url": "", "hint": "", "input_type": "checkbox", "default_value": false}, {"name": "correctAnswerFractions", "label": "Display the correct answers as fractions?", "help_url": "", "hint": "", "input_type": "checkbox", "default_value": false}, {"name": "isSet", "label": "Is the answer a set?", "help_url": "", "hint": "If ticked, the number of times an element occurs doesn't matter, only whether it's included at all.", "input_type": "checkbox", "default_value": false}, {"name": "show_input_hint", "label": "Show the input hint?", "help_url": "", "hint": "", "input_type": "checkbox", "default_value": true}, {"name": "separator", "label": "Separator", "help_url": "", "hint": "The substring that should separate items in the student's list", "input_type": "string", "default_value": ",", "subvars": false}], "public_availability": "always", "published": true, "extensions": []}], "resources": [], "navigation": {"allowregen": true, "showfrontpage": false, "preventleave": false, "typeendtoleave": false}, "question_groups": [{"pickingStrategy": "all-ordered", "questions": [{"name": "Find characteristic polynomial, eigenvalues and eigenvectors of a 2x2 matrix", "tags": ["characteristic polynomial", "eigenvalue", "eigenvector", "explore mode", "Linear algebra", "Linear Algebra", "linear algebra"], "metadata": {"description": "

Example of an explore mode question. Student is given a 2x2 matrix and is asked to find the characteristic polynomial and eigenvalues, and then eigenvectors for each eigenvalue. The part asking for eigenvectors can be repeated as often as the student wants, to be used for different eigenvalues.

\n

Assessed: calculating characteristic polynomial and eigenvectors.

\n

Feature: any correct eigenvector is recognised by the marking algorithm, also multiples of the \"obvious\" one(s) (given the reduced row echelon form that we use to calculate them).

\n

Randomisation: a random true/false for invertibility is created, and the eigenvalues a and b are randomised (condition: two different evalues, and a=0 iff invertibility is false), and a random invertible 2x2 matrix with determinant 1 or -1 is created (via random elementary row operations) to change base from diag(a,b) to the matrix for the question. Determinant 1 or -1 ensures that we keep integer entries.

\n

The implementation uses linear algebra functions such as \"find reduced echelon form\" or \"find kernel of a reduced echelon form\", from the extension \"linalg2\".

", "licence": "Creative Commons Attribution 4.0 International"}, "statement": "

Find the characteristic polynomial, eigenvalues and eigenvectors (bases for eigenspaces) for the matrix \\(\\var[fractionNumbers]{matrixA}\\).

", "advice": "

The characteristic polynomial of \\(A\\) is defined as \\(\\chi_A(t)=\\det(tI-A)\\). So in this case you should calculate

\n

\\[\\begin{vmatrix} \\simplify{t-{matrixA[0][0]}} & \\var{-matrixA[0][1]} \\\\ \\var{-matrixA[1][0]} & \\simplify{t-{matrixA[1][1]}} \\end{vmatrix}=\\simplify[!zeroterm]{(t-{matrixA[0][0]})(t-{matrixA[1][1]})-{matrixA[0][1]*matrixA[1][0]}}=\\var{chiAexpanded}= \\var[timesdot]{chiA}.\\]

\n

You can use the formula for the determinant a \\(2\\times 2\\) matrix:\\( \\begin{vmatrix}a&b\\\\c&d\\end{vmatrix}=ad-bc\\).

\n

The eigenvalues are exactly the roots of the characteristic polynomial. So the eigenvalues of \\(A\\) are \\(\\var{a}\\) and \\(\\var{b}\\).

\n

To calculate the eigenvectors for a given eigenvalue \\(\\lambda\\), we calculate the kernel of \\(A-\\lambda I\\).

\n

So, for \\(\\lambda=\\var{a}\\), we calculate the kernel of \\(\\var{matrixA-a*id(2)}\\), using the Gauss-Jordan algorithm.

\n

\\[ \\begin{pmatrix} \\var{matrixA[0][0]-a} & \\var{matrixA[0][1]} \\\\ \\var{matrixA[1][0]}& \\var{matrixA[1][1]-a} \\end{pmatrix} \\to \\begin{pmatrix}1 & \\var[fractionNumbers]{matrixA[0][1]/(matrixA[0][0]-a)} \\\\ \\var{matrixA[1][0]}& \\var{matrixA[1][1]-a} \\end{pmatrix} \\to \\var[fractionNumbers]{RREFa}\\] \\[ \\begin{pmatrix} \\var{matrixA[0][0]-a} & \\var{matrixA[0][1]} \\\\ \\var{matrixA[1][0]}& \\var{matrixA[1][1]-a} \\end{pmatrix} \\to \\begin{pmatrix}0 & 1\\\\ \\var{matrixA[1][0]}& \\var{matrixA[1][1]-a} \\end{pmatrix} \\to \\var[fractionNumbers]{RREFa} \\]

\n

The reduced row echelon form is \\(\\var[fractionNumbers]{RREFa}\\). If we write the eigenvector as \\(\\begin{pmatrix}x\\\\y\\end{pmatrix}\\), this means that we have \\(\\simplify[fractionNumbers, timesdot,all]{{RREFa[0][0]}*x+{RREFa[0][1]}*y=0}\\). We can choose \\(y=1\\), which gives us \\(x=\\var[fractionNumbers]{-RREFa[0][1]}\\). But \\(x\\) can be any number, and we can choose it to be \\(1\\). So the eigenvector for \\(\\lambda=\\var{a}\\) is \\(\\var[fractionNumbers]{v1}\\) (or any multiple of this).

\n

And for \\(\\lambda=\\var{b}\\), the reduced row echelon form of \\(\\var{matrixA-b*id(2)}\\) is \\(\\var[fractionNumbers]{RREFb}\\). If we write the eigenvector as \\(\\begin{pmatrix}x\\\\y\\end{pmatrix}\\) again, this means that we have \\(\\simplify[fractionNumbers, timesdot,all]{{RREFb[0][0]}*x+{RREFb[0][1]}*y=0}\\). We can choose \\(y=1\\), which gives us \\(x=\\var[fractionNumbers]{-RREFb[0][1]}\\). But \\(x\\) can be any number, and we can choose it to be \\(1\\). So the eigenvector is \\(\\var[fractionNumbers]{v2}\\) (or any multiple).

", "rulesets": {}, "extensions": ["linalg2", "linear-algebra"], "builtin_constants": {"e": true, "pi,\u03c0": true, "i": true}, "constants": [], "variables": {"matrixA": {"name": "matrixA", "group": "Getting the matrix", "definition": "Pinverse*matrix([a,0],[0,b])*P", "description": "

The matrix is calculated from a diagonal matrix by base change. This ensures we have the correct characteristic polynomial and eigenvalues. To get integer entries, we ensure that det P = 1 or -1. (see variable testing condition)

", "templateType": "anything", "can_override": false}, "a": {"name": "a", "group": "Eigenvalues", "definition": "random(-5..5)", "description": "

Picking between 0 as eigenvalue and a non-zero eigenvalue

", "templateType": "anything", "can_override": false}, "b": {"name": "b", "group": "Eigenvalues", "definition": "random(-5..5 except 0 )", "description": "

Second eigenvalue should not be the same as the first, because otherwise the matrix is just a multiple of the identity, which is too easy. This is ensured by a variable testing condition.

", "templateType": "anything", "can_override": false}, "chiA": {"name": "chiA", "group": "Characteristic polynomial", "definition": "simplify(expression(\"(t-{a})*(t-{b})\"),\"all\")", "description": "

The characteristic polynomial in factorised form.

", "templateType": "anything", "can_override": false}, "v1": {"name": "v1", "group": "Getting the matrix", "definition": "matrix(le_row_shuffle(id(n),2,5))", "description": "

This is a base change matrix which is used to calculate the matrix A. The function le_row_shuffle is in the Leicester extension \"linalg2\", and performs some random elementary row operations on the identity matrix to get a random invertible matrix. The testing condition ensures that the determinant of this matrix is 1 or -1, so that the matrix A will have integer entries.

", "templateType": "anything", "can_override": false}, "v2": {"name": "v2", "group": "Eigenvectors and their calculation", "definition": "transpose(matrix(le_kernel(RREFb)))", "description": "

Eigenvector for eigenvalue b. The function \"le_kernel\" gives the kernel of a reduced row echelon form as a row, so we tranpose it to get the vector.

", "templateType": "anything", "can_override": false}, "RREFa": {"name": "RREFa", "group": "Eigenvectors and their calculation", "definition": "matrix(reduced_row_echelon_form(matrixA-a*id(n)))", "description": "

Reduced row echelon form of \\(A-a I\\). The kernel of \\(A-aI\\) gives the eigenvectors for eigevalue a. This reduced row echelon form is automatically calculated by the extension \"Linear algebra\".

", "templateType": "anything", "can_override": false}, "RREFb": {"name": "RREFb", "group": "Eigenvectors and their calculation", "definition": "matrix(reduced_row_echelon_form(matrixA-b*id(n)))", "description": "

Reduced row echelon form of \\(A-b I\\). The kernel of \\(A-bI\\) gives the eigenvectors for eigevalue b. This reduced row echelon form is automatically calculated by the extension \"Linear algebra\".

", "templateType": "anything", "can_override": false}, "n": {"name": "n", "group": "Getting the matrix", "definition": "2", "description": "

The matrix has size \\(n\\times n\\). Mostly this is here because I copied much of the implementation over to use for \\(3\\times 3\\) matrices as well, and maybe bigger. That means one doesn't have to change the \\(n\\) everywhere, only once.

", "templateType": "anything", "can_override": false}, "chiAexpanded": {"name": "chiAexpanded", "group": "Characteristic polynomial", "definition": "simplify(expression(\"(t-{a})*(t-{b})\"),[\"expandBrackets\",\"all\"])", "description": "

The characteristic polynomial in expanded form, so we can use it in Advice.

", "templateType": "anything", "can_override": false}, "detP": {"name": "detP", "group": "Getting the matrix", "definition": "det(P)", "description": "

Determinant of P, to use in testing condition (and in calculating the inverse).

", "templateType": "anything", "can_override": false}, "Pinverse": {"name": "Pinverse", "group": "Getting the matrix", "definition": "1/detP*matrix([P[1][1],-P[0][1]],[-P[1][0],P[0][0]])", "description": "

This is the inverse of the base change matrix P, which we also need to calculate the matrix A.

", "templateType": "anything", "can_override": false}, "testinverse": {"name": "testinverse", "group": "Getting the matrix", "definition": "P*Pinverse=id(n)", "description": "

Just so we can visually ensure ourselves that we have really calculated the inverse of P :-)

", "templateType": "anything", "can_override": false}, "p": {"name": "p", "group": "Ungrouped variables", "definition": "", "description": "", "templateType": "anything", "can_override": false}}, "variablesTest": {"condition": "(detP=1 or detP=-1) and a<>b", "maxRuns": "100"}, "ungrouped_variables": ["p"], "variable_groups": [{"name": "Eigenvalues", "variables": ["a", "b"]}, {"name": "Getting the matrix", "variables": ["n", "v1", "Pinverse", "testinverse", "detP", "matrixA"]}, {"name": "Characteristic polynomial", "variables": ["chiA", "chiAexpanded"]}, {"name": "Eigenvectors and their calculation", "variables": ["RREFa", "RREFb", "v1", "v2"]}], "functions": {}, "preamble": {"js": "", "css": ""}, "parts": [{"type": "gapfill", "useCustomName": true, "customName": "Char poly", "marks": 0, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [{"label": "Find eigenvalues", "rawLabel": "Find eigenvalues", "otherPart": 1, "variableReplacements": [], "availabilityCondition": "answered and credit=1", "penalty": "", "penaltyAmount": 0, "lockAfterLeaving": true}], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

The characteristic polynomial is \\(\\chi_A(t)= \\) [[0]]

", "gaps": [{"type": "jme", "useCustomName": true, "customName": "char_A", "marks": 1, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "answer": "{chiA}", "showPreview": true, "checkingType": "absdiff", "checkingAccuracy": 0.001, "failureRate": 1, "vsetRangePoints": 5, "vsetRange": [0, 1], "checkVariableNames": false, "singleLetterVariables": false, "allowUnknownFunctions": true, "implicitFunctionComposition": false, "caseSensitive": false, "valuegenerators": []}], "sortAnswers": false}, {"type": "gapfill", "useCustomName": true, "customName": "eigenvalues", "marks": 0, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [{"label": "Find eigenvectors", "rawLabel": "Find eigenvectors", "otherPart": 2, "variableReplacements": [], "availabilityCondition": "answered and credit=1", "penalty": "", "penaltyAmount": 0, "lockAfterLeaving": true}], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

The eigenvalues of \\(A\\) are (in any order): [[0]]

", "gaps": [{"type": "list-of-numbers", "useCustomName": true, "customName": "eigenvalues", "marks": 1, "scripts": {}, "customMarkingAlgorithm": "included:\nmap(\n let(\n num_student,len(filter(x=y,y,interpreted_answer)),\n num_expected,len(filter(x=y,y,expected_numbers)),\n switch(\n num_student=num_expected,\n true,\n num_studentNow choose one of the eigenvalues of \\(A\\): [[0]]

\n

and enter the corresponding eigenvector(s).

\n

Enter a basis for the relevant eigenspace of \\(A\\), i.e. a linearly independent set of eigenvectors for your chosen eigenvalue, as the columns of a matrix. E.g. if there is only one eigenvector, select \"1 column\" and enter the vector. If there are two, select \"2 columns\" and enter the first vector in the first column and the second vector in the second column, etc. This way you can determine how many eigenvectors there are.

\n

[[1]]

", "gaps": [{"type": "numberentry", "useCustomName": true, "customName": "Chosen eigenvalue", "marks": "0", "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": false, "showFeedbackIcon": false, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "minValue": "a", "maxValue": "a", "correctAnswerFraction": false, "allowFractions": true, "mustBeReduced": false, "mustBeReducedPC": "0", "showFractionHint": true, "notationStyles": ["plain", "en", "si-en"], "correctAnswerStyle": "plain"}, {"type": "matrix", "useCustomName": true, "customName": "Eigenvector(s)", "marks": 1, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": false, "showFeedbackIcon": false, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "correctAnswer": "v1", "correctAnswerFractions": false, "numRows": 1, "numColumns": 1, "allowResize": true, "tolerance": 0, "markPerCell": false, "allowFractions": true, "minColumns": 1, "maxColumns": 0, "minRows": 1, "maxRows": 0}], "sortAnswers": false}, {"type": "information", "useCustomName": true, "customName": "Finish", "marks": 0, "scripts": {}, "customMarkingAlgorithm": "", "extendBaseMarkingAlgorithm": true, "unitTests": [], "showCorrectAnswer": true, "showFeedbackIcon": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "nextParts": [], "suggestGoingBack": false, "adaptiveMarkingPenalty": 0, "exploreObjective": null, "prompt": "

You have calculated everything, or decided you do not want to calculate anything else. Above you can see which parts you have worked on, and you can go back to them by clicking on the corresponding link.

"}], "partsMode": "explore", "maxMarks": 0, "objectives": [], "penalties": [], "objectiveVisibility": "always", "penaltyVisibility": "always", "type": "question", "contributors": [{"name": "Christian Lawson-Perfect", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/7/"}, {"name": "Julia Goedecke", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/5121/"}]}]}], "contributors": [{"name": "Christian Lawson-Perfect", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/7/"}, {"name": "Julia Goedecke", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/5121/"}]}