29
Experience Report: Typechecking Polymorphic Units for Astrophysics Research in Haskell Takayuki Muranushi Advanced Institute for Computational Science, RIKEN [email protected] Richard A. Eisenberg University of Pennsylvania [email protected]

Type-checking Polymorphic Units for Astrophysics Research in Haskell

Embed Size (px)

Citation preview

  • ExperienceReport:TypecheckingPolymorphicUnitsforAstrophysics

    ResearchinHaskell

    TakayukiMuranushiAdvancedInstituteforComputationalScience,

    [email protected]

    RichardA.EisenbergUniversityofPennsylvania

    [email protected]

  • July23,

    AirCanadaFlight143,aBoeing767233wasdepartingMontrealtoEdmonton.

    Thefuelgaugeisnotworking. Thecrewsuseabackupsystemandmanuallycalculatedtheamountoffueltoberefueled.

    1983 .

  • Manualcalculationmassoffuelrequired densityoffuel volumetoberefueled

    [kg] [pound/L] [*L]

    [kg] [kg/L] [L]

    massoffuelrequired densityoffuel volumetoberefueled

    Thecorrectcalculation

    Flight143tookoffwith22,300pounds offueltoEdmonton,where22,300kg wasactuallyneeded.

  • Flight143madeanemergencylandingonrunway32LofGimliabandonedairport.

    ItwasFamilyDayfestival;gocarts,campers,familiesandbarbecueswereon32L.

    Noonewasseriouslyhurtnorkilled.

    WadeH.Nelson(1997)

  • [kg] [kg/L] [L]

    Mass Density Volume

    [lb.] [lb./L] [L]

    Asamelawofphysicscanberepresentedinmanydifferentunits

    DimensionsLevel:

    UnitsLevel:

    Massoffuelrequired Densityoffuel

    Volumetoberefueled

    QuantityLevel:

    quantityvalue =numericalvalue[unit ]

    [kg] [lb./L] [L]

  • ToavoidmistakeslikeGimliGlider,wewouldliketousetypesystemtoenforcethecorrectnessofthedimensionsandunitsinourcalculations.

    Suchcorrectnessoflawsofphysicsismorethanjustaboutspecificsetofunits;wecanrepresentonequantityinmanydifferentunits,buttheymeanthesamequantity.

    unitsofmeasure aretosciencewhattypesaretoprogramming A.J.Kennedy

  • unitsofmeasure aretosciencewhattypesaretoprogramming A.J.Kennedy

    Lawsofphysicsaredimensionmonomorphicandunitpolymorphic

    T.Muranushi

    [kg] [kg/L] [L] [lb.] [lb./L] [L]

    Mass Density Volume DimensionsLevel:

    UnitsLevel:

  • WealreadyhavetypesystemofunitsformanylanguagesincludingC,F#,simulink andofcourseinHaskell;wealreadyhavepolymorphism.Willtheyblend?

    unitsofmeasurearetosciencewhattypesaretoprogramming A.J.Kennedy

    Lawsofphysicsaredimensionmonomorphicandunitpolymorphic

    T.Muranushi

  • Using`unittyped` byThijsAlkemade,IstartedanattempttoencodeknowledgeofphysicsinHaskell.

  • Aunitmonomorphicquantityfunctionrefuel::Fractionalf=>

    ValueMassKiloGram f>ValueDensityKiloGramPerLiter f>ValueVolumeLiterf

    refuelgasMassgasDen=gasMass|/|gasDen

    refuel::Fractionalf=>ValueMassKiloGram f

    >ValueDensityKiloGramPerLiter f>ValueVolumeLiterf

    refuelgasMassgasDen=gasMass|/|gasDen

    Aunitpolymorphicversion?

    Thiscodedoesntcompile.

    refuel::Fractionalf=>ValueMassuniMass f Here we replace the unit types

    >ValueDensityuniDen f with type variables>ValueVolumeuniVol f

    refuelgasMass gasDen =gasMass |/|gasDen

  • refuel::(Fractionalf,Convertible'MassuniMass,Convertible'DensityuniDen,Convertible'Volume uniVol,MapNeg negUniDen uniDen, negUniDen = 1 / uniDenMapMerge uniMass negUniDen uniVol uniMass * negUniDen = uniVol

    )=>ValueMassuniMass f

    >ValueDensityuniDen f>ValueVolumeuniVol f

    refuelgasMassgasDen=gasMass|/|gasDen

    refuel::(Fractionalf,Convertible'MassuniMass,Convertible'DensityuniDen,Convertible'Volume uniVol,MapNeg negUniDen uniDen, negUniDen = 1 / uniDenMapMerge uniMass negUniDen uniVol uniMass * negUniDen = uniVol

    )=>ValueMassuniMass f

    >ValueDensityuniDen f>ValueVolumeuniVol f

    refuelgasMassgasDen=gasMass|/|gasDen

    needstheseannotationstocompile:

    refuel::Fractionalf=>ValueMassuniMass f

    >ValueDensityuniDen f>ValueVolumeuniVol f

    refuelgasMass gasDen =gasMass |/|gasDen

    Thiscode

  • refuel::(Fractionalf,Convertible'Massumass,Convertible'Densityuden,Convertible'Volume uvol,MapNeg negUden uden,MapMerge umass negUden uvol)=>ValueMassumass f

    >ValueDensityuden f>ValueVolumeuvol frefuelgasMassgasDen=gasMass|/|gasDen

    Problemwithunitpolymorphismin`unittyped`toomuchtypeconstraint!!

    gravityPoisson::(Fractionalx,dimLen~LengthDimension,dimPot~'['(Time,NTwo),'(Length,PTwo)],dimDen~Density,dimZhz ~'['(Time,NTwo)],Convertible'dimLenuniLen,Convertible'dimPotuniPot,Convertible'dimDenuniDen,Convertible'dimZhz uniZhz,Convertible'dimZhz uniZhz',MapMergedimLendimLen dimLen2,MapNegdimLen2dimLenNeg2,MapMergedimPotdimLenNeg2dimZhz,MapMergedimDen'['(Time,NTwo),'(Length,PThree),

    '(Mass,NOne)]dimZhz,MapMergeuniLen uniLen uniLen2,MapNeguniLen2uniLenNeg2,MapMergeuniPot uniLenNeg2uniZhz,MapMergeuniDen '['(Second,NTwo),'(Meter,

    PThree),'((KiloGram),NOne)]uniZhz')=>

    (forall s.AD.Mode s=>Vec3(ValuedimLenuniLen (ADsx))>ValuedimPot

    uniPot (ADsx))>(Vec3(ValuedimLenuniLen x)>(ValuedimDen

    uniDen x))>(Vec3(ValuedimLenuniLen x)>(ValuedimZhz

    uniZhz x))

    gravityPoissongravitationalPotential densityr=laplacian gravitationalPotential r||(4*|pi|*|

    densityr|*|g)

    gravityPoisson ::(Fractional x, dimLen ~ LengthDimension, dimPot ~ '[ '(Time, NTwo), '(Length, PTwo)], dimDen ~ Density, dimZhz ~ '[ '(Time, NTwo)], Convertible' dimLen uniLen, Convertible' dimPot uniPot, Convertible' dimDen uniDen, Convertible' dimZhz uniZhz, Convertible' dimZhz uniZhz', MapMerge dimLen dimLen dimLen2, MapNeg dimLen2 dimLenNeg2, MapMerge dimPot dimLenNeg2 dimZhz, MapMerge dimDen '[ '(Time, NTwo), '(Length, PThree), '(Mass, NOne) ] dimZhz, MapMerge uniLen uniLen uniLen2, MapNeg uniLen2 uniLenNeg2, MapMerge uniPot uniLenNeg2 uniZhz, MapMerge uniDen '[ '(Second, NTwo), '(Meter, PThree), '((Kilo Gram), NOne) ] uniZhz') =>(forall s. AD.Mode s =>Vec3 (Value dimLen uniLen (AD s x)) > Value dimPot uniPot (AD s x))> (Vec3 (Value dimLen uniLen x) > (Value dimDen uniDen x))> (Vec3 (Value dimLen uniLen x) > (Value dimZhz uniZhz x))gravityPoisson gravitationalPotential density r= laplacian gravitationalPotential r || (4 *| pi |*| density r |*| g)gravitationalPotentialToDensity ::forall xdimLen dimDen dimDen' dimLen2 dimNegLen2 dimZhz dimNegGC dimPotuniLen uniDen uniDen' uniLen2 uniNegLen2 uniZhz uniNegGC uniPot .(Fractional x, dimLen ~ LengthDimension, dimPot ~ '[ '(Time, NTwo), '(Length, PTwo)], dimDen ~ Density, MapEq dimDen' dimDen, Convertible' dimLen uniLen, Convertible' dimPot uniPot, Convertible' dimZhz uniZhz, Convertible' dimDen' uniDen', Convertible' dimDen uniDen, MapMerge dimLen dimLen dimLen2, MapNeg dimLen2 dimNegLen2, MapMerge dimPot dimNegLen2 dimZhz, MapNeg '[ '(Time, NTwo), '(Length, PThree), '(Mass, NOne) ] dimNegGC, dimNegGC ~ '[ '(Time, PTwo), '(Length, NThree), '(Mass, POne) ], MapMerge dimZhz dimNegGC dimDen', MapMerge uniLen uniLen uniLen2, MapNeg uniLen2 uniNegLen2, MapMerge uniPot uniNegLen2 uniZhz, MapNeg '[ '(Second, NTwo), '(Meter, PThree), '((Kilo Gram), NOne) ] uniNegGC, uniNegGC ~ '[ '(Second, PTwo), '(Meter, NThree), '((Kilo Gram), POne) ], MapMerge uniZhz uniNegGC uniDen') =>(forall s. AD.Mode s =>Vec3 (Value dimLen uniLen (AD s x)) > Value dimPot uniPot (AD s x))> (Vec3 (Value dimLen uniLen x) > (Value dimDen uniDen x))gravitationalPotentialToDensity gravitationalPotential r= to (undefined :: Value dimDen uniDen x) $(laplacian gravitationalPotential r |/| (4 *| pi |*| g) :: Value dimDen' uniDen' x)

    hydrostatic ::forall xdimLen dimPre dimDen dimAcc dimGpr dimNegLen dimNegDen dimAcc'uniLen uniPre uniDen uniAcc uniGpr uniNegLen uniNegDen uniAcc' .( Fractional x, dimLen ~ LengthDimension, dimPre ~ Pressure, dimDen ~ Density, dimAcc ~ Acceleration, dimNegDen ~ '[ '(Length, PThree), '(Mass, NOne) ], dimGpr ~ '[ '(Length, NTwo), '(Mass, POne) , '(Time, NTwo) ], Convertible' dimLen uniLen, Convertible' dimPre uniPre, Convertible' dimGpr uniGpr, Convertible' dimDen uniDen, Convertible' dimAcc uniAcc, Convertible' dimAcc' uniAcc', MapNeg dimLen dimNegLen, MapMerge dimPre dimNegLen dimGpr, MapNeg dimDen dimNegDen, MapMerge dimGpr dimNegDen dimAcc', MapEq dimAcc' dimAcc, MapNeg uniLen uniNegLen, MapMerge uniPre uniNegLen uniGpr, MapNeg uniDen uniNegDen, MapMerge uniGpr uniNegDen uniAcc') =>(forall s. AD.Mode s =>Vec3 (Value dimLen uniLen (AD s x)) > Value dimPre uniPre (AD s x))> (Vec3 (Value dimLen uniLen x) > Value dimDen uniDen x)> (Vec3 (Value dimLen uniLen x) > Vec3 (Value dimAcc uniAcc x))> (Vec3 (Value dimLen uniLen x) > Vec3 (Value dimAcc uniAcc x))hydrostatic pressure density externalAcc r= compose $ i > to (undefined :: Value dimAcc uniAcc x) $(externalAcc r ! i) |+| (gradP r ! i) |/| (density r)wheregradP :: Vec3 (Value dimLen uniLen x) > Vec3 (Value dimGpr uniGpr x)gradP = grad pressure

    pressureToAcc ::forall xdimLen dimPre dimDen dimAcc dimGpr dimNegLen dimNegDen dimAcc'uniLen uniPre uniDen uniGpr uniNegLen uniNegDen uniAcc' .( Fractional x, dimLen ~ LengthDimension, dimPre ~ Pressure, dimDen ~ Density, dimAcc ~ Acceleration, dimNegDen ~ '[ '(Length, PThree), '(Mass, NOne) ], dimGpr ~ '[ '(Length, NTwo), '(Mass, POne) , '(Time, NTwo) ], Convertible' dimLen uniLen, Convertible' dimPre uniPre, Convertible' dimGpr uniGpr, Convertible' dimDen uniDen, Convertible' dimAcc' uniAcc', Convertible' dimAcc uniAcc', MapNeg dimLen dimNegLen, MapMerge dimPre dimNegLen dimGpr, MapNeg dimDen dimNegDen, MapMerge dimGpr dimNegDen dimAcc', MapEq dimAcc' dimAcc, MapNeg uniLen uniNegLen, MapMerge uniPre uniNegLen uniGpr, MapNeg uniDen uniNegDen, MapMerge uniGpr uniNegDen uniAcc') =>(forall s. AD.Mode s =>Vec3 (Value dimLen uniLen (AD s x)) > Value dimPre uniPre (AD s x))> (Vec3 (Value dimLen uniLen x) > Value dimDen uniDen x)> (Vec3 (Value dimLen uniLen x) > Vec3 (Value dimAcc uniAcc' x))pressureToAcc pressure density r= compose $ i > to (undefined :: Value dimAcc uniAcc' x) $(gradP r ! i) |/| (density r)wheregradP :: Vec3 (Value dimLen uniLen x) > Vec3 (Value dimGpr uniGpr x)gradP = grad pressure

    gravitationalPotentialToAcc ::forall xdimLen dimPot dimAcc' dimNegLen dimAccuniLen uniPot uniAcc' uniNegLen( Fractional x, dimLen ~ LengthDimension, dimPot ~ '[ '(Time, NTwo), '(Length, PTwo)], dimAcc' ~ '[ '(Length, POne), '(Time, NTwo)], dimAcc ~ Acceleration, Convertible' dimLen uniLen, Convertible' dimPot uniPot, Convertible' dimAcc' uniAcc', Convertible' dimAcc uniAcc', MapNeg dimLen dimNegLen, MapMerge dimPot dimNegLen dimAcc', MapEq dimAcc' dimAcc, MapNeg uniLen uniNegLen, MapMerge uniPot uniNegLen uniAcc') =>(forall s. AD.Mode s =>Vec3 (Value dimLen uniLen (AD s x)) > Value dimPot uniPot (AD s x))> (Vec3 (Value dimLen uniLen x) > Vec3 (Value dimAcc uniAcc' x))gravitationalPotentialToAcc pot r =(fmap $ to (undefined :: Value dimAcc uniAcc x)) $grad pot r

    Weneedatleasttwotypeconstraintsperonearithmeticoperator,inordertoencodetypelevel unitcalculations.

    Colorsindicate: Typeconstraints, Types,Values

  • Problem Solution

  • Oursolution:

  • Quantityrepresentationin`unittyped`

    >:t88*|mile|/|hour ::Fractionalf=>

    Value'['(Length,POne),'(Time,NOne)]'['(Mile,POne),'(Hour,NOne)]f

    >:t88*|mile|/|hour ::Fractionalf=>

    Value'['(Length,POne),'(Time,NOne)]'['(Mile,POne),'(Hour,NOne)]f

    Typeconstructortakes(dimensions)(units)(numericalvalue)

    >:t88 % mile:/hour::Fractionalf=>QuVelocitySIf ::Fractionalf=>

    Qu'['(Length,One),'(Time,MOne)]'['(Length,Meter),'(Time,Second),]f

    >:t88 % mile:/hour::Fractionalf=>QuVelocitySIf ::Fractionalf=>

    Qu'['(Length,One),'(Time,MOne)]'['(Length,Meter),'(Time,Second),]f

    Typeconstructortakes(dimensions)(mapfromdimensionstounits) (numericalvalue)

    Quantityrepresentationin`units`

  • SystemofUnitsastypeargument Themapfromdimensionstounitsrepresentsasystemofunits;e.g.SIsystem,CGS(centimetergramsecond)system,etc.>88%Miles:/Hour::QuVelocitySIFloat39.33952m/s>:infoSItypeSI=MkLCSU

    '[(Length,Meter),(Mass,Kilo:@Gram),(Time,Second),(Current,Ampere),(Temperature,Kelvin),(AmountOfSubstance,Mole),(LuminousIntensity,Lumen)]

    >:infoCGStypeCGS=MkLCSU

    '[(Length,Centi:@Meter),(Mass,Gram),(Time,Second)]

    >88%Miles:/Hour::QuVelocitySIFloat39.33952m/s>:infoSItypeSI=MkLCSU

    '[(Length,Meter),(Mass,Kilo:@Gram),(Time,Second),(Current,Ampere),(Temperature,Kelvin),(AmountOfSubstance,Mole),(LuminousIntensity,Lumen)]

    >:infoCGStypeCGS=MkLCSU

    '[(Length,Centi:@Meter),(Mass,Gram),(Time,Second)]

  • [Def]Acoherentsystemofunit

    AJoule(1 [kg/m2s2])isthecoherentderivedunitofenergyinSI

    Anerg(1 [g/cm2s2] = 10-7J)isthecoherentderivedunitofenergyincentimetergramsecondsystem

    [kg] [kg/m3] [m3]

    [SI mass] [SI density] [SI volume]

    = {u1, u2, , un} {u1p u2q unr | p,q, , r }baseunits unitsderivedbyproductsofbaseunits

    1:1mappingbetweendimensionsandunits

  • localcoherentsystemofunit istheonlyone,unconstrained,typevariable

    Thecomputationisnondimensionalized;canbecarriedoutwithoutdetailsunits.

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

    Unitpolymorphiccalculationsin`units`

    [kg] [kg/m3] [m3]

    [SI mass] [SI density] [SI volume]

  • Unitpolymorphismwithfundeps gaverisetooverwhelmingcomplexesofconstrainedtypevariables

    Takelocalcoherentsystemofunit asonlyonefreevariable

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

    refuel::(Fractionalf,Convertible'Massumass,Convertible'Densityuden,Convertible'Volume uvol,MapNeg negUden uden,MapMerge umass negUden uvol)=>ValueMassumass f

    >ValueDensityuden f>ValueVolumeuvol frefuelgasMassgasDen=gasMass|/|gasDen

    refuel::(Fractionalf,Convertible'Massumass,Convertible'Densityuden,Convertible'Volume uvol,MapNeg negUden uden,MapMerge umass negUden uvol)=>ValueMassumass f

    >ValueDensityuden f>ValueVolumeuvol frefuelgasMassgasDen=gasMass|/|gasDen

  • Anapplication:Avoidover/underflow

  • ljForce::Energy Float>Length Float>Length Float>Force Float

    ljForceepssigmar=(24*|eps|*|sigma|pSix) |/|(r|pSeven)||(48*|eps|*|sigma|pTwelve)|/|(r|pThirteen)

    ljForce::Energy Float>Length Float>Length Float>Force Float

    ljForceepssigmar=(24*|eps|*|sigma|pSix) |/|(r|pSeven)||(48*|eps|*|sigma|pTwelve)|/|(r|pThirteen)

    Solution #1:

    >letsigmaAr=3.4e8%MeterepsAr=1.68e21%Jouler=4.0e8%Meter

    >(ljForceepsArsigmaArr::ForceSIFloat)#NewtonNaN

    >letsigmaAr=3.4e8%MeterepsAr=1.68e21%Jouler=4.0e8%Meter

    >(ljForceepsArsigmaArr::ForceSIFloat)#NewtonNaN

    Exercise: How many Newtons is the Lennard-Jones force F between two argon atoms at distance 4, where

  • ljForce::Energy Float>Length Float>Length Float>Force Float

    ljForceepssigmar=(24*|eps|*|sigma|pSix) |/|(r|pSeven)||(48*|eps|*|sigma|pTwelve)|/|(r|pThirteen)

    typeCU=MkLCSU'['(Length,Angstrom),'(Mass,ProtonMass),'(Time,Pico:@Second)]

    ljForce::Energy Float>Length Float>Length Float>Force Float

    ljForceepssigmar=(24*|eps|*|sigma|pSix) |/|(r|pSeven)||(48*|eps|*|sigma|pTwelve)|/|(r|pThirteen)

    typeCU=MkLCSU'['(Length,Angstrom),'(Mass,ProtonMass),'(Time,Pico:@Second)]

    Solution #2:

    >(ljForceepsArsigmaArr::ForceCUFloat)#Newton9.3407324e14>(ljForceepsArsigmaArr::ForceCUFloat)#Newton9.3407324e14

    Exercise: How many Newtons is the Lennard-Jones force F between two argon atoms at distance 4, where

  • AstrophysicsresearchinHaskell

    A27pageastrophysicspaperhasbeenwritteninHaskell;itsquantitativereasoningispoweredbytheunits library.

  • Experience Conclusion

  • Whenyoudesigntypesystemofunitsconsiderunitpolymorphism

    because,withunitpolymorphism Wecanfaithfullyexpressunitindependentnatureoflawsofphysics.

    Wecanwritequantityexpressions,whichuserscanlaterinterpretinunitsystemsoftheirchoice.

    Wecanavoidoverflows/underflowsbyappropriatelychoosingsystemofunits.

  • Aneasywaytoimplementunitpolymorphismistotakelocalcoherentsystemofunit asonlyonefreevariable

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

  • Inthepaper

    Extensibility Quantitycombinators Valuelevelunits Protectnumericalvaluesfrommanipulation

    Thingscameafterpaper defaultLCSU TemplateHaskell

  • Comments Haskellissuchacoollanguagethatallowssomethinglike`units` atall.Itstypesystemissoprogrammablethatthesefeaturescanbebuiltontopof,insteadofbeingintegratedin(likeF#)orexternallyanalyzed(likeC)

    Asfarasweknow,`units` istheonlypracticalsystemthatsupportsunitpolymorphism.

    HeartfeltthankstoallpeoplesworkthatenabledGHC7.8,andtoRichardwhoimplemented`units`.

  • Thanks! Questions?cabalinstallunits

    andenjoyunitpolymorphism!

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen

    refuel::Fractionalf=>QuMass f>QuDensity f>QuVolume frefuelgasMassgasDen=gasMass|/|gasDen