#set document(title: "6.1 Projection onto a Plane", author: "XYZ Homework") #set page(width: 8.5in, height: auto, margin: 1in) #import "@preview/cetz:0.5.2" #set text(font: ("STIX Two Text", "Libertinus Serif", "New Computer Modern"), size: 10.5pt, lang: "en") #show math.equation: set text(font: ("STIX Two Math", "New Computer Modern Math")) #set par(justify: true, leading: 0.62em, spacing: 0.9em) #set enum(spacing: 1.1em) // room between list items so tall inline fractions don't collide #set list(spacing: 1.1em) #set table(stroke: 0.5pt + rgb("#c7ccd3")) #let BLUE = rgb("#183B6F") // brand navy — section bars + example/solution labels (white on navy 11.09:1) #let ORANGE = rgb("#A94509") // brand primary-700 — AA-safe deep orange for TEXT (5.93:1 on white; raw brand #F37021 is 2.94:1 and must never carry text) #let RED = rgb("#DC2626") // brand error-600 #let GREEN = rgb("#059669") // brand success-600 (decoration only; small green text uses green-text #007942) #show heading.where(level: 1): it => block(width: 100%, above: 0pt, below: 16pt, fill: gradient.linear(BLUE, rgb("#2C5AA0")), inset: (x: 14pt, y: 12pt), radius: 3pt, text(fill: white, weight: "bold", size: 19pt, it.body)) #show heading.where(level: 2): it => block(width: 100%, above: 18pt, below: 10pt, fill: BLUE, inset: (x: 10pt, y: 6pt), radius: 2pt, text(fill: white, weight: "bold", size: 12pt, it.body)) #show heading.where(level: 3): it => text(fill: ORANGE, weight: "bold", size: 12.5pt, it.body) #show heading.where(level: 4): it => text(fill: BLUE, weight: "bold", size: 10.5pt, it.body) #let examplebox(label, title, body) = block(width: 100%, breakable: true, fill: rgb("#EFF1F5"), stroke: 0.5pt + rgb("#CFDDF0"), radius: 4pt, inset: 10pt, above: 12pt, below: 12pt)[ #block(below: 6pt)[#box(fill: BLUE, inset: (x: 6pt, y: 2pt), radius: 2pt, text(fill: white, weight: "bold", size: 8.5pt, label)) #h(0.4em) #strong[#title]] #body] // rail = decorative left rule (raw brand token); labelcolor = AA-safe label text shade #let notebox(label, rail, labelcolor, tint, body) = block(width: 100%, breakable: true, fill: tint, stroke: (left: 3pt + rail), inset: (left: 10pt, rest: 8pt), radius: (right: 4pt), above: 11pt, below: 11pt)[ #text(fill: labelcolor, weight: "bold", size: 7.5pt, tracking: 0.5pt)[#upper(label)] #linebreak() #body] #let solutionbox(body) = block(above: 4pt, below: 8pt)[ #text(fill: BLUE, weight: "bold", size: 8.5pt)[Solution] #linebreak() #body] #let figph(msg) = block(width: 100%, height: 60pt, fill: rgb("#f6f7f9"), stroke: (paint: rgb("#c7ccd3"), dash: "dashed"), radius: 4pt, inset: 10pt)[ #align(center + horizon, text(fill: rgb("#889"), style: "italic", size: 9pt, msg))] // Standardize inlined figure sizes: measure the natural CeTZ canvas, then scale to a // consistent envelope (aspect-aware; see build_typst.py FIG_* constants). Unlike the // print preamble, dimensions are FLOORED: in an editor a user can trim a figure to a // degenerate 1-D shape (a bare line), and w/h or tw/w would then divide by zero. #let _STD_W = 3.5 #let _WIDE_W = 5.6 #let _MAX_H = 3.4 #let _ASPECT_WIDE = 2.2 #let _UPSCALE_MAX = 1.15 #let stdfig(body) = context { let m = measure(body) let w = calc.max(m.width / 1in, 0.01) let h = calc.max(m.height / 1in, 0.01) let tw = if w / h > _ASPECT_WIDE { _WIDE_W } else { _STD_W } let s = calc.min(tw / w, _MAX_H / h, _UPSCALE_MAX) align(center, box(scale(x: s * 100%, y: s * 100%, reflow: true, body))) } #show figure: set block(breakable: false) #set figure(gap: 8pt) #show figure.caption: set text(size: 8.5pt, fill: rgb("#555")) == 6.1#h(0.6em)Projection onto a Plane #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Objectives] - Compute the orthogonal projection of a vector onto a plane through the origin. - Verify optimality: the projection is the unique closest point, certified by a perpendicular error. - Split a vector into a piece in the plane plus a piece along the normal. ] Here is a new kind of question. The plane #math.equation(block: false, alt: "z equals 0.4 x plus 0.2 y")[$z = 0.4 x + 0.2 y$] is a subspace of #math.equation(block: false, alt: "ℝ cubed")[$ℝ^(3)$] — flat, through the origin, closed under the usual operations. The vector #math.equation(block: false, alt: "𝐛 equals open parenthesis 1 , 1 , 3 close parenthesis")[$𝐛 = ( 1 , 1 , 3 )$] is #emph[not] on it: the plane above the point #math.equation(block: false, alt: "open parenthesis 1 , 1 close parenthesis")[$( 1 , 1 )$] sits at height #math.equation(block: false, alt: "0.4 plus 0.2 equals 0.6")[$0.4 + 0.2 = 0.6$], far below #math.equation(block: false, alt: "3")[$3$]. Chapter 2 would stop there — not reachable — but the useful question is quantitative: which point #emph[of the plane] is closest to #math.equation(block: false, alt: "𝐛")[$𝐛$]? The answer is found by dropping a perpendicular from #math.equation(block: false, alt: "𝐛")[$𝐛$] onto the plane. The figure shows the whole construction: the dark point #math.equation(block: false, alt: "𝐛")[$𝐛$] floating above the plane, the dashed red segment falling from it along the plane's normal direction, and the blue point #math.equation(block: false, alt: "open parenthesis 1.8 , 1.4 , 1 close parenthesis")[$( 1.8 , 1.4 , 1 )$] where it lands — the #strong[orthogonal projection] of #math.equation(block: false, alt: "𝐛")[$𝐛$]. Two solid segments from the origin trace #math.equation(block: false, alt: "𝐛")[$𝐛$] itself (gray) and its projection (blue). {"camera":{"fov":50,"position":\[6.5,4,4\],"projection":"perspective","target":\[0.8,0.8,1\]},"grid":{"axisColors":{"x":"\#ef4444","y":"\#22c55e","z":"\#3b82f6"},"divisions":10,"gridColor":"\#e5e7eb","showAxes":true,"showLabels":true,"size":10,"visible":true},"id":"510bb92f-3433-412a-8751-e3206e984d0a","metadata":{"alt\_text":"A semi-transparent tilted plane through the origin with a dark point floating above it. A dashed red segment drops from the point straight down onto the plane along the plane's normal direction, ending at a blue point on the plane. Two solid segments from the origin show the original vector and its shadow in the plane. There are no sliders.","created\_at":"2026-08-01T00:00:00.000Z","description":"Book scene: orthogonal projection of b = (1, 1, 3) onto the plane z = 0.4x + 0.2y. The projected point is (1.8, 1.4, 1), the dashed segment (1 + 0.8t, 1 + 0.4t, 3 - 2t) runs along the normal (0.4, 0.2, -1) scaled by 2, and origin segments trace b and its projection.","tags":\["book","linear-algebra","projection","orthogonality"\],"updated\_at":"2026-08-01T00:00:00.000Z"},"objects":\[{"expression":"0.4\*x + 0.2\*y","id":"1570280c-a53c-4a16-8a39-b9f6fb364e85","kind":"explicit-surface","label":{"text":"subspace: z = 0.4x + 0.2y","visible":true},"resolution":32,"style":{"colormap":"viridis","doubleSided":true,"opacity":0.55,"wireframe":false,"wireframeColor":"\#000000"},"visible":true,"xDomain":\[-3,3\],"yDomain":\[-3,3\]},{"color":"\#111827","id":"be74bbe0-dafa-4b9c-832e-3eb2cd3aa39e","kind":"point","label":{"text":"b = (1, 1, 3)","visible":true},"radius":0.1,"visible":true,"x":1,"y":1,"z":3},{"color":"\#3b82f6","id":"4c5188c9-d6d8-4eda-a0e0-0b78b87445db","kind":"point","label":{"text":"projection of b: (1.8, 1.4, 1)","visible":true},"radius":0.1,"visible":true,"x":1.8,"y":1.4,"z":1},{"id":"a815da60-135b-4ade-a4e5-45faca167c4b","kind":"parametric-curve","label":{"text":"perpendicular drop from b","visible":true},"samples":50,"style":{"color":"\#ef4444","dash":\[5,4\],"lineWidth":3},"tDomain":\[0,1\],"visible":true,"xExpr":"1 + 0.8\*t","yExpr":"1 + 0.4\*t","zExpr":"3 - 2\*t"},{"id":"a1d2ce0c-cdde-4a37-86e7-f125534279b0","kind":"parametric-curve","label":{"text":"the vector b","visible":true},"samples":50,"style":{"color":"\#6b7280","dash":\[\],"lineWidth":2},"tDomain":\[0,1\],"visible":true,"xExpr":"t","yExpr":"t","zExpr":"3\*t"},{"id":"c9ea0925-1045-40ef-aff1-4a9dcf6c2ea9","kind":"parametric-curve","label":{"text":"the projection vector","visible":true},"samples":50,"style":{"color":"\#3b82f6","dash":\[\],"lineWidth":3},"tDomain":\[0,1\],"visible":true,"xExpr":"1.8\*t","yExpr":"1.4\*t","zExpr":"t"}\],"title":"Projection onto a plane","version":1} The point #math.equation(block: false, alt: "𝐛 equals open parenthesis 1 , 1 , 3 close parenthesis")[$𝐛 = ( 1 , 1 , 3 )$] above the plane #math.equation(block: false, alt: "z equals 0.4 x plus 0.2 y")[$z = 0.4 x + 0.2 y$], with the dashed red perpendicular dropping to its projection #math.equation(block: false, alt: "open parenthesis 1.8 , 1.4 , 1 close parenthesis")[$( 1.8 , 1.4 , 1 )$], marked in blue. The gray and blue segments from the origin are #math.equation(block: false, alt: "𝐛")[$𝐛$] and its projection as vectors. === Explore the figure + Orbit until you view the plane edge-on. The dashed segment meets it at a right angle — not a right angle on your screen from every viewpoint, but a true one in space, visible when the plane degenerates to a line in your view. + A natural first guess for the closest point is "straight down": drop vertically from #math.equation(block: false, alt: "𝐛")[$𝐛$] to #math.equation(block: false, alt: "open parenthesis 1 , 1 , 0.6 close parenthesis")[$( 1 , 1 , 0.6 )$]. That vertical trip has length #math.equation(block: false, alt: "3 minus 0.6 equals 2.4")[$3 − 0.6 = 2.4$]. The dashed route is visibly shorter and lands at a #emph[different] point — closest is measured perpendicular to the plane, not perpendicular to the floor. + Confirm by eye that the blue point actually lies in the plane, and that its coordinates are plausible: #math.equation(block: false, alt: "0.4 open parenthesis 1.8 close parenthesis plus 0.2 open parenthesis 1.4 close parenthesis equals 0.72 plus 0.28 equals 1")[$0.4 ( 1.8 ) + 0.2 ( 1.4 ) = 0.72 + 0.28 = 1$], exactly its height. + Follow the triangle made by the gray segment, the blue segment, and the dashed drop: #math.equation(block: false, alt: "𝐛")[$𝐛$] splits into a piece inside the plane plus a piece perpendicular to it. Nothing overlaps and nothing is missing. === Computing the drop Rewrite the plane as #math.equation(block: false, alt: "0.4 x plus 0.2 y minus z equals 0")[$0.4 x + 0.2 y − z = 0$]; its normal vector is #math.equation(block: false, alt: "𝐧 equals open parenthesis 0.4 , 0.2 , minus 1 close parenthesis")[$𝐧 = ( 0.4 , 0.2 , − 1 )$], and the perpendicular from #math.equation(block: false, alt: "𝐛")[$𝐛$] must travel along #math.equation(block: false, alt: "𝐧")[$𝐧$]. So the projection is #math.equation(block: false, alt: "𝐩 equals 𝐛 minus t 𝐧")[$𝐩 = 𝐛 − t 𝐧$] for the value of #math.equation(block: false, alt: "t")[$t$] that lands on the plane, which works out to #math.equation(block: false, alt: "t equals open parenthesis 𝐛 times 𝐧 close parenthesis / open parenthesis 𝐧 times 𝐧 close parenthesis")[$t = ( 𝐛 · 𝐧 ) / ( 𝐧 · 𝐧 )$]. Here #math.equation(block: false, alt: "𝐛 times 𝐧 equals 0.4 plus 0.2 minus 3 equals minus 2.4")[$𝐛 · 𝐧 = 0.4 + 0.2 − 3 = − 2.4$] and #math.equation(block: false, alt: "𝐧 times 𝐧 equals 0.16 plus 0.04 plus 1 equals 1.2")[$𝐧 · 𝐧 = 0.16 + 0.04 + 1 = 1.2$], so #math.equation(block: false, alt: "t equals minus 2")[$t = − 2$] and #math.equation(block: true, alt: "𝐩 equals 𝐛 plus 2 𝐧 equals open parenthesis 1 plus 0.8 , 1 plus 0.4 , 3 minus 2 close parenthesis equals open parenthesis 1.8 , 1.4 , 1 close parenthesis")[$𝐩 = 𝐛 + 2 𝐧 = ( 1 + 0.8 , #h(0.278em) 1 + 0.4 , #h(0.278em) 3 − 2 ) = ( 1.8 , #h(0.278em) 1.4 , #h(0.278em) 1 )$] The error vector is #math.equation(block: false, alt: "𝐛 minus 𝐩 equals open parenthesis minus 0.8 , minus 0.4 , 2 close parenthesis equals minus 2 𝐧")[$𝐛 − 𝐩 = ( − 0.8 , − 0.4 , 2 ) = − 2 𝐧$]: a pure multiple of the normal, with length #math.equation(block: false, alt: "the square root of 0.64 plus 0.16 plus 4 equals the square root of 4.8 approximately equals 2.19")[$sqrt(0.64 + 0.16 + 4) = sqrt(4.8) ≈ 2.19$] — beating the vertical guess of #math.equation(block: false, alt: "2.4")[$2.4$], as the figure promised. And perpendicularity is what makes #math.equation(block: false, alt: "𝐩")[$𝐩$] #emph[provably] the winner: for any other point #math.equation(block: false, alt: "𝐪")[$𝐪$] of the plane, the segment from #math.equation(block: false, alt: "𝐪")[$𝐪$] to #math.equation(block: false, alt: "𝐩")[$𝐩$] lies in the plane, at right angles to #math.equation(block: false, alt: "𝐛 minus 𝐩")[$𝐛 − 𝐩$], so Pythagoras gives #math.equation(block: false, alt: "| 𝐛 minus 𝐪 | squared equals | 𝐛 minus 𝐩 | squared plus | 𝐩 minus 𝐪 | squared")[$| 𝐛 − 𝐪 |^(2) = | 𝐛 − 𝐩 |^(2) + | 𝐩 − 𝐪 |^(2)$], strictly larger. A perpendicular error is not one good option — it is a certificate that no better option exists. #examplebox("Example 1")[Certify the projection][ Verify that #math.equation(block: false, alt: "𝐩 equals open parenthesis 1.8 , 1.4 , 1 close parenthesis")[$𝐩 = ( 1.8 , 1.4 , 1 )$] lies in the plane and that the error #math.equation(block: false, alt: "𝐛 minus 𝐩")[$𝐛 − 𝐩$] is perpendicular to it. In the plane: #math.equation(block: false, alt: "0.4 open parenthesis 1.8 close parenthesis plus 0.2 open parenthesis 1.4 close parenthesis equals 0.72 plus 0.28 equals 1")[$0.4 ( 1.8 ) + 0.2 ( 1.4 ) = 0.72 + 0.28 = 1$], which matches the third coordinate. Perpendicular: the plane is spanned by #math.equation(block: false, alt: "open parenthesis 1 , 0 , 0.4 close parenthesis")[$( 1 , 0 , 0.4 )$] and #math.equation(block: false, alt: "open parenthesis 0 , 1 , 0.2 close parenthesis")[$( 0 , 1 , 0.2 )$] — its points with #math.equation(block: false, alt: "x equals 1 , y equals 0")[$x = 1 , y = 0$] and #math.equation(block: false, alt: "x equals 0 , y equals 1")[$x = 0 , y = 1$] — so it is enough to check the error against both. With #math.equation(block: false, alt: "𝐛 minus 𝐩 equals open parenthesis minus 0.8 , minus 0.4 , 2 close parenthesis")[$𝐛 − 𝐩 = ( − 0.8 , − 0.4 , 2 )$]: first, #math.equation(block: false, alt: "open parenthesis minus 0.8 close parenthesis open parenthesis 1 close parenthesis plus open parenthesis minus 0.4 close parenthesis open parenthesis 0 close parenthesis plus open parenthesis 2 close parenthesis open parenthesis 0.4 close parenthesis equals minus 0.8 plus 0.8 equals 0")[$( − 0.8 ) ( 1 ) + ( − 0.4 ) ( 0 ) + ( 2 ) ( 0.4 ) = − 0.8 + 0.8 = 0$]; second, #math.equation(block: false, alt: "open parenthesis minus 0.8 close parenthesis open parenthesis 0 close parenthesis plus open parenthesis minus 0.4 close parenthesis open parenthesis 1 close parenthesis plus open parenthesis 2 close parenthesis open parenthesis 0.2 close parenthesis equals minus 0.4 plus 0.4 equals 0")[$( − 0.8 ) ( 0 ) + ( − 0.4 ) ( 1 ) + ( 2 ) ( 0.2 ) = − 0.4 + 0.4 = 0$]. Both vanish, so the error is orthogonal to every combination of the spanning vectors — the entire plane. The decomposition #math.equation(block: false, alt: "open parenthesis 1 , 1 , 3 close parenthesis equals open parenthesis 1.8 , 1.4 , 1 close parenthesis plus open parenthesis minus 0.8 , minus 0.4 , 2 close parenthesis")[$( 1 , 1 , 3 ) = ( 1.8 , 1.4 , 1 ) + ( − 0.8 , − 0.4 , 2 )$] splits #math.equation(block: false, alt: "𝐛")[$𝐛$] into plane part plus normal part exactly. ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ Projection answers "how close can a subspace get to this vector?", and its signature is the perpendicular error. Hold on to the certificate idea — when least squares arrives two sections from now, the #emph[same] perpendicularity, transplanted into #math.equation(block: false, alt: "ℝ to the power 7")[$ℝ^(7)$], will be the reason a machine's fit beats every fit you can tune by hand. ]