# Khan/khan-exercises

### Subversion checkout URL

You can clone with HTTPS or Subversion.

Add exercises: Multiplying a matrix with a vector, multiplying a matr…

…ix with a matrix, matrix dimensions, and defined and undefined matrix operations

Summary:
- First pass at question-based hints

Test Plan: Tested locally

Reviewers: eater

Reviewed By: eater

Differential Revision: http://phabricator.khanacademy.org/D856
stephjang authored
30 css/khan-exercise.css
 @@ -654,3 +654,33 @@ div.timeline-total { opacity: 0.8; filter: alpha(opacity = 80); } + +/* Question-based hints */ + +.qhint { + border: 1px solid #aaaaaa; + background: #f9f9f9; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + margin-right: 20px; + margin-bottom: 20px; + padding: 10px; +} + +.qhint-answer { + display: none; +} + +.qhint-feedback { + font-weight: bold; + color: #6495ED; +} + +.qhint-feedback.correct { + color: #28AE7B; +} + +.qhint-feedback.incorrect { + color: #CE4444; +}
125 exercises/defined_and_undefined_matrix_operations.html
 @@ -0,0 +1,125 @@ + + + + + Defined and undefined matrix operations + + + + +
+ +
+ DEFINED ? "Yes" : "No" + + makeMatrix(randRange(-2, 4, DIM_1, DIM_2)) + makeMatrix(randRange(-2, 4, DIM_3, DIM_4)) + + "\\textbf " + randFromArray("ABCDEF") + "\\textbf " + randFromArray("ABCDEF") + + + printSimpleMatrix(MAT_1) + + + printSimpleMatrix(MAT_2) + +
+ +
+

+ PRETTY_MAT_1_ID = PRETTY_MAT_1 +

+

+ PRETTY_MAT_2_ID = PRETTY_MAT_2 +

+
+ +

+ Is PRETTY_MAT_1_ID + OPERATION + PRETTY_MAT_2_ID defined? +

+ +

+
+
• Yes
• +
• No
• +
+ +
+
+
+ randRange(0, 1) + randRange(1, 3) + randRange(1, 3) + DIM_1 + + DEFINED ? DIM_2 : randRangeExclude(1, 3, [DIM_2]) + + randFromArray("+-") +
+ +
+
+

+ In order for additionsubtraction of two matrices to be defined, the matrices must have the same dimensions. +

+

+ If PRETTY_MAT_1_ID is of dimension (\blue m \times \red n) and PRETTY_MAT_2_ID is of dimension (\blue p \times \red q), then: +

+

+ 1. \blue m (number of rows in PRETTY_MAT_1_ID) must equal \blue p (number of rows in PRETTY_MAT_2_ID) and +

+

+ 2. \red n (number of columns in PRETTY_MAT_1_ID) must equal \red q (number of columns in PRETTY_MAT_2_ID) +

+

+ for their sumdifference to be defined. +

+
+
+

+ Since PRETTY_MAT_1_ID has the samedifferent dimensions (DIM_1 + "\\times" + DIM_2) asfrom PRETTY_MAT_2_ID (DIM_3 + "\\times" + DIM_4), +

+ PRETTY_MAT_1_ID + OPERATION + PRETTY_MAT_2_ID is not defined. +

+
+
+
+ +
+
+ randRange(0, 1) + randRange(1, 3) + randRange(1, 3) + + DEFINED ? DIM_2 : randRangeExclude(1, 3, [DIM_2]) + + randRange(1, 3) + "" +
+ +
+
+

+ In order for multiplication of two matrices to be defined, the two inner dimensions must be equal. +

+
+
+

+ If the two matrices have dimensions (\blue m \times \red n) and (\red p \times \green q), then \red n (number of columns in the first matrix) must equal \red p (number of rows in the second matrix) for their product to be defined. +

+
+
+ Since PRETTY_MAT_1_ID has the samea different number of columns (DIM_2) asthan PRETTY_MAT_2_ID has rows (DIM_3), PRETTY_MAT_1_ID + PRETTY_MAT_2_ID is not defined. +
+
+
+
+ +
+ +
165 exercises/defined_and_undefined_matrix_operations_alternative.html
 @@ -0,0 +1,165 @@ + + + + + Defined and undefined matrix operations + + + + +
+ +
+ DEFINED ? "Yes" : "No" + + makeMatrix(randRange(-2, 4, DIM_1, DIM_2)) + makeMatrix(randRange(-2, 4, DIM_3, DIM_4)) + + "\\textbf " + randFromArray("ABCDEF") + "\\textbf " + randFromArray("ABCDEF") + + + printSimpleMatrix(MAT_1) + + + printSimpleMatrix(MAT_2) + +
+ +
+

+ PRETTY_MAT_1_ID = PRETTY_MAT_1 +

+

+ PRETTY_MAT_2_ID = PRETTY_MAT_2 +

+
+ +

+ Is PRETTY_MAT_1_ID + OPERATION + PRETTY_MAT_2_ID defined? +

+ +

+
+
• Yes
• +
• No
• +
+ +
+
+
+ randRange(0, 1) + randRange(1, 3) + randRange(1, 3) + DIM_1 + + DEFINED ? DIM_2 : randRangeExclude(1, 3, [DIM_2]) + + randFromArray("+-") +
+ +
+
+

+ In order for additionsubtraction of two matrices to be defined, the matrices must have the same dimensions. +

+

+ If PRETTY_MAT_1_ID is of dimension (\blue m \times \red n) and PRETTY_MAT_2_ID is of dimension (\blue p \times \red q), then: +

+

+ 1. \blue m (number of rows in PRETTY_MAT_1_ID) must equal \blue p (number of rows in PRETTY_MAT_2_ID) and +

+

+ 2. \red n (number of columns in PRETTY_MAT_1_ID) must equal \red q (number of columns in PRETTY_MAT_2_ID) +

+

+ for their sumdifference to be defined. +

+
+
+

+ Do PRETTY_MAT_1_ID and PRETTY_MAT_2_ID have the same number of rows? +

+ DIM_1 === DIM_3 ? "Yes" : "No" +

+ + +

+
+
+

+ Do PRETTY_MAT_1_ID and PRETTY_MAT_2_ID have the same number of columns? +

+ DIM_2 === DIM_4 ? "Yes" : "No" +

+ + +

+
+
+

+ Since PRETTY_MAT_1_ID has the samedifferent dimensions (DIM_1 + "\\times" + DIM_2) asfrom PRETTY_MAT_2_ID (DIM_3 + "\\times" + DIM_4), +

+ PRETTY_MAT_1_ID + OPERATION + PRETTY_MAT_2_ID is not defined. +

+
+
+
+ +
+
+ randRange(0, 1) + randRange(1, 3) + randRange(1, 3) + + DEFINED ? DIM_2 : randRangeExclude(1, 3, [DIM_2]) + + randRange(1, 3) + "" +
+ +
+
+

+ In order for multiplication of two matrices to be defined, the two inner dimensions must be equal. +

+
+
+

+ If the two matrices have dimensions (\blue m \times \red n) and (\red p \times \green q), then \red n (number of columns in the first matrix) must equal \red p (number of rows in the second matrix) for their product to be defined. +

+
+
+

+ How many columns does the first matrix, PRETTY_MAT_1_ID, have? +

+ DIM_2 +

+ + +

+
+
+

+ How many rows does the second matrix, PRETTY_MAT_2_ID, have? +

+ DIM_3 +

+ + +

+
+
+ Since PRETTY_MAT_1_ID has the samea different number of columns (DIM_2) asthan PRETTY_MAT_2_ID has rows (DIM_3), PRETTY_MAT_1_ID + PRETTY_MAT_2_ID is not defined. +
+
+
+
+ +
+ +
 @@ -38,16 +38,20 @@ PINK - printMatrix(MAT_A, MAT_A_COLOR) + printSimpleMatrix(MAT_A, MAT_A_COLOR) - printMatrix(MAT_B, MAT_B_COLOR) + printSimpleMatrix(MAT_B, MAT_B_COLOR) - printMatrix(MAT_A, MAT_A_COLOR, MAT_B, MAT_B_COLOR, OPERATION) + printMatrix(function(a, b) { + a = colorMarkup(a, MAT_A_COLOR); + b = colorMarkup(b, MAT_B_COLOR); + return a + OPERATION + b; + }, MAT_A, MAT_B) - printMatrix(SOLN_MAT, SOLN_MAT_COLOR) + printSimpleMatrix(SOLN_MAT, SOLN_MAT_COLOR)
61 exercises/matrix_dimensions.html
 @@ -0,0 +1,61 @@ + + + + + Matrix dimensions + + + + +
+
+ randRange(1, 4) + randRange(1, 4) + makeMatrix(randRange(-2, 4, DIM_1, DIM_2)) + + "\\textbf " + randFromArray("ABCDEF") + + printSimpleMatrix(MAT_A) + +
+
+
+
+

+ PRETTY_MAT_ID = PRETTY_MAT_A +

+
+ +

+ What are the dimensions of matrix PRETTY_MAT_ID? +

+ +
+ DIM_1 + \times + DIM_2 +
+
+
+ +
+
+

+ The first dimension is the number of rows in the matrix. PRETTY_MAT_ID has DIM_1 rows. +

+
+
+

+ The second dimension is the number of columns in the matrix. PRETTY_MAT_ID has DIM_2 columns. +

+
+ So, PRETTY_MAT_ID is a DIM_1 \times DIM_2 matrix. +
+
+
+ +
72 exercises/matrix_dimensions_alternative.html
 @@ -0,0 +1,72 @@ + + + + + Matrix dimensions + + + + +
+
+ randRange(1, 4) + randRange(1, 4) + makeMatrix(randRange(-2, 4, DIM_1, DIM_2)) + + "\\textbf " + randFromArray("ABCDEF") + + printSimpleMatrix(MAT_A) + +
+
+
+
+

+ PRETTY_MAT_ID = PRETTY_MAT_A +

+
+ +

+ What are the dimensions of matrix PRETTY_MAT_ID? +

+ +
+ DIM_1 + \times + DIM_2 +
+
+
+ +
+
+

+ The first dimension is the number of rows in the matrix. How many rows does PRETTY_MAT_ID have? +

+ DIM_1 +

+ + +

+
+
+

+ The second dimension is the number of columns in the matrix. How many columns does PRETTY_MAT_ID have? +

+ DIM_2 +

+ + +

+
+
+ So, PRETTY_MAT_ID is a DIM_1 \times DIM_2 matrix. +
+
+
+ +
194 exercises/multiplying_a_matrix_by_a_matrix.html
 @@ -0,0 +1,194 @@ + + + + + Multiplying a matrix by a matrix + + + + +
+ +
+ DIM_2 + makeMatrix(randRange(-2, 5, DIM_1, DIM_2)) + makeMatrix(randRange(-2, 5, DIM_3, DIM_4)) + + + matrixMult(MAT_1, MAT_2) + + + "\\textbf " + randFromArray("ABCDEF") + "\\textbf " + randFromArray("ABCDEF") + + + [GREEN, BLUE, GRAY] + [ORANGE, "#DF0030", "#9D38BD"] + + + makeMultHintMatrix(MAT_1, MAT_2, ROW_COLORS, COL_COLORS) + + +
+ +
+

+ Let PRETTY_MAT_1_ID = printSimpleMatrix(MAT_1) and + PRETTY_MAT_2_ID = printSimpleMatrix(MAT_2). +

+
+ +

+ What is PRETTY_MAT_1_ID + PRETTY_MAT_2_ID? +

+ +
+
+

+ Because PRETTY_MAT_1_ID has dimensions (DIM_1 + "\\times" + DIM_2) and PRETTY_MAT_2_ID has dimensions (DIM_3 + "\\times" + DIM_4), the answer matrix will have dimensions (DIM_1 + "\\times" + DIM_4). +

+

+ + PRETTY_MAT_1_ID + PRETTY_MAT_2_ID + = + printColoredDimMatrix(MAT_1, ROW_COLORS, true) + printColoredDimMatrix(MAT_2, COL_COLORS, false) + = + + printSimpleMatrix(maskMatrix(FINAL_HINT_MAT, [])) + + +

+
+
+

+ To find the element at any row i, column j of the answer matrix, multiply the elements in row i of the first matrix, PRETTY_MAT_1_ID, with the corresponding elements in column j of the second matrix, PRETTY_MAT_2_ID, and add the products together. +

+
+
+

+ So, to find the element at row 1, column 1 of the answer matrix, multiply the first element in colorMarkup("\\text{row }1", ROW_COLORS[0]) of PRETTY_MAT_1_ID with the first element in colorMarkup("\\text{column }1", COL_COLORS[0]) of PRETTY_MAT_2_ID, then multiply the second element in colorMarkup("\\text{row }1", ROW_COLORS[0]) of PRETTY_MAT_1_ID with the second element in colorMarkup("\\text{column }1", COL_COLORS[0]) of PRETTY_MAT_2_ID, and so on. Add the products together. +

+

+ + + printSimpleMatrix( + maskMatrix(FINAL_HINT_MAT, [[1, 1]]) + ) + + +

+
+
+

+ Likewise, to find the element at row 2, column 1 of the answer matrix, multiply the elements in colorMarkup("\\text{row }2", ROW_COLORS[1]) of PRETTY_MAT_1_ID with the corresponding elements in colorMarkup("\\text{column }1", COL_COLORS[0]) of PRETTY_MAT_2_ID and add the products together. +

+

+ + + printSimpleMatrix( + maskMatrix(FINAL_HINT_MAT, [[1, 1], [2, 1]]) + ) + + +

+
+
+

+ Likewise, to find the element at row 1, column 2 of the answer matrix, multiply the elements in colorMarkup("\\text{row }1", ROW_COLORS[0]) of PRETTY_MAT_1_ID with the corresponding elements in colorMarkup("\\text{column }2", COL_COLORS[1]) of PRETTY_MAT_2_ID and add the products together. +

+

+ + + printSimpleMatrix( + maskMatrix(FINAL_HINT_MAT, [[1, 1], [2, 1], [1, 2]]) + ) + + +

+
+
+

+ Fill out the rest: +

+

+ + + printSimpleMatrix(FINAL_HINT_MAT) + + +

+
+
+

After simplifying, we end up with:

+
+ + printSimpleMatrix(SOLN_MAT) + +
+
+
+ +
+

+ + elem + +

+
+ +
+ +
+
+ 2 + 2 + 2 +
+
+
+
+ 2 + 3 + 2 +
+
+ + +
+
+ 2 + 2 + 3 +
+
+ + +
+
+ 3 + 1 + 2 +
+
+
+
+ 3 + 2 + 2 +
+
+
+ +
+ +
170 exercises/multiplying_a_matrix_by_a_vector.html
 @@ -0,0 +1,170 @@ + + + + + Multiplying a matrix by a vector + + + + +
+ +
+ DIM_2 + 1 + makeMatrix(randRange(-2, 5, DIM_1, DIM_2)) + makeMatrix(randRange(-2, 5, DIM_3, DIM_4)) + + + matrixMult(MAT_1, MAT_2) + + + "\\textbf " + randFromArray("ABCDEF") + "\\textbf " + randFromArray("vw") + + + [GREEN, BLUE, GRAY] + [ORANGE] + + + makeMultHintMatrix(MAT_1, MAT_2, ROW_COLORS, COL_COLORS) + + +
+ +
+

+ Let PRETTY_MAT_1_ID = printSimpleMatrix(MAT_1) and + PRETTY_MAT_2_ID = printSimpleMatrix(MAT_2). +

+
+ +

+ What is PRETTY_MAT_1_ID + PRETTY_MAT_2_ID? +

+ +
+
+

+ Because PRETTY_MAT_1_ID has dimensions (DIM_1 + "\\times" + DIM_2) and PRETTY_MAT_2_ID has dimensions (DIM_3 + "\\times" + DIM_4), the answer matrix will have dimensions (DIM_1 + "\\times" + DIM_4). +

+

+ + PRETTY_MAT_1_ID + PRETTY_MAT_2_ID + = + printColoredDimMatrix(MAT_1, ROW_COLORS, true) + printColoredDimMatrix(MAT_2, COL_COLORS, false) + = + + printSimpleMatrix(maskMatrix(FINAL_HINT_MAT, [])) + + +

+
+
+

+ To find the element at any row i, column j of the answer matrix, multiply the elements in row i of the first matrix, PRETTY_MAT_1_ID, with the corresponding elements in column j of the second matrix, PRETTY_MAT_2_ID, and add the products together. +

+
+
+

+ So, to find the element at row 1, column 1 of the answer matrix, multiply the first element in colorMarkup("\\text{row }1", ROW_COLORS[0]) of PRETTY_MAT_1_ID with the first element in colorMarkup("\\text{column }1", COL_COLORS[0]) of PRETTY_MAT_2_ID, then multiply the second element in colorMarkup("\\text{row }1", ROW_COLORS[0]) of PRETTY_MAT_1_ID with the second element in colorMarkup("\\text{column }1", COL_COLORS[0]) of PRETTY_MAT_2_ID, and so on. Add the products together. +

+

+ + + printSimpleMatrix( + maskMatrix(FINAL_HINT_MAT, [[1, 1]]) + ) + + +

+
+
+

+ Likewise, to find the element at row 2, column 1 of the answer matrix, multiply the elements in colorMarkup("\\text{row }2", ROW_COLORS[1]) of PRETTY_MAT_1_ID with the corresponding elements in colorMarkup("\\text{column }1", COL_COLORS[0]) of PRETTY_MAT_2_ID and add the products together. +

+

+ + + printSimpleMatrix( + maskMatrix(FINAL_HINT_MAT, [[1, 1], [2, 1]]) + ) + + +

+
+
+

+ Fill out the rest: +

+

+ + + printSimpleMatrix(FINAL_HINT_MAT) + + +

+
+
+

After simplifying, we end up with:

+
+ + printSimpleMatrix(SOLN_MAT) + +
+
+
+ +
+

+ + elem + +

+
+ +
+ + +
+
+ 2 + 2 +
+
+
+
+ 2 + 3 +
+
+ + +
+
+ 3 + 2 +
+
+ + +
+
+ 4 + 2 +
+
+
+
+ +
15 exercises/scalar_matrix_multiplication.html
 @@ -27,24 +27,23 @@ return a * SCALAR; }, MAT_A) - - deepZipWith(2, function(a) { - return SCALAR; - }, MAT_A) - BLUE GREEN PINK - printMatrix(MAT_A, MAT_A_COLOR) + printSimpleMatrix(MAT_A, MAT_A_COLOR) - printMatrix(SCALAR_MAT, SCALAR_COLOR, MAT_A, MAT_A_COLOR, OPERATION) + printMatrix(function(a) { + var s = colorMarkup(SCALAR, SCALAR_COLOR); + var b = colorMarkup(a, MAT_A_COLOR); + return s + OPERATION + b; + }, MAT_A) - printMatrix(SOLN_MAT, SOLN_MAT_COLOR) + printSimpleMatrix(SOLN_MAT, SOLN_MAT_COLOR)
