1-- Parallelograms, diagonal bisection, and Varignon's midpoint theorem.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.Parallelogram8import Lines910namespace Euclidean11exportopen Euclidean1213-- The affine parallelogram identity, allowing degenerate configurations.14-- Opposite directed sides agree. Nonzero-side hypotheses are supplied when15-- asserting ParallelSegments; coincident supporting lines remain allowed.16predicate Parallelogram (a b c d : Set) := vector(a, b) = vector(d, c)1718theorem parallelogram.rotate (a b c d : Point)19requires shape : Parallelogram(a, b, c, d)20shows Parallelogram(b, c, d, a)21proof22unfold Parallelogram at shape23obtain⟨horizontal, vertical⟩:= vector.equal_iff.forward with shape24have other : x(c) - x(b) = x(d) - x(a) ∧25 y(c) - y(b) = y(d) - y(a)26constructor27 . linear_combination -horizontal28 . linear_combination -vertical29unfold Parallelogram30exact vector.equal_iff.backward with other3132theorem parallelogram.opposite_lengths (a b c d : Point)33requires shape : Parallelogram(a, b, c, d)34shows Euclidean.distanceSquared(a, b) = Euclidean.distanceSquared(d, c) ∧35 Euclidean.distanceSquared(b, c) = Euclidean.distanceSquared(a, d)36proof37have other := parallelogram.rotate with*38unfold Parallelogram at shape39unfold Parallelogram at other40constructor41 . unfold Euclidean.distanceSquared42cc43 . unfold Euclidean.distanceSquared44cc4546theorem parallelogram.parallel (a b c d : Point)47requires shape : Parallelogram(a, b, c, d)48requires first : a ≠ b49requires second : d ≠ c50shows ParallelSegments(a, b, d, c)51proof52unfold Parallelogram at shape53obtain⟨horizontal, vertical⟩:= vector.equal_iff.forward with shape54have cross : directionCross(a, b, d, c) =055simp [directionCross]56ring57unfold ParallelSegments58refine⟨first, second, cross⟩5960-- Diagonals that bisect one another give the same affine parallelogram.61theorem parallelogram.of_bisected_diagonals (a b c d m : Point)62requires first : Midpoint(m, a, c)63requires second : Midpoint(m, b, d)64shows Parallelogram(a, b, c, d)65proof66rcases first with⟨firstX, firstY⟩67rcases second with⟨secondX, secondY⟩68have components : x(b) - x(a) = x(c) - x(d) ∧69 y(b) - y(a) = y(c) - y(d)70constructor71 . linear_combination secondX - firstX72 . linear_combination secondY - firstY73unfold Parallelogram74exact vector.equal_iff.backward with components7576theorem parallelogram.bisects (a b c d m : Point)77requires shape : Parallelogram(a, b, c, d)78requires first : Midpoint(m, a, c)79shows Midpoint(m, b, d)80proof81unfold Parallelogram at shape82obtain⟨horizontal, vertical⟩:= vector.equal_iff.forward with shape83rcases first with⟨firstX, firstY⟩84constructor85 . linear_combination firstX + horizontal86 . linear_combination firstY + vertical8788theorem parallelogram.diagonals (a b c d : Point)89requires shape : Parallelogram(a, b, c, d)90shows∃ m, Point(m) ∧ Midpoint(m, a, c) ∧ Midpoint(m, b, d)91proof92have point := midpoint.point at a, c with*93have first := midpoint.correct at a, c with*94have second := parallelogram.bisects with*95refine⟨midpoint(a, c), point, first, second⟩9697theorem parallelogram.iff_diagonals (a b c d : Point)98shows Parallelogram(a, b, c, d) ↔99∃ m, Point(m) ∧ Midpoint(m, a, c) ∧ Midpoint(m, b, d)100proof101constructor102 . intro shape103exact parallelogram.diagonals with*104 . intro center105rcases center with⟨m, point, first, second⟩106exact parallelogram.of_bisected_diagonals with*107108-- The two pairs of side midpoints are midsegments of triangles sharing AC.109-- Both directed midsegments are half of that same directed diagonal.110theorem varignon (a b c d m n p q : Point)111requires first : Midpoint(m, a, b)112requires second : Midpoint(n, b, c)113requires third : Midpoint(p, c, d)114requires fourth : Midpoint(q, d, a)115shows Parallelogram(m, n, p, q)116proof117have firstReversed := midpoint.symmetric at a, b, m with*118have thirdReversed := midpoint.symmetric at c, d, p with*119unfold Parallelogram120exact midsegment.equal_vectors with*121122-- Nonzero original diagonals give nonzero sides of the midpoint figure.123-- No convexity or simplicity assumption is needed for this affine result.124theorem varignon.parallel (a b c d m n p q : Point)125requires first : Midpoint(m, a, b)126requires second : Midpoint(n, b, c)127requires third : Midpoint(p, c, d)128requires fourth : Midpoint(q, d, a)129requires firstDiagonal : a ≠ c130requires secondDiagonal : b ≠ d131shows ParallelSegments(m, n, q, p) ∧ ParallelSegments(n, p, m, q)132proof133have shape := varignon at a, b, c, d, m, n, p, q with*134have rotated := parallelogram.rotate at m, n, p, q with*135have firstReversed := midpoint.symmetric at a, b, m with*136have secondReversed := midpoint.symmetric at b, c, n with*137have thirdReversed := midpoint.symmetric at c, d, p with*138have fourthReversed := midpoint.symmetric at d, a, q with*139have mn := midsegment.distinct at a, c, b, m, n with*140have qp := midsegment.distinct at a, c, d, q, p with*141have np := midsegment.distinct at b, d, c, n, p with*142have mq := midsegment.distinct at b, d, a, m, q with*143have opposite := parallelogram.parallel at m, n, p, q with*144have other := parallelogram.parallel at n, p, q, m with*145refine⟨opposite, other⟩146147theorem varignon.constructed (a b c d : Point)148shows Parallelogram(midpoint(a, b), midpoint(b, c),149 midpoint(c, d), midpoint(d, a))150proof151have mPoint := midpoint.point at a, b with*152have nPoint := midpoint.point at b, c with*153have pPoint := midpoint.point at c, d with*154have qPoint := midpoint.point at d, a with*155have first := midpoint.correct at a, b with*156have second := midpoint.correct at b, c with*157have third := midpoint.correct at c, d with*158have fourth := midpoint.correct at d, a with*159exact varignon at a, b, c, d, midpoint(a, b), midpoint(b, c), midpoint(c, d), midpoint(d, a) with*160161end Euclidean162