Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add exercises: Finding the determinant of a matrix, finding the inver…

…se of a matrix

Test Plan: Tested locally

Reviewers: eater

Reviewed By: eater

Differential Revision: http://phabricator.khanacademy.org/D891
  • Loading branch information...
commit 8fc85e7bcee3198c18e3b744f4fe3fa9f0e68ecf 1 parent 6935430
@stephjang stephjang authored
View
42 css/khan-exercise.css
@@ -655,6 +655,12 @@ div.timeline-total {
filter: alpha(opacity = 80);
}
+/* Video hints */
+
+.video-hint {
+ margin-bottom: 20px;
+}
+
/* Question-based hints */
.qhint {
@@ -683,4 +689,40 @@ div.timeline-total {
.qhint-feedback.incorrect {
color: #CE4444;
+}
+
+/* Fancy matrix input - goes along with matrix-input.js */
+
+#answer_area .matrix-row .sol {
+ margin: 0;
+ float: left;
+}
+
+#answer_area .matrix-row .sol input[type=text] {
+ width: 45px;
+ height: 30px;
+ border: none;
+ margin: 3px;
+ padding: 1px;
+}
+
+.matrix-input .matrix-bracket {
+ width: 6px;
+ position: absolute;
+ border-top: 2px solid #888;
+ border-bottom: 2px solid #888;
+ /* margin-top must have the same magnitude
+ as the border widths */
+ margin-top: -2px;
+}
+
+.matrix-input .matrix-bracket.bracket-left {
+ border-left: 2px solid #888;
+ /* margin-left for the left bracket must have
+ the same magnitude as the border widths */
+ margin-left: -2px;
+}
+
+.matrix-input .matrix-bracket.bracket-right {
+ border-right: 2px solid #888;
}
View
26 exercises/matrix_addition_and_subtraction.html
@@ -1,19 +1,9 @@
<!DOCTYPE html>
-<html data-require="math matrix">
+<html data-require="math matrix matrix-input">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Matrix addition and subtraction</title>
<script src="../khan-exercise.js"></script>
- <style>
- #answer_area .row input[type=text] {
- width: 40px;
- margin-right: 5px;
- }
-
- #answer_area .row {
- margin: 0;
- }
- </style>
</head>
<body>
<div class="exercise">
@@ -32,6 +22,7 @@
}
}, MAT_A, MAT_B)
</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
<var id="MAT_A_COLOR">BLUE</var>
<var id="MAT_B_COLOR">GREEN</var>
@@ -86,11 +77,16 @@
</div>
<div class="solution" data-type="multiple">
- <p data-each="SOLN_MAT as row" class="row">
- <span data-each="row as elem" class="sol">
- <var>elem</var>
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
</span>
- </p>
+ </div>
</div>
<div class="problems">
View
60 exercises/matrix_determinant.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html data-require="math matrix">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Matrix determinant</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars">
+ <var id="MAT">makeMatrix(randRange(-2, 5, DIM, DIM))</var>
+ <var id="SOLN">matrixDet(MAT)</var>
+ <var id="PRETTY_MAT_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ </div>
+
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_ID</var> = <var>printSimpleMatrix(MAT)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ What is the determinant of <code><var>PRETTY_MAT_ID</var></code>?
+ </p>
+
+ <div class="hints">
+ <div>
+ <p>The solution is:</p>
+ <code>\text{det}(<var>PRETTY_MAT_ID</var>) = <var>SOLN</var></code>
+ </div>
+ </div>
+
+ <div class="solution">
+ <span class="sol"><var>SOLN</var></span>
+ </div>
+
+ <div class="problems">
+ <div id="2x2" data-weight="7">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM">2</var>
+ </div>
+ <div class="hints" data-apply="prependContents">
+ <div data-video-hint data-youtube-id="OU9sWHk_dlw"></div>
+ </div>
+ </div>
+
+ <div id="3x3" data-weight="1">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM">3</var>
+ </div>
+ <div class="hints" data-apply="prependContents">
+ <div data-video-hint data-youtube-id="v4MenooI1J0"></div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
74 exercises/matrix_inverse_2x2.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html data-require="math matrix matrix-input">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Inverse of a 2x2 matrix</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars" data-ensure="DET !== 0">
+ <var id="DIM">2</var>
+ <var id="MAT">makeMatrix(randRange(-2, 5, DIM, DIM))</var>
+ <var id="DET">matrixDet(MAT)</var>
+ <var id="SOLN_MAT">matrixInverse(MAT)</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+ <var id="PRETTY_SOLN_MAT">
+ printMatrix(function(a) {
+ var sign = (a &lt; 0) ? "-" : "";
+
+ var frac = toFraction(abs(a));
+
+ // omit denominator when it's equal to 1
+ if (frac[1] === 1) {
+ return sign + frac[0];
+ }
+
+ return sign + "\\frac{" + frac[0] + "}{" + frac[1] + "}";
+ }, SOLN_MAT)
+ </var>
+ <var id="PRETTY_MAT_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ </div>
+
+ <div class="problems">
+ <div>
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_ID</var> = <var>printSimpleMatrix(MAT)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ <p>
+ What is <code><var>PRETTY_MAT_ID</var>^{-1}</code>?
+ </p>
+ </p>
+
+ <div class="solution" data-type="multiple">
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
+ </span>
+ </div>
+ <p class="example">Express your answer in fractions or exact decimals.</p>
+ <p class="example">The fractions do not need to be simplified.</p>
+ </div>
+
+ <div class="hints">
+ <div data-video-hint data-youtube-id="01c12NaUQDw"></div>
+ <div>
+ <code><var>PRETTY_MAT_ID</var>^{-1} = <var>PRETTY_SOLN_MAT</var></code>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
76 exercises/matrix_inverse_3x3.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html data-require="math matrix matrix-input">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Inverse of a 3x3 matrix</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars" data-ensure="DET !== 0">
+ <var id="DIM">3</var>
+ <var id="MAT">makeMatrix(randRange(-2, 5, DIM, DIM))</var>
+ <var id="DET">matrixDet(MAT)</var>
+ <var id="SOLN_MAT">matrixInverse(MAT)</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+ <var id="PRETTY_SOLN_MAT">
+ printMatrix(function(a) {
+ var sign = (a &lt; 0) ? "-" : "";
+
+ var frac = toFraction(abs(a));
+
+ // omit denominator when it's equal to 1
+ if (frac[1] === 1) {
+ return sign + frac[0];
+ }
+
+ return sign + "\\frac{" + frac[0] + "}{" + frac[1] + "}";
+ }, SOLN_MAT)
+ </var>
+ <var id="PRETTY_MAT_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ </div>
+
+ <div class="problems">
+ <div>
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_ID</var> = <var>printSimpleMatrix(MAT)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ <p>
+ What is <code><var>PRETTY_MAT_ID</var>^{-1}</code>?
+ </p>
+ </p>
+
+ <div class="solution" data-type="multiple">
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
+ </span>
+ </div>
+ <p class="example">Express your answer in fractions or exact decimals.</p>
+ <p class="example">The fractions do not need to be simplified.</p>
+ </div>
+
+ <div class="hints">
+ <div>
+ <div data-video-hint data-youtube-id="xZBbfLLfVV4, ArcrdMkEmKo"></div>
+ </div>
+ <div>
+ <code><var>PRETTY_MAT_ID</var>^{-1} = <var>PRETTY_SOLN_MAT</var></code>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
94 exercises/matrix_transpose.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html data-require="math matrix matrix-input">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Matrix transpose</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars">
+ <var id="MAT">makeMatrix(randRange(0, 9, DIM_1, DIM_2))</var>
+ <var id="SOLN_MAT">matrixTranspose(MAT)</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+ <var id="PRETTY_MAT_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ <var id="PRETTY_SOLN_MAT">printSimpleMatrix(SOLN_MAT)</var>
+ </div>
+
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_ID</var> = <var>printSimpleMatrix(MAT)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ What is <code><var>PRETTY_MAT_ID</var>^{T}</code>?
+ </p>
+
+ <div class="hints">
+ <div>
+ <code><var>PRETTY_MAT_ID</var>^{T}</code> = <code><var>PRETTY_SOLN_MAT</var></code>
+ </div>
+ </div>
+
+ <div class="solution" data-type="multiple">
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
+ </span>
+ </div>
+ </div>
+
+ <div class="problems">
+ <div id="1x2" data-weight="1">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">1</var>
+ <var id="DIM_2">2</var>
+ </div>
+ </div>
+
+ <div id="2x2" data-weight="2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ </div>
+ </div>
+
+ <div id="2x3" data-weight="2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">3</var>
+ </div>
+ </div>
+
+ <div id="3x1" data-weight="1">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">1</var>
+ </div>
+ </div>
+
+ <div id="3x2" data-weight="2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">2</var>
+ </div>
+ </div>
+
+ <div id="3x3" data-weight="2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">3</var>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
32 exercises/multiplying_a_matrix_by_a_matrix.html
@@ -1,19 +1,9 @@
<!DOCTYPE html>
-<html data-require="math matrix">
+<html data-require="math matrix matrix-input">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Multiplying a matrix by a matrix</title>
<script src="../khan-exercise.js"></script>
- <style>
- #answer_area .row input[type=text] {
- width: 40px;
- margin-right: 5px;
- }
-
- #answer_area .row {
- margin: 0;
- }
- </style>
</head>
<body>
<div class="exercise">
@@ -26,6 +16,7 @@
<var id="SOLN_MAT">
matrixMult(MAT_1, MAT_2)
</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
<var id="PRETTY_MAT_1_ID">"\\textbf " + randFromArray("ABCDEF")</var>
<var id="PRETTY_MAT_2_ID">"\\textbf " + randFromArray("ABCDEF")</var>
@@ -42,8 +33,10 @@
<div class="problem">
<p>
- Let <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code> and
- <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>.
+ <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code>
+ </p>
+ <p>
+ <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>
</p>
</div>
@@ -139,11 +132,16 @@
</div>
<div class="solution" data-type="multiple">
- <p data-each="SOLN_MAT as row" class="row">
- <span data-each="row as elem" class="sol">
- <var>elem</var>
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
</span>
- </p>
+ </div>
</div>
<div class="problems">
View
116 exercises/multiplying_a_matrix_by_a_matrix_solution_only.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<html data-require="math matrix matrix-input">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Multiplying a matrix by a matrix</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars" data-ensure="PRETTY_MAT_1_ID !== PRETTY_MAT_2_ID">
+ <var id="DIM_3">DIM_2</var>
+ <var id="MAT_1">makeMatrix(randRange(-2, 5, DIM_1, DIM_2))</var>
+ <var id="MAT_2">makeMatrix(randRange(-2, 5, DIM_3, DIM_4))</var>
+
+ <var id="SOLN_MAT">
+ matrixMult(MAT_1, MAT_2)
+ </var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+
+ <var id="PRETTY_MAT_1_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ <var id="PRETTY_MAT_2_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+
+ <!-- For generating hint matrices-->
+ <var id="ROW_COLORS">[GREEN, BLUE, GRAY]</var>
+ <var id="COL_COLORS">[ORANGE, "#DF0030", "#9D38BD"]</var>
+
+ <var id="FINAL_HINT_MAT">
+ makeMultHintMatrix(MAT_1, MAT_2, ROW_COLORS, COL_COLORS)
+ </var>
+
+ </div>
+
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code>
+ </p>
+ <p>
+ <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ What is <code><var>PRETTY_MAT_1_ID + PRETTY_MAT_2_ID</var></code>?
+ </p>
+
+ <div class="hints">
+ <div>
+ <p>The solution is:</p>
+ <div>
+ <code>
+ <var>printSimpleMatrix(SOLN_MAT)</var>
+ </code>
+ </div>
+ </div>
+ </div>
+
+ <div class="solution" data-type="multiple">
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
+ </span>
+ </div>
+ </div>
+
+ <div class="problems">
+ <!-- 2x2 solution dimensions -->
+ <div id="2x2-2x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ <div id="2x3-3x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">3</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+
+ <!-- 2x3 solution dimensions -->
+ <div id="2x2-2x3">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">3</var>
+ </div>
+ </div>
+
+ <!-- 3x2 solution dimensions -->
+ <div id="3x1-1x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">1</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ <div id="3x2-2x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
176 exercises/multiplying_a_matrix_by_a_matrix_steps_only.html
@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<html data-require="math matrix matrix-input">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Multiplying a matrix by a matrix</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars" data-ensure="PRETTY_MAT_1_ID !== PRETTY_MAT_2_ID">
+ <var id="DIM_3">DIM_2</var>
+ <var id="MAT_1">makeMatrix(randRange(-2, 5, DIM_1, DIM_2))</var>
+ <var id="MAT_2">makeMatrix(randRange(-2, 5, DIM_3, DIM_4))</var>
+
+ <var id="SOLN_MAT">
+ matrixMult(MAT_1, MAT_2)
+ </var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+
+ <var id="PRETTY_MAT_1_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ <var id="PRETTY_MAT_2_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+
+ <!-- For generating hint matrices-->
+ <var id="ROW_COLORS">[GREEN, BLUE, GRAY]</var>
+ <var id="COL_COLORS">[ORANGE, "#DF0030", "#9D38BD"]</var>
+
+ <var id="FINAL_HINT_MAT">
+ makeMultHintMatrix(MAT_1, MAT_2, ROW_COLORS, COL_COLORS)
+ </var>
+
+ </div>
+
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code>
+ </p>
+ <p>
+ <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ What is <code><var>PRETTY_MAT_1_ID + PRETTY_MAT_2_ID</var></code>?
+ </p>
+
+ <div class="hints">
+ <div>
+ <p>
+ <code>
+ <var>PRETTY_MAT_1_ID + PRETTY_MAT_2_ID</var>
+ =
+ <var>printColoredDimMatrix(MAT_1, ROW_COLORS, true)</var>
+ <var>printColoredDimMatrix(MAT_2, COL_COLORS, false)</var>
+ =
+ <var>
+ printSimpleMatrix(maskMatrix(FINAL_HINT_MAT, []))
+ </var>
+ </code>
+ </p>
+ </div>
+ <div>
+ <p>
+ <code>
+ =
+ <var>
+ printSimpleMatrix(
+ maskMatrix(FINAL_HINT_MAT, [[1, 1]])
+ )
+ </var>
+ </code>
+ </p>
+ </div>
+ <div>
+ <p>
+ <code>
+ =
+ <var>
+ printSimpleMatrix(
+ maskMatrix(FINAL_HINT_MAT, [[1, 1], [2, 1]])
+ )
+ </var>
+ </code>
+ </p>
+ </div>
+ <div>
+ <p>
+ <code>
+ =
+ <var>
+ printSimpleMatrix(
+ maskMatrix(FINAL_HINT_MAT, [[1, 1], [2, 1], [1, 2]])
+ )
+ </var>
+ </code>
+ </p>
+ </div>
+ <div>
+ <p>
+ <code>
+ =
+ <var>
+ printSimpleMatrix(FINAL_HINT_MAT)
+ </var>
+ </code>
+ </p>
+ </div>
+ <div>
+ <div>
+ <code>
+ =
+ <var>printSimpleMatrix(SOLN_MAT)</var>
+ </code>
+ </div>
+ </div>
+ </div>
+
+ <div class="solution" data-type="multiple">
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
+ </span>
+ </div>
+ </div>
+
+ <div class="problems">
+ <!-- 2x2 solution dimensions -->
+ <div id="2x2-2x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ <div id="2x3-3x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">3</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+
+ <!-- 2x3 solution dimensions -->
+ <div id="2x2-2x3">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">3</var>
+ </div>
+ </div>
+
+ <!-- 3x2 solution dimensions -->
+ <div id="3x1-1x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">1</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ <div id="3x2-2x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
119 exercises/multiplying_a_matrix_by_a_matrix_video_hint.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html data-require="math matrix matrix-input">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Multiplying a matrix by a matrix</title>
+ <script src="../khan-exercise.js"></script>
+</head>
+<body>
+ <div class="exercise">
+
+ <div class="vars" data-ensure="PRETTY_MAT_1_ID !== PRETTY_MAT_2_ID">
+ <var id="DIM_3">DIM_2</var>
+ <var id="MAT_1">makeMatrix(randRange(-2, 5, DIM_1, DIM_2))</var>
+ <var id="MAT_2">makeMatrix(randRange(-2, 5, DIM_3, DIM_4))</var>
+
+ <var id="SOLN_MAT">
+ matrixMult(MAT_1, MAT_2)
+ </var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+
+ <var id="PRETTY_MAT_1_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+ <var id="PRETTY_MAT_2_ID">"\\textbf " + randFromArray("ABCDEF")</var>
+
+ <!-- For generating hint matrices-->
+ <var id="ROW_COLORS">[GREEN, BLUE, GRAY]</var>
+ <var id="COL_COLORS">[ORANGE, "#DF0030", "#9D38BD"]</var>
+
+ <var id="FINAL_HINT_MAT">
+ makeMultHintMatrix(MAT_1, MAT_2, ROW_COLORS, COL_COLORS)
+ </var>
+
+ </div>
+
+ <div class="problem">
+ <p>
+ <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code>
+ </p>
+ <p>
+ <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>
+ </p>
+ </div>
+
+ <p class="question">
+ What is <code><var>PRETTY_MAT_1_ID + PRETTY_MAT_2_ID</var></code>?
+ </p>
+
+ <div class="hints">
+ <div>
+ <div data-video-hint data-youtube-id="u3Nvcq1D4rI"></div>
+ </div>
+ <div>
+ <p>The solution is:</p>
+ <div>
+ <code>
+ <var>printSimpleMatrix(SOLN_MAT)</var>
+ </code>
+ </div>
+ </div>
+ </div>
+
+ <div class="solution" data-type="multiple">
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
+ </span>
+ </div>
+ </div>
+
+ <div class="problems">
+ <!-- 2x2 solution dimensions -->
+ <div id="2x2-2x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ <div id="2x3-3x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">3</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+
+ <!-- 2x3 solution dimensions -->
+ <div id="2x2-2x3">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">2</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">3</var>
+ </div>
+ </div>
+
+ <!-- 3x2 solution dimensions -->
+ <div id="3x1-1x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">1</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ <div id="3x2-2x2">
+ <div class="vars" data-apply="prependVars">
+ <var id="DIM_1">3</var>
+ <var id="DIM_2">2</var>
+ <var id="DIM_4">2</var>
+ </div>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html>
View
40 exercises/multiplying_a_matrix_by_a_vector.html
@@ -1,19 +1,9 @@
<!DOCTYPE html>
-<html data-require="math matrix">
+<html data-require="math matrix matrix-input">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Multiplying a matrix by a vector</title>
<script src="../khan-exercise.js"></script>
- <style>
- #answer_area .row input[type=text] {
- width: 40px;
- margin-right: 5px;
- }
-
- #answer_area .row {
- margin: 0;
- }
- </style>
</head>
<body>
<div class="exercise">
@@ -27,6 +17,7 @@
<var id="SOLN_MAT">
matrixMult(MAT_1, MAT_2)
</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
<var id="PRETTY_MAT_1_ID">"\\textbf " + randFromArray("ABCDEF")</var>
<var id="PRETTY_MAT_2_ID">"\\textbf " + randFromArray("vw")</var>
@@ -43,8 +34,10 @@
<div class="problem">
<p>
- Let <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code> and
- <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>.
+ <code><var>PRETTY_MAT_1_ID</var> = <var>printSimpleMatrix(MAT_1)</var></code>
+ </p>
+ <p>
+ <code><var>PRETTY_MAT_2_ID</var> = <var>printSimpleMatrix(MAT_2)</var></code>
</p>
</div>
@@ -126,11 +119,16 @@
</div>
<div class="solution" data-type="multiple">
- <p data-each="SOLN_MAT as row" class="row">
- <span data-each="row as elem" class="sol">
- <var>elem</var>
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
</span>
- </p>
+ </div>
</div>
<div class="problems">
@@ -156,14 +154,6 @@
<var id="DIM_2">2</var>
</div>
</div>
-
- <!-- 4x1 solution dimensions -->
- <div id="4x2-2x1">
- <div class="vars" data-apply="prependVars">
- <var id="DIM_1">4</var>
- <var id="DIM_2">2</var>
- </div>
- </div>
</div>
</div>
</body>
View
26 exercises/scalar_matrix_multiplication.html
@@ -1,19 +1,9 @@
<!DOCTYPE html>
-<html data-require="math matrix">
+<html data-require="math matrix matrix-input">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Scalar matrix multiplication</title>
<script src="../khan-exercise.js"></script>
- <style>
- #answer_area .row input[type=text] {
- width: 40px;
- margin-right: 5px;
- }
-
- #answer_area .row {
- margin: 0;
- }
- </style>
</head>
<body>
<div class="exercise">
@@ -28,6 +18,7 @@
return a * SCALAR;
}, MAT_A)
</var>
+ <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
<var id="MAT_A_COLOR">BLUE</var>
<var id="SCALAR_COLOR">GREEN</var>
@@ -74,11 +65,16 @@
</div>
<div class="solution" data-type="multiple">
- <p data-each="SOLN_MAT as row" class="row">
- <span data-each="row as elem" class="sol">
- <var>elem</var>
+ <div data-each="PADDED_SOLN_MAT as row" class="matrix-row">
+ <span data-each="row as elem">
+ <span data-if="elem !== ''" class="sol">
+ <var>elem</var>
+ </span>
+ <span data-else data-type="text" class="sol">
+ <var>elem</var>
+ </span>
</span>
- </p>
+ </div>
</div>
<div class="problems">
View
8 khan-exercise.js
@@ -56,6 +56,9 @@
* updateUserExercise -- when an updated userExercise has been received
and is being used by khan-exercises, either via the result of an API
call or initialization
+
+ * showGuess -- when a guess is populated in the answer area in problem
+ history mode
*/
var Khan = (function() {
@@ -318,7 +321,8 @@ var Khan = (function() {
"simplify": ["math-model", "ast", "expr-helpers", "expr-normal-form", "steps-helpers"],
"congruency": ["angles", "interactive"],
"graphie-3d": ["graphie", "matrix"],
- "graphie-geometry": ["graphie", "matrix"]
+ "graphie-geometry": ["graphie", "matrix"],
+ "matrix-input": ["jquery.cursor-position"]
},
warnTimeout: function() {
@@ -1661,6 +1665,8 @@ var Khan = (function() {
} else {
answerData.showGuess();
}
+ // fire the "show guess" event
+ $(Khan).trigger("showGuess");
// TODO: still highlight even if hint modifies problem (and highlight following hints)
if (slideNum > 0 && (thisState.hintNum > statelist[slideNum - 1].hintNum)) {
View
28 utils/jquery.cursor-position.js
@@ -0,0 +1,28 @@
+(function ($) {
+ // from http://stackoverflow.com/questions/1891444/how-can-i-get-cursor-position-in-a-textarea?rq=1
+ $.fn.getCursorPosition = function() {
+ var el = $(this).get(0);
+ var pos = 0;
+ if ("selectionStart" in el) {
+ pos = el.selectionStart;
+ } else if ("selection" in document) {
+ el.focus();
+ var sel = document.selection.createRange();
+ var selLength = document.selection.createRange().text.length;
+ sel.moveStart("character", -el.value.length);
+ pos = sel.text.length - selLength;
+ }
+ return pos;
+ };
+
+ $.fn.isCursorFirst = function() {
+ var pos = $(this).getCursorPosition();
+ return pos === 0;
+ };
+
+ $.fn.isCursorLast = function() {
+ var pos = $(this).getCursorPosition();
+ var last = $(this).val().length;
+ return pos === last;
+ };
+})(jQuery);
View
320 utils/matrix-input.js
@@ -0,0 +1,320 @@
+/**
+ * Allows for intuitive matrix input for matrix exercises.
+ *
+ * See `matrix_transpose.html` for an example.
+ *
+ * To use in an exercise:
+ *
+ * 1. Add "matrix matrix-input" to data-require.
+ *
+ * 2. Use `matrixPad()` to pad the solution matrix with empty string values
+ * and assign to a `var` named `PADDED_SOLN_MAT`:
+ *
+ * Ex: <var id="PADDED_SOLN_MAT">matrixPad(SOLN_MAT, 3, 3)</var>
+ *
+ * 3. Use the following HTML for the
+ * solution markup:
+ *
+ * <div class="solution" data-type="multiple">
+ * <div data-each="PADDED_SOLN_MAT as row" class="row">
+ * <div data-each="row as elem">
+ * <div data-if="elem !== ''" class="sol">
+ * <var>elem</var>
+ * </div>
+ * <div data-else data-type="text" class="sol">
+ * <var>elem</var>
+ * </div>
+ * </div>
+ * </div>
+ * </div>
+ *
+ */
+
+$.extend(KhanUtil, {
+
+ matrixInput: {
+
+ containerEl: null,
+ bracketEls: null,
+ cells: null,
+
+ LEFT_ARROW: 37,
+ UP_ARROW: 38,
+ RIGHT_ARROW: 39,
+ DOWN_ARROW: 40,
+ ENTER_KEY: 13,
+
+ ROWS: 3,
+ COLS: 3,
+
+ maxRow: 0,
+ maxCol: 0,
+
+ contentMaxRow: 0,
+ contentMaxCol: 0,
+
+ init: function() {
+ var self = this;
+
+ this.initContainer();
+
+ var inputs = $(".matrix-input .sol input[type='text']");
+ this.cells = _.map(inputs, function(input, i) {
+ return {
+ el: input,
+ index: i,
+ row: self.indexToRow(i),
+ col: self.indexToCol(i),
+ val: function() {
+ return $.trim($(this.el).val());
+ },
+ clearVal: function() {
+ $(this.el).val("");
+ }
+ };
+ });
+
+ this.addBrackets();
+
+ this.bindInputEvents();
+ this.resetAllMaxVals();
+ this.render();
+ },
+
+ initContainer: function() {
+ this.containerEl = $("#solutionarea").addClass("matrix-input");
+ },
+
+ addBrackets: function(i) {
+ var left = $("<div>").addClass("matrix-bracket bracket-left");
+ var right = $("<div>").addClass("matrix-bracket bracket-right");
+ this.containerEl.append(left).append(right);
+ this.bracketEls = [left, right];
+ },
+
+ indexToRow: function(i) {
+ return Math.floor(i / this.COLS);
+ },
+
+ indexToCol: function(i) {
+ return i % this.COLS;
+ },
+
+ coordToIndex: function(row, col) {
+ return this.COLS * row + col;
+ },
+
+ bindInputEvents: function() {
+ // We reevaluate the highlighted area after:
+ // 1) clicking on some element besides the cells, or
+ // 2) tabbing to a new cell in the solution area
+ // This is sufficient since these are the only ways
+ // the user will get to change the value.
+ var self = this;
+
+ // case #1
+ $("body").click(function() {
+ self.resetMaxToContentMax();
+ self.render();
+ });
+
+ _.each(this.cells, function(cell) {
+
+ $(cell.el).on({
+ // case #2
+ focus: function(e) {
+ self.setMaxVals(cell);
+ self.render();
+ },
+
+ blur: function(e) {
+ self.setMaxVals(cell);
+ },
+
+ // case #1 (prevent from performing a redundant
+ // reevaluation when clicking on a cell, since focus event
+ // is triggered on both tabs and clicks)
+ click: function(e) {
+ e.stopPropagation();
+ },
+
+ keydown: function(e) {
+ var LAST_ROW = self.ROWS - 1;
+ var LAST_INDEX = self.cells.length - 1;
+
+ var nextIndex = null;
+ var nextRow;
+
+ // cursor position only does something when you
+ // are at the start of the input, moving left, or
+ // at the end of the input, moving right
+
+ if (e.which === self.LEFT_ARROW) {
+ // don't do anything if at the first cell
+ // or if the cursor is not at the start
+ if (cell.index === 0 || !$(this).isCursorFirst()) {
+ return;
+ }
+ nextIndex = cell.index - 1;
+
+ } else if (e.which === self.RIGHT_ARROW) {
+ // don't do anything if at the last cell
+ // or if the cursor is not at the end of the input
+ // text
+ if (cell.index === LAST_INDEX ||
+ !$(this).isCursorLast()) {
+ return;
+ }
+ nextIndex = cell.index + 1;
+
+ } else if (e.which === self.UP_ARROW) {
+ // if already on first row, don't do anything
+ if (cell.row === 0) {
+ return;
+ }
+ nextRow = cell.row - 1;
+ nextIndex = self.coordToIndex(nextRow, cell.col);
+
+ } else if (e.which === self.DOWN_ARROW) {
+ // if on last row, don't do anything
+ if (cell.row === LAST_ROW) {
+ return;
+ }
+ nextRow = cell.row + 1;
+ nextIndex = self.coordToIndex(nextRow, cell.col);
+
+ // when submitting via enter key, make sure max vals
+ // are set properly
+ } else if (e.which === self.ENTER_KEY) {
+ self.setMaxVals(cell);
+ }
+
+ // let default behavior take place if we don't do
+ // anything
+ if (nextIndex === null) {
+ return;
+ }
+
+ // change focus to next input
+ $(self.cells[nextIndex].el).focus();
+
+ // don't let event bubble
+ e.preventDefault();
+ }
+ });
+ });
+ },
+
+ setContentMaxRow: function(val) {
+ this.contentMaxRow = Math.max(val, this.contentMaxRow);
+ },
+
+ setContentMaxCol: function(val) {
+ this.contentMaxCol = Math.max(val, this.contentMaxCol);
+ },
+
+ // maxRow/maxCol is the max of the currently selected element and the
+ // content max element
+ setMaxRow: function(val) {
+ this.maxRow = Math.max(val, this.contentMaxRow);
+ },
+
+ setMaxCol: function(val) {
+ this.maxCol = Math.max(val, this.contentMaxCol);
+ },
+
+ resetMaxToContentMax: function() {
+ this.maxRow = this.contentMaxRow;
+ this.maxCol = this.contentMaxCol;
+ },
+
+ resetAllMaxVals: function() {
+ this.maxRow = 0;
+ this.maxCol = 0;
+ this.contentMaxRow = 0;
+ this.contentMaxCol = 0;
+ },
+
+ setMaxValsFromScratch: function() {
+ // initialize to 0, since we want to start from scratch
+ this.resetAllMaxVals();
+
+ var self = this;
+ _.each(this.cells, function(cell) {
+ if (cell.val()) {
+ self.setContentMaxRow(cell.row);
+ self.setContentMaxCol(cell.col);
+ }
+ });
+
+ this.resetMaxToContentMax();
+ },
+
+ setMaxVals: function(cell) {
+ var el = $(cell.el);
+ var val = cell.val();
+
+ // cell is nonempty
+ if (val) {
+ // only nonempty cell can be used to set content max values
+ // unless (see case below)
+ this.setContentMaxRow(cell.row);
+ this.setContentMaxCol(cell.col);
+
+ // cell is empty
+ } else {
+ // reset the contents of the cell when it's just spaces
+ cell.clearVal();
+
+ // if it was the cell responsible for a content max val(s),
+ // we need to find the new content max val(s)...
+ if (this.contentMaxRow === cell.row ||
+ this.contentMaxCol === cell.col) {
+
+ this.setMaxValsFromScratch();
+ }
+ }
+
+ // both nonempty and empty cells can set absolute max values
+ this.setMaxRow(cell.row);
+ this.setMaxCol(cell.col);
+ },
+
+ // position matrix brackets based on bounds
+ positionBrackets: function() {
+
+ var cell = $(this.cells[0].el);
+ var bracketWidth = this.bracketEls[0].width();
+
+ var rows = this.maxRow + 1;
+ var cols = this.maxCol + 1;
+
+ var height = cell.outerHeight(true) * rows;
+ var marginLeft = cell.outerWidth(true) * cols - bracketWidth;
+
+ _.each(this.bracketEls, function($el) {
+ $el.css({
+ "height": height
+ });
+ });
+
+ // right bracket
+ this.bracketEls[1].css({
+ "margin-left": marginLeft
+ });
+ },
+
+ render: function() {
+ this.positionBrackets();
+ }
+ }
+});
+
+$(Khan).on("newProblem", function() {
+ KhanUtil.matrixInput.init();
+});
+
+$(Khan).on("showGuess", function() {
+ KhanUtil.matrixInput.setMaxValsFromScratch();
+ KhanUtil.matrixInput.render();
+});
View
231 utils/matrix.js
@@ -13,6 +13,10 @@ $.extend(KhanUtil, {
}
},
+ matrixCopy: function(mat) {
+ return jQuery.extend(true, [], mat);
+ },
+
/**
* Apply the given function to each element of the given matrix and return
* the resulting matrix.
@@ -160,15 +164,18 @@ $.extend(KhanUtil, {
// add matrix properties to a 2d matrix
// currently only rows and columns
- makeMatrix: function(m) {
- m.r = m.length;
- m.c = m[0].length;
+ makeMatrix: function(mat) {
+ mat.r = mat.length;
+ mat.c = mat[0].length;
- return m;
+ return mat;
},
// multiply two matrices
matrixMult: function(a, b) {
+ a = KhanUtil.makeMatrix(a);
+ b = KhanUtil.makeMatrix(b);
+
var c = [];
// create the new matrix
_.times(a.r, function() {
@@ -190,6 +197,219 @@ $.extend(KhanUtil, {
return KhanUtil.makeMatrix(c);
},
+ /**
+ * Find the transpose of a matrix.
+ *
+ * @param m {result of makeMatrix} the matrix
+ */
+ matrixTranspose: function(mat) {
+ mat = KhanUtil.makeMatrix(mat);
+
+ var r = mat.c;
+ var c = mat.r;
+
+ if (!r || !c) {
+ return undefined;
+ }
+
+ var matT = [];
+
+ _.times(r, function(i) {
+ var row = [];
+ _.times(c, function(j) {
+ row.push(mat[j][i]);
+ });
+ matT.push(row);
+ });
+
+ return KhanUtil.makeMatrix(matT);
+ },
+
+ /**
+ * Find the determinant of a matrix.
+ *
+ * Note: Only works for 2x2 and 3x3 matrices.
+ *
+ * @param m {result of makeMatrix} the matrix
+ */
+ matrixDet: function(mat) {
+ mat = KhanUtil.makeMatrix(mat);
+
+ // determinant is only defined for a square matrix
+ if (mat.r !== mat.c) {
+ return undefined;
+ }
+
+ var a, b, c, d, e, f, g, h, k, det;
+
+ // 2x2 case
+ // [[a, b], [c, d]]
+ if (mat.r === 2) {
+
+ a = mat[0][0];
+ b = mat[0][1];
+ c = mat[1][0];
+ d = mat[1][1];
+
+ det = a*d - b*c;
+
+ // 3x3 case
+ // [[a, b, c], [d, e, f], [g, h, k]]
+ } else if (mat.r === 3) {
+
+ a = mat[0][0];
+ b = mat[0][1];
+ c = mat[0][2];
+ d = mat[1][0];
+ e = mat[1][1];
+ f = mat[1][2];
+ g = mat[2][0];
+ h = mat[2][1];
+ k = mat[2][2];
+
+ det = a*(e*k - f*h) - b*(k*d - f*g) + c*(d*h - e*g);
+ }
+
+ return det;
+ },
+
+ /**
+ * Find the adjugate of a matrix.
+ *
+ * Note: Only works for 2x2 and 3x3 matrices.
+ *
+ * @param m {result of makeMatrix} the matrix
+ */
+ matrixAdj: function(mat) {
+ mat = KhanUtil.makeMatrix(mat);
+
+ var a, b, c, d, e, f, g, h, k;
+ var adj;
+
+ // 2x2 case
+ // [[a, b], [c, d]]
+ if (mat.r === 2) {
+
+ a = mat[0][0];
+ b = mat[0][1];
+ c = mat[1][0];
+ d = mat[1][1];
+
+ adj = [[d, -b], [-c, a]];
+
+ // 3x3 case
+ // [[a, b, c], [d, e, f], [g, h, k]]
+ } else if (mat.r === 3) {
+
+ a = mat[0][0];
+ b = mat[0][1];
+ c = mat[0][2];
+ d = mat[1][0];
+ e = mat[1][1];
+ f = mat[1][2];
+ g = mat[2][0];
+ h = mat[2][1];
+ k = mat[2][2];
+
+ var A = (e*k - f*h);
+ var B = -(d*k - f*g);
+ var C = (d*h - e*g);
+ var D = -(b*k - c*h);
+ var E = (a*k - c*g);
+ var F = -(a*h - b*g);
+ var G = (b*f - c*e);
+ var H = -(a*f - c*d);
+ var K = (a*e - b*d);
+
+ adj = [[A, D, G], [B, E, H], [C, F, K]];
+ }
+
+ if (adj) {
+ adj = KhanUtil.makeMatrix(adj);
+ }
+
+ return adj;
+ },
+
+ /**
+ * Find the inverse of a matrix.
+ *
+ * Note: Only works for 2x2 and 3x3 matrices.
+ *
+ * @param m {result of makeMatrix} the matrix
+ * @param precision {int} number of decimal places to round to (optional)
+ */
+ matrixInverse: function(mat, precision) {
+ var det = KhanUtil.matrixDet(mat);
+
+ // if determinant is undefined or 0, inverse does not exist
+ if (!det) {
+ return undefined;
+ }
+
+ var adj = KhanUtil.matrixAdj(mat);
+
+ if (!adj) {
+ return undefined;
+ }
+
+ var inv = KhanUtil.deepZipWith(2, function(val) {
+ val = val / det;
+ if (precision) {
+ val = KhanUtil.roundTo(precision, val);
+ }
+ return val;
+ }, adj);
+
+ inv = KhanUtil.makeMatrix(inv);
+
+ return inv;
+ },
+
+ /**
+ * Pad (or crop) the given matrix with the given padding value (`padval`)
+ * until it is of dimensions `rows` x `cols`
+ * @param {result of makeMatrix} m
+ * @param {int} rows
+ * @param {int} cols
+ * @param {anything} padVal [defaults to "" if not specified]
+ * @return {result of makeMatrix}
+ */
+ matrixPad: function(mat, rows, cols, padVal) {
+ mat = KhanUtil.makeMatrix(mat);
+ matP = KhanUtil.matrixCopy(mat);
+
+ finalCols = Math.max(cols, mat.c);
+
+ if (padVal === undefined) {
+ padVal = "";
+ }
+
+ // first add padding to the columns
+ var dcols = cols - matP.c;
+ if (dcols > 0) {
+ _.times(matP.r, function(i) {
+ _.times(dcols, function() {
+ matP[i].push(padVal);
+ });
+ });
+ }
+
+ // make new rows and fill with padding
+ var drows = rows - matP.r;
+ if (drows > 0) {
+ _.times(drows, function() {
+ var row = [];
+ _.times(finalCols, function() {
+ row.push(padVal);
+ });
+ matP.push(row);
+ });
+ }
+
+ return KhanUtil.makeMatrix(matP);
+ },
+
// convert an array to a column matrix
arrayToColumn: function(arr) {
var col = [];
@@ -223,4 +443,5 @@ $.extend(KhanUtil, {
vectorDot: function(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
-});
+
+});
View
34 utils/tmpl.js
@@ -101,7 +101,41 @@ $.tmpl = {
"data-unwrap": function(elem) {
return $(elem).contents();
+ },
+
+ "data-video-hint": function(elem) {
+ var youtubeIds = $(elem).data("youtube-id");
+ if (!youtubeIds) {
+ return;
+ }
+
+ youtubeIds = youtubeIds.split(/,\s*/);
+
+ var author = $(elem).data("video-hint-author") || "Sal";
+ var msg = "Watch " + author +
+ " work through a very similar problem:";
+ var preface = $("<p>").text(msg);
+
+ var wrapper = $("<div>", { "class": "video-hint" });
+ wrapper.append(preface);
+
+ _.each(youtubeIds, function(youtubeId) {
+ var href = "http://www.khanacademy.org/embed_video?v=" +
+ youtubeId;
+ var iframe = $("<iframe>").attr({
+ "frameborder": "0",
+ "scrolling": "no",
+ "width": "100%",
+ "height": "360px",
+ "src": href
+ });
+
+ wrapper.append(iframe);
+ });
+
+ return wrapper;
}
+
},
// Processors that act based on tag names
Please sign in to comment.
Something went wrong with that request. Please try again.