```------------------------------------------------------------------------
-- The Agda standard library
--
-- Some functional properties are symmetric
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

module Function.Construct.Symmetry where

open import Data.Product using (_,_; swap)
open import Function
open import Level using (Level)
open import Relation.Binary hiding (_⇔_)

private
variable
a b c ℓ₁ ℓ₂ ℓ₃ : Level
A : Set a
B : Set b
C : Set c

------------------------------------------------------------------------
-- Properties

module _ (≈₁ : Rel A ℓ₁) (≈₂ : Rel B ℓ₂)
(f : A → B) {f⁻¹ : B → A}
where

inverseʳ : Inverseˡ ≈₁ ≈₂ f f⁻¹ → Inverseʳ ≈₂ ≈₁ f⁻¹ f
inverseʳ inv = inv

inverseˡ : Inverseʳ ≈₁ ≈₂ f f⁻¹ → Inverseˡ ≈₂ ≈₁ f⁻¹ f
inverseˡ inv = inv

inverseᵇ : Inverseᵇ ≈₁ ≈₂ f f⁻¹ → Inverseᵇ ≈₂ ≈₁ f⁻¹ f
inverseᵇ (invˡ , invʳ) = (invʳ , invˡ)

------------------------------------------------------------------------
-- Structures

module _ {≈₁ : Rel A ℓ₁} {≈₂ : Rel B ℓ₂}
{f : A → B} {f⁻¹ : B → A}
where

isCongruent : IsCongruent ≈₁ ≈₂ f → Congruent ≈₂ ≈₁ f⁻¹ → IsCongruent ≈₂ ≈₁ f⁻¹
isCongruent ic cg = record
{ cong = cg
; isEquivalence₁ = IC.isEquivalence₂
; isEquivalence₂ = IC.isEquivalence₁
}
where module IC = IsCongruent ic

isLeftInverse : IsRightInverse ≈₁ ≈₂ f f⁻¹ → IsLeftInverse ≈₂ ≈₁ f⁻¹ f
isLeftInverse inv = record
{ isCongruent = isCongruent F.isCongruent F.cong₂
; cong₂ = F.cong₁
; inverseˡ = inverseˡ ≈₁ ≈₂ f {f⁻¹} F.inverseʳ
}
where module F = IsRightInverse inv

isRightInverse : IsLeftInverse ≈₁ ≈₂ f f⁻¹ → IsRightInverse ≈₂ ≈₁ f⁻¹ f
isRightInverse inv = record
{ isCongruent = isCongruent F.isCongruent F.cong₂
; cong₂ = F.cong₁
; inverseʳ = inverseʳ ≈₁ ≈₂ f {f⁻¹} F.inverseˡ
}
where module F = IsLeftInverse inv

isInverse : IsInverse ≈₁ ≈₂ f f⁻¹ → IsInverse ≈₂ ≈₁ f⁻¹ f
isInverse f-inv = record
{ isLeftInverse = isLeftInverse F.isRightInverse
; inverseʳ = inverseʳ ≈₁ ≈₂ f F.inverseˡ
}
where module F = IsInverse f-inv

------------------------------------------------------------------------
-- Setoid bundles

module _ {R : Setoid a ℓ₁} {S : Setoid b ℓ₂} where

equivalence : Equivalence R S → Equivalence S R
equivalence equiv = record
{ f = E.g
; g = E.f
; cong₁ = E.cong₂
; cong₂ = E.cong₁
}
where module E = Equivalence equiv

rightInverse : LeftInverse R S → RightInverse S R
rightInverse left = record
{ f = L.g
; g = L.f
; cong₁ = L.cong₂
; cong₂ = L.cong₁
; inverseʳ = L.inverseˡ
} where module L = LeftInverse left

leftInverse : RightInverse R S → LeftInverse S R
leftInverse right = record
{ f = R.g
; g = R.f
; cong₁ = R.cong₂
; cong₂ = R.cong₁
; inverseˡ = R.inverseʳ
} where module R = RightInverse right

inverse : Inverse R S → Inverse S R
inverse inv = record
{ f = I.f⁻¹
; f⁻¹ = I.f
; cong₁ = I.cong₂
; cong₂ = I.cong₁
; inverse = swap I.inverse
} where module I = Inverse inv

------------------------------------------------------------------------
-- Propositional bundles

sym-⇔ : A ⇔ B → B ⇔ A
sym-⇔ = equivalence

sym-↩ : A ↩ B → B ↪ A
sym-↩ = rightInverse

sym-↪ : A ↪ B → B ↩ A
sym-↪ = leftInverse

sym-↔ : A ↔ B → B ↔ A
sym-↔ = inverse
```