1-- Points and vectors in the Cartesian plane over the Dedekind reals.2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.Geometry.Plane8import Pythagoras9import Real.Squares1011namespace Euclidean12exportopen Euclidean1314-- Points are ordered pairs of reals.15predicate Point (p : Set) :=∃ a ∈ ℝ, ∃ b ∈ ℝ, p = (a, b)1617defunique coordinateX (p : Set) (a ∈ ℝ) :=∃ b ∈ ℝ, p = (a, b)18requires point : Point(p)19proof20unfold Point at point21exact point2223uniqueness24intros a aMember first c cMember second25obtain⟨b, bMember, firstPair⟩:= first26obtain⟨d, dMember, secondPair⟩:= second27have same : (a, b) = (c, d)28cc29have coordinates := orderedPair.injective at a, b, c, d with same30tauto3132def x (p : Point) : Real:= coordinateX(p)3334defunique coordinateY (p : Set) (b ∈ ℝ) := p = (x(p), b)35requires point : Point(p)36proof37have selected := coordinateX.selected at p with point38rcases selected with⟨realX, b, realB, pair⟩39witness b40constructor41 . exact realB42 . unfold x43exact pair4445uniqueness46intros b bMember first d dMember second47have same : (x(p), b) = (x(p), d)48cc49have coordinates := orderedPair.injective at x(p), b, x(p), d with same50tauto5152def y (p : Point) : Real:= coordinateY(p)5354theorem x.real (p : Point)55showsReal(x(p))56proof57obtain⟨realX, rest⟩:= coordinateX.selected at p withassumption58unfold x59exact realX6061theorem y.real (p : Point)62showsReal(y(p))63proof64obtain⟨realY, pair⟩:= coordinateY.selected at p withassumption65unfold y66exact realY6768theorem coordinates (p : Point)69shows p = (x(p), y(p))70proof71obtain⟨realY, pair⟩:= coordinateY.selected at p withassumption72simp [y]7374theorem pair.point (a b : Real)75shows Point((a, b))76proof77unfold Point78have ha : a ∈ ℝ bysimp [Real]79have hb : b ∈ ℝ bysimp [Real]80refine⟨a, ha, b, hb, rfl⟩8182theorem x.pair (a b : Real)83shows x((a, b)) = a84proof85have point := pair.point at a, b with*86have coords := coordinates with point87have equal := orderedPair.injective with coords88simp8990theorem y.pair (a b : Real)91shows y((a, b)) = b92proof93have point := pair.point at a, b with*94have coords := coordinates with point95have equal := orderedPair.injective with coords96simp9798theorem point.ext (p q : Point)99requires horizontal : x(p) = x(q)100requires vertical : y(p) = y(q)101shows p = q102proof103have pCoords := coordinates at p withassumption104have qCoords := coordinates at q withassumption105cc106107-- A displacement is another pair of real coordinates.108def vector (a b : Set) : Set:= (x(b) - x(a), y(b) - y(a))109def dot (u v : Point) : Real:= x(u) * x(v) + y(u) * y(v)110def normSquared (u : Point) : Real:= dot(u, u)111def distanceSquared (a b : Point) : Real:= normSquared(vector(a, b))112113theorem vector.point (a b : Point)114shows Point(vector(a, b))115proof116have ax := x.real at a withassumption117have ay := y.real at a withassumption118have bx := x.real at b withassumption119have byReal := y.real at b withassumption120have horizontal := realSubValue.real with bx, ax121have vertical := realSubValue.real with byReal, ay122unfold vector123exact pair.point with horizontal, vertical124125theorem vector.x (a b : Point)126shows x(vector(a, b)) = x(b) - x(a)127proof128have ax := x.real at a withassumption129have ay := y.real at a withassumption130have bx := x.real at b withassumption131have byReal := y.real at b withassumption132have horizontal := realSubValue.real with bx, ax133have vertical := realSubValue.real with byReal, ay134unfold vector135exact x.pair with horizontal, vertical136137theorem vector.y (a b : Point)138shows y(vector(a, b)) = y(b) - y(a)139proof140have ax := x.real at a withassumption141have ay := y.real at a withassumption142have bx := x.real at b withassumption143have byReal := y.real at b withassumption144have horizontal := realSubValue.real with bx, ax145have vertical := realSubValue.real with byReal, ay146unfold vector147exact y.pair with horizontal, vertical148149-- Dot products of two directed segments in their endpoint coordinates.150theorem vector.dot_coordinates (a b c d : Point)151shows dot(vector(a, b), vector(c, d)) =152 (x(b) - x(a)) * (x(d) - x(c)) + (y(b) - y(a)) * (y(d) - y(c))153proof154have firstX := vector.x at a, b with*155have firstY := vector.y at a, b with*156have secondX := vector.x at c, d with*157have secondY := vector.y at c, d with*158unfold dot159cc160161-- Equality of displacements can be used without exposing ordered-pair encodings.162theorem vector.equal_iff (a b c d : Set)163shows vector(a, b) = vector(c, d) ↔164 x(b) - x(a) = x(d) - x(c) ∧ y(b) - y(a) = y(d) - y(c)165proof166constructor167 . intro equal168unfold vector at equal169exact orderedPair.injective with equal170 . intro components171rcases components with⟨horizontal, vertical⟩172unfold vector173cc174175theorem dot.real (u v : Point)176showsReal(dot(u, v))177proof178have ux := x.real at u withassumption179have uy := y.real at u withassumption180have vx := x.real at v withassumption181have vy := y.real at v withassumption182have horizontal := realMulValue.real with ux, vx183have vertical := realMulValue.real with uy, vy184unfold dot185exact realAddValue.real with horizontal, vertical186187theorem normSquared.real (u : Point)188showsReal(normSquared(u))189proof190unfold normSquared191exact dot.real with*192193theorem distanceSquared.real (a b : Point)194showsReal(distanceSquared(a, b))195proof196have displacement := vector.point at a, b with*197unfold distanceSquared198exact normSquared.real with displacement199200theorem distanceSquared.coordinates (a b : Point)201shows distanceSquared(a, b) =202 (x(b) - x(a)) * (x(b) - x(a)) + (y(b) - y(a)) * (y(b) - y(a))203proof204unfold distanceSquared205unfold normSquared206unfold dot207have coordinateRule1 := vector.x at a, b with*208rw coordinateRule1209have coordinateRule2 := vector.y at a, b with*210rw coordinateRule2211rfl212213theorem normSquared.nonnegative (u : Point)214shows0≤ normSquared(u)215proof216have ux := x.real withassumption217have uy := y.real withassumption218unfold normSquared219unfold dot220exact realAddValue.sum_squares_nonnegative with ux, uy221222theorem distanceSquared.symmetric (a b : Point)223shows distanceSquared(a, b) = distanceSquared(b, a)224proof225have coordinateRule3 := distanceSquared.coordinates at a, b with*226rw coordinateRule3227have coordinateRule4 := distanceSquared.coordinates at b, a with*228rw coordinateRule4229ring230231theorem distanceSquared.nonnegative (a b : Point)232shows0≤ distanceSquared(a, b)233proof234have displacement := vector.point at a, b with*235unfold distanceSquared236exact normSquared.nonnegative with displacement237238theorem distanceSquared.zero_iff (a b : Point)239shows distanceSquared(a, b) =0↔ a = b240proof241have ax := x.real at a withassumption242have ay := y.real at a withassumption243have bx := x.real at b withassumption244have byReal := y.real at b withassumption245have dx := realSubValue.real with bx, ax246have dy := realSubValue.real with byReal, ay247have xx := realMulValue.square_nonnegative with dx248have yy := realMulValue.square_nonnegative with dy249have formula := distanceSquared.coordinates at a, b with*250constructor251 . intro zeroDistance252rw formula at zeroDistance253have squareX := realAddValue.nonnegative_eq_zero with xx, yy, zeroDistance254have reversed : (y(b) - y(a)) * (y(b) - y(a)) + (x(b) - x(a)) * (x(b) - x(a)) =0byring255have squareY := realAddValue.nonnegative_eq_zero with yy, xx, reversed256have zeroX := realMulValue.square_eq_zero_iff.forward with squareX257have zeroY := realMulValue.square_eq_zero_iff.forward with squareY258have equalX : x(a) = x(b) bylinear_combination -zeroX259have equalY : y(a) = y(b) bylinear_combination -zeroY260exact point.ext with*261 . intro equal262rw equal263have coordinateRule5 := distanceSquared.coordinates at b, b with*264rw coordinateRule5265ring266267theorem distanceSquared.positive (a b : Point)268requires distinct : a ≠ b269shows0 < distanceSquared(a, b)270proof271have nonnegative := distanceSquared.nonnegative at a, b with*272have nonzero : distanceSquared(a, b) ≠0273intro zeroDistance274have equal := distanceSquared.zero_iff.forward with*275exact distinct with equal276exactReal.positive_of_nonnegative_of_ne_zero with nonnegative, nonzero277278-- The middle point is the vertex of the angle.279def angleDot (a b c : Point) : Real:= dot(vector(b, a), vector(b, c))280281predicate RightAngle (a b c : Set) := angleDot(a, b, c) =0282283theorem angleDot.real (a b c : Point)284showsReal(angleDot(a, b, c))285proof286have first := vector.point at b, a with*287have second := vector.point at b, c with*288unfold angleDot289exact dot.real with first, second290291theorem angleDot.coordinates (a b c : Point)292shows angleDot(a, b, c) =293 (x(a) - x(b)) * (x(c) - x(b)) + (y(a) - y(b)) * (y(c) - y(b))294proof295unfold angleDot296unfold dot297have coordinateRule6 := vector.x at b, a with*298rw coordinateRule6299have coordinateRule7 := vector.x at b, c with*300rw coordinateRule7301have coordinateRule8 := vector.y at b, a with*302rw coordinateRule8303have coordinateRule9 := vector.y at b, c with*304rw coordinateRule9305rfl306307-- The cosine-law identity, stated without division or square roots.308theorem cosine_identity (a b c : Point)309shows distanceSquared(a, c) + angleDot(a, b, c) + angleDot(a, b, c) =310 distanceSquared(a, b) + distanceSquared(b, c)311proof312have coordinateRule10 := distanceSquared.coordinates at a, c with*313rw coordinateRule10314have coordinateRule11 := distanceSquared.coordinates at a, b with*315rw coordinateRule11316have coordinateRule12 := distanceSquared.coordinates at b, c with*317rw coordinateRule12318have coordinateRule13 := angleDot.coordinates at a, b, c with*319rw coordinateRule13320ring321322theorem pythagoras (a b c : Point)323requiresright : RightAngle(a, b, c)324shows distanceSquared(a, c) = distanceSquared(a, b) + distanceSquared(b, c)325proof326have identity := cosine_identity at a, b, c with*327unfold RightAngle atright328linear_combination identity - (2:R) *right329330end Euclidean331