22 utils/math.js
 @@ -482,6 +482,28 @@ $.extend(KhanUtil, { isInt: function(num) { return parseFloat(num) === parseInt(num, 10) && !isNaN(num); }, + + + /** + * Add LaTeX color markup to a given value. + */ + colorMarkup: function(val, color) { + return "\\color{" + color + "}{" + val + "}"; + }, + + /** + * Like _.contains except using _.isEqual to verify if item is present. + * (Works for lists of non-primitive values.) + */ + contains: function(list, item) { + return _.any(list, function(elem) { + if (_.isEqual(item, elem)) { + return true; + } + return false; + }); + }, + BLUE: "#6495ED", ORANGE: "#FFA500", PINK: "#FF00AF", 177 utils/matrix.js  @@ -14,51 +14,67 @@$.extend(KhanUtil, { }, /** - * Given a 2d matrix, return the LaTeX (MathJax) code for printing - * the matrix. - * - * If optional parameters mat2, color2, and operation are included, this - * can be used to generate intermediate hint matrices as in - * matrix_addition.html. - * - * @param mat {array} a 2d matrix - * ex: [[0, 2], [1, 3], [4, 5]] (3 x 2 matrix) - * @param color {string} (optional) color to format the elements of /mat/, - in hexadecimal. ex: "#28AE7B" (KhanUtil.GREEN) - * @param mat2 {array} (optional) a 2d matrix w/ same dimensions as /mat/ - * @param color2 {string} (optional) color to format the elements of /mat2/ - * @param operation {string} (optional) operation being explained in hints - * ex: "+" + * Apply the given function to each element of the given matrix and return + * the resulting matrix. */ - printMatrix: function(mat, color, mat2, color2, operation) { - // return prematurely if no matrix included - if (!_.isArray(mat) || !mat.length) { - return ""; - } + matrixMap: function(fn, mat) { + return _.map(mat, function(row, i) { + return _.map(row, function(elem, j) { + return fn(elem, i, j); + }); + }); + }, - var isCombo = (_.isArray(mat2) && mat2.length === mat.length && - mat2[0].length === mat[0].length && - _.isString(color2) && _.isString(operation)); + /** + * Given a matrix and list of row-col indices to exclude from masking, + * return a new matrix with all but the elements in excludeList overwritten + * by the value "?". + * + * @param mat {result of makeMatrix} + * @param excludeList {array of arrays} List of row-col indices to keep + * from being overwritten. Note that these indices start at 1, not + * 0, to match with common math notation. + */ + maskMatrix: function(mat, excludeList) { + var result = []; + + _.times(mat.r, function(i) { + var row = []; + _.times(mat.c, function(j) { + if (KhanUtil.contains(excludeList, [i+1, j+1])) { + row.push(mat[i][j]); + } else { + row.push("?"); + } + }); + result.push(row); + }); + return result; + }, - if (isCombo) { - mat = KhanUtil.deepZipWith(2, function(a, b) { - var elem1 = "\\color{" + color + "}{" + a + "}"; - var elem2 = "\\color{" + color2 + "}{" + b + "}"; - return elem1 + operation + elem2; - }, mat, mat2); - } + /** + * Given one or more same-dimension 2d matrices and a function for + * how to combine and format their elements in the output matrix, + * return the LaTeX code for rendering the matrix. Inherits syntax from + * deepZipWith(). + * + * Example usage: + * + * printMatrix(function(a, b) { + * return colorMarkup(a, "#FF0000") + "-" + colorMarkup(b, "#00FF00"); + * }, matA, matB); + * + */ + printMatrix: function(fn) { + var args = Array.prototype.slice.call(arguments); + mat = KhanUtil.deepZipWith.apply(this, [2].concat(args)); var table = _.map(mat, function(row, i) { return row.join(" & "); }).join(" \\\\ "); - var prefix = "\\left[ \\begin{array}"; - var suffix = "\\end{array} \\right]"; - - if (!isCombo && color) { - prefix = "\\left[ \\color{" + color + "}{\\begin{array}"; - suffix = "\\end{array}} \\right]"; - } + var prefix = "\\left[\\begin{array}"; + var suffix = "\\end{array}\\right]"; // to generate the alignment info needed for LaTeX table markup var alignment = "{"; @@ -71,6 +87,77 @@ .extend(KhanUtil, { return prefix + alignment + table + suffix; }, + /** + * Given a matrix and a color, format all elements with the given color + * (if supplied) and return the LaTeX code for rendering the matrix. + * + * @param mat {array of arrays} the matrix to format + * @param color {string} + */ + printSimpleMatrix: function(mat, color) { + return KhanUtil.printMatrix(function(item) { + if (color) { + return KhanUtil.colorMarkup(item, color); + } + return item; + }, mat); + }, + + /** + * Format the rows or columns of the given matrix with the colors in the + * given colors array, and return the LaTeX code for rendering the matrix. + * + * @param mat {array of arrays} the matrix to format + * @param colors {array of strings} list of colors + * @param isRow {bool} whether to apply the colors by row or by column + */ + printColoredDimMatrix: function(mat, colors, isRow) { + var matrix = KhanUtil.matrixMap(function(item, i, j) { + var color = colors[isRow ? i : j]; + return KhanUtil.colorMarkup(item, color); + }, mat); + return KhanUtil.printSimpleMatrix(matrix); + }, + + /** + * Generate markup for a color-coded matrix illustrating the calculations + * behind each element in matrix multiplication. + * + * @param a {result of makeMatrix} the first matrix + * @param b {result of makeMatrix} the second matrix + * @param rowColors {array of strings} list of colors to apply to the + * rows of the first matrix + * @param colColors {array of strings} list of colors to apply to the + * columns of the second matrix + */ + makeMultHintMatrix: function(a, b, rowColors, colColors) { + var c = []; + // create the new matrix + _.times(a.r, function() { + c.push([]); + }); + + // perform the multiply + _.times(a.r, function(i) { + var c1 = rowColors[i]; + _.times(b.c, function(j) { + var c2 = colColors[j]; + var temp = ""; + _.times(a.c, function(k) { + if (k > 0) { + temp += "+"; + } + var elem1 = KhanUtil.colorMarkup(a[i][k], c1); + var elem2 = KhanUtil.colorMarkup(b[k][j], c2); + temp += elem1 + "\\cdot" + elem2; + }); + c[i][j] = temp; + }); + }); + + return KhanUtil.makeMatrix(c); + }, + // add matrix properties to a 2d matrix // currently only rows and columns makeMatrix: function(m) { @@ -84,20 +171,20 @@.extend(KhanUtil, { matrixMult: function(a, b) { var c = []; // create the new matrix - for (var i = 0; i < a.r; ++i) { + _.times(a.r, function() { c.push([]); - } + }); // perform the multiply - for (var i = 0; i < a.r; ++i) { - for (var j = 0; j < b.c; ++j) { + _.times(a.r, function(i) { + _.times(b.c, function(j) { var temp = 0; - for (var k = 0; k < a.c; ++k) { + _.times(a.c, function(k) { temp += a[i][k] * b[k][j]; - } + }); c[i][j] = temp; - } - } + }); + }); // add matrix properties to the result return KhanUtil.makeMatrix(c);
64 utils/qhints.js
 @@ -0,0 +1,64 @@ +$.fn["qhintsLoad"] = function() { + + var checkAnswer = function(parent, source) { + var feedback = parent.find(".qhint-feedback"); + + // if answer already revealed in the feedback, don't do anything + if (feedback.length) { + return; + } + + // make a new feedback element + feedback =$("

", { "class": "qhint-feedback" }); + var answer = $(parent.find(".qhint-answer")).text(); + var input = parent.find(".qhint-input"); + var userInput = ""; + + if (source) { + var type = source.attr("type"); + if (type === "text" || type === "submit") { + userInput =$(parent.find("input:text")).val(); + } else if (type === "button") { + userInput = $(source).val(); + } + } + + // hide input element and instead show the feedback element + input.hide(); + + if (!source) { + feedback.text(answer); + } else if (userInput === answer) { + feedback.text("Correct! The answer is " + answer + ".") + .addClass("correct"); + } else { + feedback.text("Incorrect. The answer is " + answer + ".") + .addClass("incorrect"); + } + + parent.append(feedback); + }; + + var handleCheck = function(e) { + var parent =$(e.currentTarget).parents(".qhint"); + checkAnswer(parent, $(e.currentTarget)); + }; + + var selectors = ".qhint input:submit, .qhint input:button"; +$("body").on("click", selectors, handleCheck); + + // check hint when user presses enter + $("body").on("keydown", ".qhint input:text", function(e) { + // enter is pressed + if (e.keyCode === 13) { + handleCheck(e); + } + }); + +$(Khan).on("hintUsed", function() { + var lastQhElem = \$(".qhint").last(); + if (lastQhElem.length) { + checkAnswer(lastQhElem, null); + } + }); +};