packages feed

ghc-typelits-presburger 0.2.0.5 → 0.3.0.0

raw patch · 9 files changed

+1837/−1621 lines, 9 filesdep −singletonsdep ~equational-reasoningdep ~ghcdep ~ghc-tcplugins-extranew-component:exe:simple-arith-corePVP ok

version bump matches the API change (PVP)

Dependencies removed: singletons

Dependency ranges changed: equational-reasoning, ghc, ghc-tcplugins-extra

API changes (from Hackage documentation)

- GHC.TypeLits.Presburger: instance GHC.Classes.Eq GHC.TypeLits.Presburger.Proof
- GHC.TypeLits.Presburger: instance GHC.Classes.Ord GHC.TypeLits.Presburger.Proof
- GHC.TypeLits.Presburger: instance GHC.Read.Read GHC.TypeLits.Presburger.Proof
- GHC.TypeLits.Presburger: instance GHC.Show.Show GHC.TypeLits.Presburger.Proof
+ GHC.TypeLits.Presburger.Compat: AbstractClosedSynFamilyTyCon :: FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: AbstractTyCon :: AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: AbstractTypeFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: AddrRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: AnonTCB :: TyConBndrVis
+ GHC.TypeLits.Presburger.Compat: AppTy :: Type -> Type -> Type
+ GHC.TypeLits.Presburger.Compat: BuiltInSynFamTyCon :: BuiltInSynFamily -> FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: BuiltInSynFamily :: ([Type] -> Maybe (CoAxiomRule, [Type], Type)) -> ([Type] -> Type -> [TypeEqn]) -> ([Type] -> Type -> [Type] -> Type -> [TypeEqn]) -> BuiltInSynFamily
+ GHC.TypeLits.Presburger.Compat: BuiltInTypeFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: CastTy :: Type -> KindCoercion -> Type
+ GHC.TypeLits.Presburger.Compat: ClassFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: ClassPred :: Class -> [Type] -> PredTree
+ GHC.TypeLits.Presburger.Compat: ClassTyCon :: Class -> TyConRepName -> AlgTyConFlav
+ GHC.TypeLits.Presburger.Compat: ClosedSynFamilyTyCon :: Maybe (CoAxiom Branched) -> FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: ClosedTypeFamilyFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: CoercionTy :: Coercion -> Type
+ GHC.TypeLits.Presburger.Compat: DataFamInstTyCon :: CoAxiom Unbranched -> TyCon -> [Type] -> AlgTyConFlav
+ GHC.TypeLits.Presburger.Compat: DataFamilyFlavour :: Bool -> TyConFlavour
+ GHC.TypeLits.Presburger.Compat: DataFamilyTyCon :: TyConRepName -> FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: DataTyCon :: [DataCon] -> Int -> Bool -> AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: DataTypeFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: DoubleElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: DoubleRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: EqPred :: EqRel -> Type -> Type -> PredTree
+ GHC.TypeLits.Presburger.Compat: FloatElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: FloatRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: ForAllPred :: [TyVarBinder] -> [PredType] -> PredType -> PredTree
+ GHC.TypeLits.Presburger.Compat: ForAllTy :: {-# UNPACK #-} !TyVarBinder -> Type -> Type
+ GHC.TypeLits.Presburger.Compat: FunTy :: Type -> Type -> Type
+ GHC.TypeLits.Presburger.Compat: Injective :: [Bool] -> Injectivity
+ GHC.TypeLits.Presburger.Compat: Int16ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: Int32ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: Int64ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: Int64Rep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: Int8ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: IntRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: IrredPred :: PredType -> PredTree
+ GHC.TypeLits.Presburger.Compat: LiftedRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: LitTy :: TyLit -> Type
+ GHC.TypeLits.Presburger.Compat: NamedTCB :: ArgFlag -> TyConBndrVis
+ GHC.TypeLits.Presburger.Compat: NewTyCon :: DataCon -> Type -> ([TyVar], Type) -> CoAxiom Unbranched -> AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: NewtypeFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: NoRRI :: RuntimeRepInfo
+ GHC.TypeLits.Presburger.Compat: NomEq :: EqRel
+ GHC.TypeLits.Presburger.Compat: Nominal :: Role
+ GHC.TypeLits.Presburger.Compat: NotInjective :: Injectivity
+ GHC.TypeLits.Presburger.Compat: NumTyLit :: Integer -> TyLit
+ GHC.TypeLits.Presburger.Compat: OpenSynFamilyTyCon :: FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: OpenTypeFamilyFlavour :: Bool -> TyConFlavour
+ GHC.TypeLits.Presburger.Compat: Phantom :: Role
+ GHC.TypeLits.Presburger.Compat: Plugin :: CorePlugin -> TcPlugin -> ([CommandLineOption] -> IO PluginRecompile) -> ([CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule) -> ([CommandLineOption] -> TcGblEnv -> HsGroup GhcRn -> TcM (TcGblEnv, HsGroup GhcRn)) -> ([CommandLineOption] -> ModSummary -> TcGblEnv -> TcM TcGblEnv) -> ([CommandLineOption] -> LHsExpr GhcTc -> TcM (LHsExpr GhcTc)) -> (forall lcl. () => [CommandLineOption] -> ModIface -> IfM lcl ModIface) -> Plugin
+ GHC.TypeLits.Presburger.Compat: PromotedDataConFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: ReprEq :: EqRel
+ GHC.TypeLits.Presburger.Compat: Representational :: Role
+ GHC.TypeLits.Presburger.Compat: RuntimeRep :: ([Type] -> [PrimRep]) -> RuntimeRepInfo
+ GHC.TypeLits.Presburger.Compat: SumFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: SumTyCon :: [DataCon] -> Int -> AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: TCvSubst :: InScopeSet -> TvSubstEnv -> CvSubstEnv -> TCvSubst
+ GHC.TypeLits.Presburger.Compat: TcPluginContradiction :: [Ct] -> TcPluginResult
+ GHC.TypeLits.Presburger.Compat: TcPluginOk :: [(EvTerm, Ct)] -> [Ct] -> TcPluginResult
+ GHC.TypeLits.Presburger.Compat: TupleFlavour :: Boxity -> TyConFlavour
+ GHC.TypeLits.Presburger.Compat: TupleTyCon :: DataCon -> TupleSort -> AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: TvSubst :: InScopeSet -> TvSubstEnv -> TvSubst
+ GHC.TypeLits.Presburger.Compat: TyConApp :: TyCon -> [KindOrType] -> Type
+ GHC.TypeLits.Presburger.Compat: TyVarTy :: Var -> Type
+ GHC.TypeLits.Presburger.Compat: TypeEq :: Type -> TypeEq
+ GHC.TypeLits.Presburger.Compat: TypeSynonymFlavour :: TyConFlavour
+ GHC.TypeLits.Presburger.Compat: UnboxedAlgTyCon :: Maybe TyConRepName -> AlgTyConFlav
+ GHC.TypeLits.Presburger.Compat: UnliftedRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: VanillaAlgTyCon :: TyConRepName -> AlgTyConFlav
+ GHC.TypeLits.Presburger.Compat: VecCount :: Int -> RuntimeRepInfo
+ GHC.TypeLits.Presburger.Compat: VecElem :: PrimElemRep -> RuntimeRepInfo
+ GHC.TypeLits.Presburger.Compat: VecRep :: Int -> PrimElemRep -> PrimRep
+ GHC.TypeLits.Presburger.Compat: VoidRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: Word16ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: Word32ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: Word64ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: Word64Rep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: Word8ElemRep :: PrimElemRep
+ GHC.TypeLits.Presburger.Compat: WordRep :: PrimRep
+ GHC.TypeLits.Presburger.Compat: [TcPlugin] :: forall s. () => {tcPluginInit :: TcPluginM s, tcPluginSolve :: s -> TcPluginSolver, tcPluginStop :: s -> TcPluginM ()} -> TcPlugin
+ GHC.TypeLits.Presburger.Compat: [data_con] :: AlgTyConRhs -> DataCon
+ GHC.TypeLits.Presburger.Compat: [data_cons] :: AlgTyConRhs -> [DataCon]
+ GHC.TypeLits.Presburger.Compat: [data_cons_size] :: AlgTyConRhs -> Int
+ GHC.TypeLits.Presburger.Compat: [installCoreToDos] :: Plugin -> CorePlugin
+ GHC.TypeLits.Presburger.Compat: [interfaceLoadAction] :: Plugin -> forall lcl. () => [CommandLineOption] -> ModIface -> IfM lcl ModIface
+ GHC.TypeLits.Presburger.Compat: [is_enum] :: AlgTyConRhs -> Bool
+ GHC.TypeLits.Presburger.Compat: [nt_co] :: AlgTyConRhs -> CoAxiom Unbranched
+ GHC.TypeLits.Presburger.Compat: [nt_etad_rhs] :: AlgTyConRhs -> ([TyVar], Type)
+ GHC.TypeLits.Presburger.Compat: [nt_rhs] :: AlgTyConRhs -> Type
+ GHC.TypeLits.Presburger.Compat: [parsedResultAction] :: Plugin -> [CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule
+ GHC.TypeLits.Presburger.Compat: [pluginRecompile] :: Plugin -> [CommandLineOption] -> IO PluginRecompile
+ GHC.TypeLits.Presburger.Compat: [renamedResultAction] :: Plugin -> [CommandLineOption] -> TcGblEnv -> HsGroup GhcRn -> TcM (TcGblEnv, HsGroup GhcRn)
+ GHC.TypeLits.Presburger.Compat: [runTypeEq] :: TypeEq -> Type
+ GHC.TypeLits.Presburger.Compat: [sfInteractInert] :: BuiltInSynFamily -> [Type] -> Type -> [Type] -> Type -> [TypeEqn]
+ GHC.TypeLits.Presburger.Compat: [sfInteractTop] :: BuiltInSynFamily -> [Type] -> Type -> [TypeEqn]
+ GHC.TypeLits.Presburger.Compat: [sfMatchFam] :: BuiltInSynFamily -> [Type] -> Maybe (CoAxiomRule, [Type], Type)
+ GHC.TypeLits.Presburger.Compat: [spliceRunAction] :: Plugin -> [CommandLineOption] -> LHsExpr GhcTc -> TcM (LHsExpr GhcTc)
+ GHC.TypeLits.Presburger.Compat: [tcPlugin] :: Plugin -> TcPlugin
+ GHC.TypeLits.Presburger.Compat: [tup_sort] :: AlgTyConRhs -> TupleSort
+ GHC.TypeLits.Presburger.Compat: [typeCheckResultAction] :: Plugin -> [CommandLineOption] -> ModSummary -> TcGblEnv -> TcM TcGblEnv
+ GHC.TypeLits.Presburger.Compat: algTyConRhs :: TyCon -> AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: boolTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: checkFamInstConsistency :: [Module] -> TcM ()
+ GHC.TypeLits.Presburger.Compat: checkRecTc :: RecTcChecker -> TyCon -> Maybe RecTcChecker
+ GHC.TypeLits.Presburger.Compat: classifyPredType :: PredType -> PredTree
+ GHC.TypeLits.Presburger.Compat: ctEvPred :: CtEvidence -> TcPredType
+ GHC.TypeLits.Presburger.Compat: ctEvidence :: Ct -> CtEvidence
+ GHC.TypeLits.Presburger.Compat: data AlgTyConFlav
+ GHC.TypeLits.Presburger.Compat: data AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: data BuiltInSynFamily
+ GHC.TypeLits.Presburger.Compat: data Ct
+ GHC.TypeLits.Presburger.Compat: data EqRel
+ GHC.TypeLits.Presburger.Compat: data EvTerm
+ GHC.TypeLits.Presburger.Compat: data FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: data Injectivity
+ GHC.TypeLits.Presburger.Compat: data ModuleName
+ GHC.TypeLits.Presburger.Compat: data Plugin
+ GHC.TypeLits.Presburger.Compat: data PredTree
+ GHC.TypeLits.Presburger.Compat: data PrimElemRep
+ GHC.TypeLits.Presburger.Compat: data PrimRep
+ GHC.TypeLits.Presburger.Compat: data RecTcChecker
+ GHC.TypeLits.Presburger.Compat: data Role
+ GHC.TypeLits.Presburger.Compat: data RuntimeRepInfo
+ GHC.TypeLits.Presburger.Compat: data TCvSubst
+ GHC.TypeLits.Presburger.Compat: data TcPlugin
+ GHC.TypeLits.Presburger.Compat: data TcPluginM a
+ GHC.TypeLits.Presburger.Compat: data TcPluginResult
+ GHC.TypeLits.Presburger.Compat: data TvSubst
+ GHC.TypeLits.Presburger.Compat: data TyCon
+ GHC.TypeLits.Presburger.Compat: data TyConBndrVis
+ GHC.TypeLits.Presburger.Compat: data TyConFlavour
+ GHC.TypeLits.Presburger.Compat: data TyLit
+ GHC.TypeLits.Presburger.Compat: data Type
+ GHC.TypeLits.Presburger.Compat: decompFunTy :: Type -> [Type]
+ GHC.TypeLits.Presburger.Compat: defaultPlugin :: Plugin
+ GHC.TypeLits.Presburger.Compat: emptyOccSet :: OccSet
+ GHC.TypeLits.Presburger.Compat: emptyTCvSubst :: TCvSubst
+ GHC.TypeLits.Presburger.Compat: emptyTvSubst :: TvSubst
+ GHC.TypeLits.Presburger.Compat: eqType :: Type -> Type -> Bool
+ GHC.TypeLits.Presburger.Compat: evByFiat :: String -> Type -> Type -> EvTerm
+ GHC.TypeLits.Presburger.Compat: expandSynTyCon_maybe :: () => TyCon -> [tyco] -> Maybe ([(TyVar, tyco)], Type, [tyco])
+ GHC.TypeLits.Presburger.Compat: famTyConFlav_maybe :: TyCon -> Maybe FamTyConFlav
+ GHC.TypeLits.Presburger.Compat: fromTCv :: TCvSubst -> TvSubst
+ GHC.TypeLits.Presburger.Compat: fsLit :: String -> FastString
+ GHC.TypeLits.Presburger.Compat: getEqTyCon :: TcPluginM TyCon
+ GHC.TypeLits.Presburger.Compat: getEqWitnessTyCon :: TcPluginM TyCon
+ GHC.TypeLits.Presburger.Compat: getKey :: Unique -> Int
+ GHC.TypeLits.Presburger.Compat: getUnique :: Uniquable a => a -> Unique
+ GHC.TypeLits.Presburger.Compat: initRecTc :: RecTcChecker
+ GHC.TypeLits.Presburger.Compat: injTyVarsOfType :: TcTauType -> TcTyVarSet
+ GHC.TypeLits.Presburger.Compat: injTyVarsOfTypes :: [Type] -> VarSet
+ GHC.TypeLits.Presburger.Compat: instance GHC.Classes.Eq GHC.TypeLits.Presburger.Compat.TypeEq
+ GHC.TypeLits.Presburger.Compat: instance GHC.Classes.Ord GHC.TypeLits.Presburger.Compat.TypeEq
+ GHC.TypeLits.Presburger.Compat: instance Outputable.Outputable GHC.TypeLits.Presburger.Compat.TvSubst
+ GHC.TypeLits.Presburger.Compat: isAbstractTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isAlgTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isBoxedTupleTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isBuiltInSynFamTyCon_maybe :: TyCon -> Maybe BuiltInSynFamily
+ GHC.TypeLits.Presburger.Compat: isClassTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isClosedSynFamilyTyConWithAxiom_maybe :: TyCon -> Maybe (CoAxiom Branched)
+ GHC.TypeLits.Presburger.Compat: isDataFamilyTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isDataProductTyCon_maybe :: TyCon -> Maybe DataCon
+ GHC.TypeLits.Presburger.Compat: isDataSumTyCon_maybe :: TyCon -> Maybe [DataCon]
+ GHC.TypeLits.Presburger.Compat: isDataTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isEnumerationTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isEqPred :: PredType -> Bool
+ GHC.TypeLits.Presburger.Compat: isFamFreeTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isFamInstTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isFamilyTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isFunTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isGadtSyntaxTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isGcPtrRep :: PrimRep -> Bool
+ GHC.TypeLits.Presburger.Compat: isGenInjAlgRhs :: AlgTyConRhs -> Bool
+ GHC.TypeLits.Presburger.Compat: isGenerativeTyCon :: TyCon -> Role -> Bool
+ GHC.TypeLits.Presburger.Compat: isImplicitTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isInjectiveTyCon :: TyCon -> Role -> Bool
+ GHC.TypeLits.Presburger.Compat: isInvisibleTyConBinder :: () => TyVarBndr tv TyConBndrVis -> Bool
+ GHC.TypeLits.Presburger.Compat: isKindTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isLiftedTypeKindTyConName :: Name -> Bool
+ GHC.TypeLits.Presburger.Compat: isNamedTyConBinder :: TyConBinder -> Bool
+ GHC.TypeLits.Presburger.Compat: isNewTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isNoParent :: AlgTyConFlav -> Bool
+ GHC.TypeLits.Presburger.Compat: isOpenFamilyTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isOpenTypeFamilyTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isPrimTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isProductTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isPromotedDataCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isPromotedDataCon_maybe :: TyCon -> Maybe DataCon
+ GHC.TypeLits.Presburger.Compat: isPromotedTupleTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTauTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTcLevPoly :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTcTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTrivial :: PredType -> Bool
+ GHC.TypeLits.Presburger.Compat: isTupleTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTyConAssoc :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTyConWithSrcDataCons :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTypeFamilyTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isTypeSynonymTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isUnboxedSumTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isUnboxedTupleTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isUnliftedTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isVanillaAlgTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: isVisibleTyConBinder :: () => TyVarBndr tv TyConBndrVis -> Bool
+ GHC.TypeLits.Presburger.Compat: isVoidRep :: PrimRep -> Bool
+ GHC.TypeLits.Presburger.Compat: isWanted :: CtEvidence -> Bool
+ GHC.TypeLits.Presburger.Compat: lookupModule :: ModuleName -> FastString -> TcPluginM Module
+ GHC.TypeLits.Presburger.Compat: lookupName :: Module -> OccName -> TcPluginM Name
+ GHC.TypeLits.Presburger.Compat: lookupTyCon :: MonadThings m => Name -> m TyCon
+ GHC.TypeLits.Presburger.Compat: lookupTyConFieldLabel :: FieldLabelString -> TyCon -> Maybe FieldLabel
+ GHC.TypeLits.Presburger.Compat: makeInjectivityErrors :: () => CoAxiom br -> CoAxBranch -> [Bool] -> [CoAxBranch] -> [(SDoc, SrcSpan)]
+ GHC.TypeLits.Presburger.Compat: makeRecoveryTyCon :: TyCon -> TyCon
+ GHC.TypeLits.Presburger.Compat: mightBeUnsaturatedTyCon :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: mkAlgTyCon :: Name -> [TyConBinder] -> Kind -> [Role] -> Maybe CType -> [PredType] -> AlgTyConRhs -> AlgTyConFlav -> Bool -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkAnonTyConBinder :: TyVar -> TyConBinder
+ GHC.TypeLits.Presburger.Compat: mkAnonTyConBinders :: [TyVar] -> [TyConBinder]
+ GHC.TypeLits.Presburger.Compat: mkClassTyCon :: Name -> [TyConBinder] -> [Role] -> AlgTyConRhs -> Class -> Name -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkDataTyConRhs :: [DataCon] -> AlgTyConRhs
+ GHC.TypeLits.Presburger.Compat: mkFamilyTyCon :: Name -> [TyConBinder] -> Kind -> Maybe Name -> FamTyConFlav -> Maybe Class -> Injectivity -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkFunTyCon :: Name -> [TyConBinder] -> Name -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkInstTyTcOcc :: String -> OccSet -> OccName
+ GHC.TypeLits.Presburger.Compat: mkKindTyCon :: Name -> [TyConBinder] -> Kind -> [Role] -> Name -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkLiftedPrimTyCon :: Name -> [TyConBinder] -> Kind -> [Role] -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkModuleName :: String -> ModuleName
+ GHC.TypeLits.Presburger.Compat: mkNamedTyConBinder :: ArgFlag -> TyVar -> TyConBinder
+ GHC.TypeLits.Presburger.Compat: mkNamedTyConBinders :: ArgFlag -> [TyVar] -> [TyConBinder]
+ GHC.TypeLits.Presburger.Compat: mkPrelTyConRepName :: Name -> TyConRepName
+ GHC.TypeLits.Presburger.Compat: mkPrimTyCon :: Name -> [TyConBinder] -> Kind -> [Role] -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkPromotedDataCon :: DataCon -> Name -> TyConRepName -> [TyConBinder] -> Kind -> [Role] -> RuntimeRepInfo -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkSubstitution :: [Ct] -> Substitution
+ GHC.TypeLits.Presburger.Compat: mkSumTyCon :: Name -> [TyConBinder] -> Kind -> Arity -> [TyVar] -> [DataCon] -> AlgTyConFlav -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkSynonymTyCon :: Name -> [TyConBinder] -> Kind -> [Role] -> Type -> Bool -> Bool -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkTcOcc :: String -> OccName
+ GHC.TypeLits.Presburger.Compat: mkTcTyCon :: Name -> SDoc -> [TyConBinder] -> Kind -> [(Name, TcTyVar)] -> TyConFlavour -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkTupleTyCon :: Name -> [TyConBinder] -> Kind -> Arity -> DataCon -> TupleSort -> AlgTyConFlav -> TyCon
+ GHC.TypeLits.Presburger.Compat: mkTyConKind :: [TyConBinder] -> Kind -> Kind
+ GHC.TypeLits.Presburger.Compat: mkTyConTagMap :: TyCon -> NameEnv ConTag
+ GHC.TypeLits.Presburger.Compat: mkTyConTy :: TyCon -> Type
+ GHC.TypeLits.Presburger.Compat: newFamInst :: FamFlavor -> CoAxiom Unbranched -> TcM FamInst
+ GHC.TypeLits.Presburger.Compat: newTyConCo :: TyCon -> CoAxiom Unbranched
+ GHC.TypeLits.Presburger.Compat: newTyConCo_maybe :: TyCon -> Maybe (CoAxiom Unbranched)
+ GHC.TypeLits.Presburger.Compat: newTyConDataCon_maybe :: TyCon -> Maybe DataCon
+ GHC.TypeLits.Presburger.Compat: newTyConEtadArity :: TyCon -> Int
+ GHC.TypeLits.Presburger.Compat: newTyConEtadRhs :: TyCon -> ([TyVar], Type)
+ GHC.TypeLits.Presburger.Compat: newTyConRhs :: TyCon -> ([TyVar], Type)
+ GHC.TypeLits.Presburger.Compat: newtype TypeEq
+ GHC.TypeLits.Presburger.Compat: normaliseGivens :: [Ct] -> TcPluginM [Ct]
+ GHC.TypeLits.Presburger.Compat: ppr :: Outputable a => a -> SDoc
+ GHC.TypeLits.Presburger.Compat: pprPromotionQuote :: TyCon -> SDoc
+ GHC.TypeLits.Presburger.Compat: primElemRepSizeB :: PrimElemRep -> Int
+ GHC.TypeLits.Presburger.Compat: primRepIsFloat :: PrimRep -> Maybe Bool
+ GHC.TypeLits.Presburger.Compat: primRepSizeB :: DynFlags -> PrimRep -> Int
+ GHC.TypeLits.Presburger.Compat: promotedBoolTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: promotedFalseDataCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: promotedTrueDataCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: splitTyConApp_maybe :: HasDebugCallStack -> Type -> Maybe (TyCon, [Type])
+ GHC.TypeLits.Presburger.Compat: subsCt :: Substitution -> Ct -> Ct
+ GHC.TypeLits.Presburger.Compat: subsType :: Substitution -> Type -> Type
+ GHC.TypeLits.Presburger.Compat: substTy :: TvSubst -> Type -> Type
+ GHC.TypeLits.Presburger.Compat: synTyConDefn_maybe :: TyCon -> Maybe ([TyVar], Type)
+ GHC.TypeLits.Presburger.Compat: synTyConRhs_maybe :: TyCon -> Maybe Type
+ GHC.TypeLits.Presburger.Compat: tcExtendLocalFamInstEnv :: () => [FamInst] -> TcM a -> TcM a
+ GHC.TypeLits.Presburger.Compat: tcFlavourCanBeUnsaturated :: TyConFlavour -> Bool
+ GHC.TypeLits.Presburger.Compat: tcFlavourIsOpen :: TyConFlavour -> Bool
+ GHC.TypeLits.Presburger.Compat: tcGetFamInstEnvs :: TcM FamInstEnvs
+ GHC.TypeLits.Presburger.Compat: tcInferApps :: TcTyMode -> Maybe (VarEnv Kind) -> LHsType GhcRn -> TcType -> TcKind -> [LHsType GhcRn] -> TcM (TcType, [TcType], TcKind)
+ GHC.TypeLits.Presburger.Compat: tcInstNewTyCon_maybe :: TyCon -> [TcType] -> Maybe (TcType, TcCoercion)
+ GHC.TypeLits.Presburger.Compat: tcLookupDataFamInst :: FamInstEnvs -> TyCon -> [TcType] -> (TyCon, [TcType], Coercion)
+ GHC.TypeLits.Presburger.Compat: tcLookupDataFamInst_maybe :: FamInstEnvs -> TyCon -> [TcType] -> Maybe (TyCon, [TcType], Coercion)
+ GHC.TypeLits.Presburger.Compat: tcLookupTyCon :: Name -> TcPluginM TyCon
+ GHC.TypeLits.Presburger.Compat: tcPluginTrace :: String -> SDoc -> TcPluginM ()
+ GHC.TypeLits.Presburger.Compat: tcTopNormaliseNewTypeTF_maybe :: FamInstEnvs -> GlobalRdrEnv -> Type -> Maybe ((Bag GlobalRdrElt, TcCoercion), Type)
+ GHC.TypeLits.Presburger.Compat: tcTyFamInsts :: Type -> [(TyCon, [Type])]
+ GHC.TypeLits.Presburger.Compat: tcUnifyTy :: Type -> Type -> Maybe TvSubst
+ GHC.TypeLits.Presburger.Compat: text :: String -> SDoc
+ GHC.TypeLits.Presburger.Compat: toTCv :: TvSubst -> TCvSubst
+ GHC.TypeLits.Presburger.Compat: tracePlugin :: String -> TcPlugin -> TcPlugin
+ GHC.TypeLits.Presburger.Compat: tyConATs :: TyCon -> [TyCon]
+ GHC.TypeLits.Presburger.Compat: tyConAppTyCon_maybe :: Type -> Maybe TyCon
+ GHC.TypeLits.Presburger.Compat: tyConAssoc_maybe :: TyCon -> Maybe Class
+ GHC.TypeLits.Presburger.Compat: tyConBinderArgFlag :: TyConBinder -> ArgFlag
+ GHC.TypeLits.Presburger.Compat: tyConBndrVisArgFlag :: TyConBndrVis -> ArgFlag
+ GHC.TypeLits.Presburger.Compat: tyConCType_maybe :: TyCon -> Maybe CType
+ GHC.TypeLits.Presburger.Compat: tyConClass_maybe :: TyCon -> Maybe Class
+ GHC.TypeLits.Presburger.Compat: tyConDataCons :: TyCon -> [DataCon]
+ GHC.TypeLits.Presburger.Compat: tyConDataCons_maybe :: TyCon -> Maybe [DataCon]
+ GHC.TypeLits.Presburger.Compat: tyConFamInstSig_maybe :: TyCon -> Maybe (TyCon, [Type], CoAxiom Unbranched)
+ GHC.TypeLits.Presburger.Compat: tyConFamInst_maybe :: TyCon -> Maybe (TyCon, [Type])
+ GHC.TypeLits.Presburger.Compat: tyConFamilyCoercion_maybe :: TyCon -> Maybe (CoAxiom Unbranched)
+ GHC.TypeLits.Presburger.Compat: tyConFamilyResVar_maybe :: TyCon -> Maybe Name
+ GHC.TypeLits.Presburger.Compat: tyConFamilySize :: TyCon -> Int
+ GHC.TypeLits.Presburger.Compat: tyConFieldLabels :: TyCon -> [FieldLabel]
+ GHC.TypeLits.Presburger.Compat: tyConFlavour :: TyCon -> TyConFlavour
+ GHC.TypeLits.Presburger.Compat: tyConInjectivityInfo :: TyCon -> Injectivity
+ GHC.TypeLits.Presburger.Compat: tyConRepModOcc :: Module -> OccName -> (Module, OccName)
+ GHC.TypeLits.Presburger.Compat: tyConRepName_maybe :: TyCon -> Maybe TyConRepName
+ GHC.TypeLits.Presburger.Compat: tyConRoles :: TyCon -> [Role]
+ GHC.TypeLits.Presburger.Compat: tyConRuntimeRepInfo :: TyCon -> RuntimeRepInfo
+ GHC.TypeLits.Presburger.Compat: tyConSingleAlgDataCon_maybe :: TyCon -> Maybe DataCon
+ GHC.TypeLits.Presburger.Compat: tyConSingleDataCon :: TyCon -> DataCon
+ GHC.TypeLits.Presburger.Compat: tyConSingleDataCon_maybe :: TyCon -> Maybe DataCon
+ GHC.TypeLits.Presburger.Compat: tyConSkolem :: TyCon -> Bool
+ GHC.TypeLits.Presburger.Compat: tyConStupidTheta :: TyCon -> [PredType]
+ GHC.TypeLits.Presburger.Compat: tyConTuple_maybe :: TyCon -> Maybe TupleSort
+ GHC.TypeLits.Presburger.Compat: tyConTyVarBinders :: [TyConBinder] -> [TyVarBinder]
+ GHC.TypeLits.Presburger.Compat: tyConVisibleTyVars :: TyCon -> [TyVar]
+ GHC.TypeLits.Presburger.Compat: type FamInstEnvs = (FamInstEnv, FamInstEnv)
+ GHC.TypeLits.Presburger.Compat: type Substitution = [(TcTyVar, TcType)]
+ GHC.TypeLits.Presburger.Compat: type TvSubstEnv = TyVarEnv Type
+ GHC.TypeLits.Presburger.Compat: type TyConBinder = TyVarBndr TyVar TyConBndrVis
+ GHC.TypeLits.Presburger.Compat: type TyConRepName = Name
+ GHC.TypeLits.Presburger.Compat: typeKind :: HasDebugCallStack -> Type -> Kind
+ GHC.TypeLits.Presburger.Compat: typeNatAddTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatCmpTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatCoAxiomRules :: Map FastString CoAxiomRule
+ GHC.TypeLits.Presburger.Compat: typeNatDivTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatExpTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatKind :: Kind
+ GHC.TypeLits.Presburger.Compat: typeNatLeqTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatLogTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatModTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatMulTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatSubTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeNatTyCons :: [TyCon]
+ GHC.TypeLits.Presburger.Compat: typeSymbolAppendTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: typeSymbolCmpTyCon :: TyCon
+ GHC.TypeLits.Presburger.Compat: unionTCvSubst :: TCvSubst -> TCvSubst -> TCvSubst
+ GHC.TypeLits.Presburger.Compat: unionTvSubst :: TvSubst -> TvSubst -> TvSubst
+ GHC.TypeLits.Presburger.Compat: unwrapNewTyConEtad_maybe :: TyCon -> Maybe ([TyVar], Type, CoAxiom Unbranched)
+ GHC.TypeLits.Presburger.Compat: unwrapNewTyCon_maybe :: TyCon -> Maybe ([TyVar], Type, CoAxiom Unbranched)
+ GHC.TypeLits.Presburger.Compat: viewFunTy :: Type -> Maybe (Type, Type)
+ GHC.TypeLits.Presburger.Compat: visibleDataCons :: AlgTyConRhs -> [DataCon]
+ GHC.TypeLits.Presburger.Types: (:&&) :: Prop -> Prop -> Prop
+ GHC.TypeLits.Presburger.Types: (:*) :: Integer -> Expr -> Expr
+ GHC.TypeLits.Presburger.Types: (:+) :: Expr -> Expr -> Expr
+ GHC.TypeLits.Presburger.Types: (:-) :: Expr -> Expr -> Expr
+ GHC.TypeLits.Presburger.Types: (:/=) :: Expr -> Expr -> Prop
+ GHC.TypeLits.Presburger.Types: (:<) :: Expr -> Expr -> Prop
+ GHC.TypeLits.Presburger.Types: (:<=) :: Expr -> Expr -> Prop
+ GHC.TypeLits.Presburger.Types: (:==) :: Expr -> Expr -> Prop
+ GHC.TypeLits.Presburger.Types: (:>) :: Expr -> Expr -> Prop
+ GHC.TypeLits.Presburger.Types: (:>=) :: Expr -> Expr -> Prop
+ GHC.TypeLits.Presburger.Types: (:||) :: Prop -> Prop -> Prop
+ GHC.TypeLits.Presburger.Types: Div :: Expr -> Integer -> Expr
+ GHC.TypeLits.Presburger.Types: If :: Prop -> Expr -> Expr -> Expr
+ GHC.TypeLits.Presburger.Types: K :: Integer -> Expr
+ GHC.TypeLits.Presburger.Types: Mod :: Expr -> Integer -> Expr
+ GHC.TypeLits.Presburger.Types: Negate :: Expr -> Expr
+ GHC.TypeLits.Presburger.Types: Not :: Prop -> Prop
+ GHC.TypeLits.Presburger.Types: PFalse :: Prop
+ GHC.TypeLits.Presburger.Types: PTrue :: Prop
+ GHC.TypeLits.Presburger.Types: Translation :: [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> [TyCon] -> ((Type -> Machine Expr) -> Type -> Machine Prop) -> (Type -> Machine Expr) -> Translation
+ GHC.TypeLits.Presburger.Types: Var :: Name -> Expr
+ GHC.TypeLits.Presburger.Types: [falseData] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [isEmpty] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [isTrue] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natCompare] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natExp] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natGeqBool] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natGeq] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natGtBool] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natGt] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natLeqBool] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natLeq] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natLtBool] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natLt] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natMinus] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natPlus] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [natTimes] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [orderingEQ] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [orderingGT] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [orderingLT] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [parseExpr] :: Translation -> Type -> Machine Expr
+ GHC.TypeLits.Presburger.Types: [parsePred] :: Translation -> (Type -> Machine Expr) -> Type -> Machine Prop
+ GHC.TypeLits.Presburger.Types: [trueData] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [tyEqBool] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [tyEqWitness] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [tyEq] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [tyNeqBool] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: [voids] :: Translation -> [TyCon]
+ GHC.TypeLits.Presburger.Types: assert :: Prop -> PropSet -> PropSet
+ GHC.TypeLits.Presburger.Types: checkSat :: PropSet -> Maybe [(Int, Integer)]
+ GHC.TypeLits.Presburger.Types: data Expr
+ GHC.TypeLits.Presburger.Types: data Prop
+ GHC.TypeLits.Presburger.Types: data PropSet
+ GHC.TypeLits.Presburger.Types: data Translation
+ GHC.TypeLits.Presburger.Types: defaultTranslation :: TcPluginM Translation
+ GHC.TypeLits.Presburger.Types: infix 4 :>=
+ GHC.TypeLits.Presburger.Types: infixl 6 :-
+ GHC.TypeLits.Presburger.Types: infixl 7 :*
+ GHC.TypeLits.Presburger.Types: infixr 2 :||
+ GHC.TypeLits.Presburger.Types: infixr 3 :&&
+ GHC.TypeLits.Presburger.Types: instance GHC.Base.Monoid GHC.TypeLits.Presburger.Types.Translation
+ GHC.TypeLits.Presburger.Types: instance GHC.Base.Semigroup GHC.TypeLits.Presburger.Types.Translation
+ GHC.TypeLits.Presburger.Types: instance GHC.Classes.Eq GHC.TypeLits.Presburger.Types.PluginMode
+ GHC.TypeLits.Presburger.Types: instance GHC.Classes.Eq GHC.TypeLits.Presburger.Types.Proof
+ GHC.TypeLits.Presburger.Types: instance GHC.Classes.Ord GHC.TypeLits.Presburger.Types.PluginMode
+ GHC.TypeLits.Presburger.Types: instance GHC.Classes.Ord GHC.TypeLits.Presburger.Types.Proof
+ GHC.TypeLits.Presburger.Types: instance GHC.Read.Read GHC.TypeLits.Presburger.Types.PluginMode
+ GHC.TypeLits.Presburger.Types: instance GHC.Read.Read GHC.TypeLits.Presburger.Types.Proof
+ GHC.TypeLits.Presburger.Types: instance GHC.Show.Show GHC.TypeLits.Presburger.Types.PluginMode
+ GHC.TypeLits.Presburger.Types: instance GHC.Show.Show GHC.TypeLits.Presburger.Types.Proof
+ GHC.TypeLits.Presburger.Types: noProps :: PropSet
+ GHC.TypeLits.Presburger.Types: pluginWith :: TcPluginM Translation -> Plugin
+ GHC.TypeLits.Presburger.Types: toName :: Int -> Name
+ GHC.TypeLits.Presburger.Types: type Machine = MaybeT (StateT ParseEnv TcPluginM)
+ GHC.TypeLits.Presburger.Types: type ParseEnv = Map TypeEq TyVar

Files

+ examples/simple-arith-core.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE CPP, DataKinds, EmptyCase, FlexibleContexts, GADTs, LambdaCase #-}+{-# LANGUAGE PolyKinds, ScopedTypeVariables, TypeFamilies, TypeInType       #-}+{-# LANGUAGE TypeOperators, UndecidableInstances                            #-}+{-# OPTIONS_GHC -dcore-lint #-}+{-# OPTIONS_GHC -fplugin GHC.TypeLits.Presburger #-}++#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE NoStarIsType #-}+#endif++module Main where+import Data.Proxy+import Data.Type.Equality+import GHC.TypeLits+import Proof.Propositional (Empty (..), withEmpty)+import Proof.Propositional (IsTrue (Witness))++type n <=! m = IsTrue (n <=? m)+infix 4 <=!++type family Length (as :: [k]) where+  Length '[] = 0+  Length (x ': xs) = 1 + Length xs++natLen :: (Length xs <= Length ys)+       => proxy xs -> proxy ys -> (Length ys - Length xs) + Length xs :~: Length ys+natLen _ _ = Refl++natLeqZero' :: (n <= 0) => proxy n -> n :~: 0+natLeqZero' _ = Refl++leqSucc :: proxy n -> proxy m -> IsTrue ((n + 1) <=? m) -> CmpNat n m :~: 'LT+leqSucc _ _ Witness = Refl++leqEquiv :: (n <= m) => p n -> p m -> IsTrue (n <=? m)+leqEquiv _ _ = Witness+++plusLeq :: (n <= m) => proxy (n :: Nat) -> proxy m -> ((m - n) + n :~: m)+plusLeq _ _ = Refl++minusLeq :: (n <= m) => proxy (n :: Nat) -> proxy m -> IsTrue ((m - n) + n <=? m)+minusLeq _ _ = Witness++absurdTrueFalse :: ('True :~: 'False) -> a+absurdTrueFalse = \case {}++#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ > 802+hoge :: proxy n -> IsTrue (n + 1 <=? n) -> a+hoge _ Witness = absurdTrueFalse Refl+#endif++bar :: ((2 * (n + 1)) ~ ((2 * n) + 2)) => proxy n -> ()+bar _ = ()++barResult :: ()+barResult = bar (Proxy :: Proxy 2)+++trans :: proxy n -> proxy m -> n <=! m -> (n + 1) <=! (m + 1)+trans _ _  Witness = Witness++eqv :: proxy n -> proxy m -> (n <=? m) :~: ((n + 1) <=? (m + 1))+eqv _ _ = Refl++predSucc :: forall proxy n. Empty (n <=! 0) => proxy n -> IsTrue (n + 1 <=? 2 * n)+predSucc _ = Witness+++succLEqLTSucc :: pxy m -> CmpNat 0 (m + 1) :~: 'LT+succLEqLTSucc _ = Refl++succCompare :: pxy n -> pxy m -> CmpNat n m :~: CmpNat (n + 1) (m + 1)+succCompare _ _ = Refl++eqToRefl :: pxy n -> pxy m -> CmpNat n m :~: 'EQ -> n :~: m+eqToRefl _n _m Refl = Refl++main :: IO ()+main = putStrLn "finished"
− examples/simple-arith.hs
@@ -1,77 +0,0 @@-{-# LANGUAGE DataKinds, TypeOperators, GADTs, TypeFamilies, ExplicitForAll, FlexibleContexts #-}-{-# LANGUAGE ScopedTypeVariables, CPP #-}-#if !MIN_VERSION_singletons(2,4,1)-{-# LANGUAGE KindSignatures #-}-#endif-{-# OPTIONS_GHC -fplugin GHC.TypeLits.Presburger #-}-module Main where-import Data.Type.Equality-import GHC.TypeLits       (Nat, type (<=?), CmpNat)-import Proof.Propositional (Empty(..))-import Proof.Propositional (IsTrue(Witness))-import Data.Singletons.Prelude-import Data.Singletons.Prelude.List--#if !MIN_VERSION_singletons(2,4,1)-import qualified Data.Singletons.Prelude as Sing-type n <= m = (n :: Nat) Sing.:<= (m :: Nat)-infix 4 <=-type n - m = (n :: Nat) Sing.:- (m :: Nat)-infixl 6 --type n + m = (n :: Nat) Sing.:+ (m :: Nat)-infixl 6 +-type n * m = (n :: Nat) Sing.:* (m :: Nat)-infixl 7 *-#endif--type n <=! m = IsTrue (n <=? m)-infix 4 <=!--natLen :: (Length xs <= Length ys) ~ 'True-       => proxy xs -> proxy ys -> Length ys - Length xs + Length xs :~: Length ys-natLen _ _ = Refl--natLeqZero' :: ((n <= 0) ~ 'True) => proxy n -> n :~: 0-natLeqZero' _ = Refl--plusLeq :: (n <= m) ~ 'True => proxy (n :: Nat) -> proxy m -> ((m - n) + n :~: m)-plusLeq _ _ = Refl--(%:<=?) :: Sing n -> Sing m -> Sing (n <=? m)-n %:<=? m = case sCompare n m of-  SLT -> STrue-  SEQ -> STrue-  SGT -> SFalse--hoge :: ((n + 1 <=? n) ~ 'False) => proxy n -> ()-hoge _ = ()--hoge' :: (((n + 1) <= n) ~ 'False) => proxy n -> ()-hoge' _ = ()--bar :: ((2 * (n + 1)) ~ ((2 * n) + 2)) => proxy n -> ()-bar _ = ()--trans :: proxy n -> proxy m -> n <=! m -> (n + 1) <=! (m + 1)-trans _ _  Witness = Witness--eqv :: proxy n -> proxy m -> (n <=? m) :~: ((n + 1) <=? (m + 1))-eqv _ _ = Refl--leqSucc :: proxy n -> proxy m -> IsTrue ((n + 1) <= m) -> CmpNat n m :~: 'LT-leqSucc _ _ Witness = Refl--predSucc :: forall proxy n. Empty (n <=! 0) => proxy n -> IsTrue (n + 1 <=? 2 * n)-predSucc _ = Witness--main :: IO ()-main = putStrLn "finished"--succLEqLTSucc :: Sing m -> Compare 0 (m + 1) :~: 'LT-succLEqLTSucc _ = Refl--succCompare :: Sing (n :: Nat) -> Sing m -> CmpNat n m :~: CmpNat (n + 1) (m + 1)-succCompare _ _ = Refl--eqToRefl :: Sing (n :: Nat) -> Sing (m :: Nat) -> CmpNat n m :~: 'EQ -> n :~: m-eqToRefl _n _m Refl = Refl
ghc-typelits-presburger.cabal view
@@ -1,61 +1,80 @@-name:                ghc-typelits-presburger-version:             0.2.0.5-synopsis:            Presburger Arithmetic Solver for GHC Type-level natural numbers.-description: -  @ghc-typelits-presburger@ augments GHC type-system with Presburger Arithmetic Solver for Type-level natural numbers.-  You can use by adding this package to @build-depends@ and add the following pragma to the head of .hs files:-  .-  > OPTIONS_GHC -fplugin GHC.TypeLits.Presburger-                  -homepage:            https://github.com/konn/ghc-typelits-presburger#readme-license:             BSD3-license-file:        LICENSE-author:              Hiromi ISHII-maintainer:          konn.jinro _at_ gmail.com-copyright:           2015 (c) Hiromi ISHII-category:            Math, Type System-build-type:          Simple--- extra-source-files:-cabal-version:       >=1.10-tested-with:         GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.3--flag examples-    Default: False+cabal-version: 1.12 -library-  ghc-options:         -Wall -Wno-dodgy-imports-  hs-source-dirs:      src-                     , presburger/src-  exposed-modules:     GHC.TypeLits.Presburger-  other-modules:       GHC.Compat-                       Data.Integer.SAT-  build-depends:       base                 >= 4.7  && < 5-                     , ghc                  >= 7.10 && < 8.5-                     , ghc-tcplugins-extra  >= 0.2  && < 0.4-                     , equational-reasoning >= 0.4.0.0-                     , singletons-                     , transformers-                     , mtl-                     , containers-                     , pretty-                     , syb-                     , reflection-  default-language:    Haskell2010+-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 213617ccefa67bad574a0687988e14cef38a75e07ac2e08140bcda55feeee3f6 -executable simple-arith-  if flag(examples)-    buildable:         True-  else-    buildable:         False-  hs-source-dirs:      examples-  Main-is:             simple-arith.hs-  build-depends:       base-                     , ghc-typelits-presburger-                     , equational-reasoning-                     , singletons-  default-language:    Haskell2010-  ghc-options:         -Wall -Wno-dodgy-imports -Wno-unused-imports+name:           ghc-typelits-presburger+version:        0.3.0.0+synopsis:       Presburger Arithmetic Solver for GHC Type-level natural numbers.+description:    @ghc-typelits-presburger@ augments GHC type-system with Presburger+                Arithmetic Solver for Type-level natural numbers.+                This plugin only work with GHC builtin operations.+                To work with those of @singletons@ package, use @ghc-typelits-meta@ and/or @ghc-typelits-presburger@ instead.+                .+                Since 0.3.0.0, integration with <https://hackage.haskell.org/package/singletons singletons> package moves to <https://hackage.haskell.org/package/singletons-presburger singletons-presburger>.+                .+                You can use by adding this package to @build-depends@ and add the following pragma+                to the head of .hs files:+                .+                .+                > OPTIONS_GHC -fplugin GHC.TypeLits.Presburger+category:       Math, Type System+homepage:       https://github.com/konn/ghc-typelits-presburger#readme+bug-reports:    https://github.com/konn/ghc-typelits-presburger/issues+author:         Hiromi ISHII+maintainer:     konn.jinro _at_ gmail.com+copyright:      2015 (c) Hiromi ISHII+license:        BSD3+license-file:   LICENSE+tested-with:    GHC==8.4.3 GHC==8.6.3 GHC==8.8.2+build-type:     Simple  source-repository head-  type:     git+  type: git   location: https://github.com/konn/ghc-typelits-presburger++flag examples+  description: Builds example+  manual: False+  default: False++library+  exposed-modules:+      GHC.TypeLits.Presburger.Types+      GHC.TypeLits.Presburger+      GHC.TypeLits.Presburger.Compat+  other-modules:+      Data.Integer.SAT+      Paths_ghc_typelits_presburger+  hs-source-dirs:+      src+  ghc-options: -Wall -Wno-dodgy-imports+  build-depends:+      base >=4.7 && <5+    , containers+    , ghc >=7.10 && <8.11+    , ghc-tcplugins-extra >=0.2 && <0.4+    , mtl+    , pretty+    , reflection+    , syb+    , transformers+  default-language: Haskell2010++executable simple-arith-core+  main-is: simple-arith-core.hs+  other-modules:+      Paths_ghc_typelits_presburger+  hs-source-dirs:+      examples+  ghc-options: -Wall -Wno-dodgy-imports -Wno-unused-imports+  build-depends:+      base+    , equational-reasoning+    , ghc-typelits-presburger+  if !(flag(examples))+    buildable: False+  default-language: Haskell2010
− presburger/src/Data/Integer/SAT.hs
@@ -1,981 +0,0 @@-{-# LANGUAGE BangPatterns, PatternGuards, Trustworthy #-}-{-|-This module implements a decision procedure for quantifier-free linear-arithmetic.  The algorithm is based on the following paper:--  An Online Proof-Producing Decision Procedure for-  Mixed-Integer Linear Arithmetic-  by-  Sergey Berezin, Vijay Ganesh, and David L. Dill--}-module Data.Integer.SAT-  ( PropSet-  , noProps-  , checkSat-  , assert-  , Prop(..)-  , Expr(..)-  , BoundType(..)-  , getExprBound-  , getExprRange-  , Name-  , toName-  , fromName-  -- * Iterators-  , allSolutions-  , slnCurrent-  , slnNextVal-  , slnNextVar-  , slnEnumerate---  -- * Debug-  , dotPropSet-  , sizePropSet-  , allInerts-  , ppInerts--  -- * For QuickCheck-  , iPickBounded-  , Bound(..)-  , tConst-  ) where--import Debug.Trace--import           Control.Applicative (Alternative (..), Applicative (..), (<$>))-import           Control.Monad       (MonadPlus (..), ap, guard, liftM)-import           Data.List           (partition)-import           Data.Map            (Map)-import qualified Data.Map            as Map-import           Data.Maybe          (fromMaybe, mapMaybe, maybeToList)-import           Prelude             hiding ((<>))-import           Text.PrettyPrint--infixr 2 :||-infixr 3 :&&-infix  4 :==, :/=, :<, :<=, :>, :>=-infixl 6 :+, :--infixl 7 :*------------------------------------------------------------------------------------- Solver interface---- | A collection of propositions.-newtype PropSet = State (Answer RW)-                  deriving Show--dotPropSet :: PropSet -> Doc-dotPropSet (State a) = dotAnswer (ppInerts . inerts) a--sizePropSet :: PropSet -> (Integer,Integer,Integer)-sizePropSet (State a) = answerSize a---- | An empty collection of propositions.-noProps :: PropSet-noProps = State $ return initRW---- | Add a new proposition to an existing collection.-assert :: Prop -> PropSet -> PropSet-assert p (State rws) = State $ fmap snd $ m =<< rws-  where S m = prop p---- | Extract a model from a consistent set of propositions.--- Returns 'Nothing' if the assertions have no model.--- If a variable does not appear in the assignment, then it is 0 (?).-checkSat :: PropSet -> Maybe [(Int,Integer)]-checkSat (State m) = go m-  where-  go None           = mzero-  go (One rw)       = return [ (x,v) | (UserName x, v) <- iModel (inerts rw) ]-  go (Choice m1 m2) = mplus (go m1) (go m2)--allInerts :: PropSet -> [Inerts]-allInerts (State m) = map inerts (toList m)--allSolutions :: PropSet -> [Solutions]-allSolutions = map startIter . allInerts----- | Computes bounds on the expression that are compatible with the model.--- Returns `Nothing` if the bound is not known.-getExprBound :: BoundType -> Expr -> PropSet -> Maybe Integer-getExprBound bt e (State s) =-  do let S m          = expr e-         check (t,s1) = iTermBound bt t (inerts s1)-     bs <- mapM check $ toList $ s >>= m-     case bs of-       [] -> Nothing-       _  -> Just (maximum bs)---- | Compute the range of possible values for an expression.--- Returns `Nothing` if the bound is not known.-getExprRange :: Expr -> PropSet -> Maybe [Integer]-getExprRange e (State s) =-  do let S m          = expr e-         check (t,s1) = do l <- iTermBound Lower t (inerts s1)-                           u <- iTermBound Upper t (inerts s1)-                           return (l,u)-     bs <- mapM check $ toList $ s >>= m-     case bs of-       [] -> Nothing-       _  -> let (ls,us) = unzip bs-             in Just [ x | x <- [ minimum ls .. maximum us ] ]------ | The type of proposition.-data Prop = PTrue-          | PFalse-          | Prop :|| Prop-          | Prop :&& Prop-          | Not Prop-          | Expr :== Expr-          | Expr :/= Expr-          | Expr :<  Expr-          | Expr :>  Expr-          | Expr :<= Expr-          | Expr :>= Expr-            deriving (Read,Show)---- | The type of integer expressions.--- Variable names must be non-negative.-data Expr = Expr :+ Expr          -- ^ Addition-          | Expr :- Expr          -- ^ Subtraction-          | Integer :* Expr       -- ^ Multiplication by a constant-          | Negate Expr           -- ^ Negation-          | Var Name              -- ^ Variable-          | K Integer             -- ^ Constant-          | If Prop Expr Expr     -- ^ A conditional expression-          | Div Expr Integer      -- ^ Division, rounds down-          | Mod Expr Integer      -- ^ Non-negative remainder-            deriving (Read,Show)--prop :: Prop -> S ()-prop PTrue       = return ()-prop PFalse      = mzero-prop (p1 :|| p2) = prop p1 `mplus` prop p2-prop (p1 :&& p2) = prop p1 >> prop p2-prop (Not p)     = prop (neg p)-  where-  neg PTrue       = PFalse-  neg PFalse      = PTrue-  neg (p1 :&& p2) = neg p1 :|| neg p2-  neg (p1 :|| p2) = neg p1 :&& neg p2-  neg (Not q)     = q-  neg (e1 :== e2) = e1 :/= e2-  neg (e1 :/= e2) = e1 :== e2-  neg (e1 :<  e2) = e1 :>= e2-  neg (e1 :<= e2) = e1 :>  e2-  neg (e1 :>  e2) = e1 :<= e2-  neg (e1 :>= e2) = e1 :<  e2--prop (e1 :== e2) = do t1 <- expr e1-                      t2 <- expr e2-                      solveIs0 (t1 |-| t2)--prop (e1 :/= e2)  = do t1 <- expr e1-                       t2 <- expr e2-                       let t = t1 |-| t2-                       solveIsNeg t `orElse` solveIsNeg (tNeg t)--prop (e1 :< e2)   = do t1 <- expr e1-                       t2 <- expr e2-                       solveIsNeg (t1 |-| t2)--prop (e1 :<= e2)  = do t1 <- expr e1-                       t2 <- expr e2-                       let t = t1 |-| t2 |-| tConst 1-                       solveIsNeg t--prop (e1 :> e2)   = prop (e2 :<  e1)-prop (e1 :>= e2)  = prop (e2 :<= e1)---expr :: Expr -> S Term-expr (e1 :+ e2)   = (|+|)   <$> expr e1 <*> expr e2-expr (e1 :- e2)   = (|-|)   <$> expr e1 <*> expr e2-expr (k  :* e2)   = (k |*|) <$> expr e2-expr (Negate e)   = tNeg    <$> expr e-expr (Var x)      = pure (tVar x)-expr (K x)        = pure (tConst x)-expr (If p e1 e2) = do x <- newVar-                       prop (p :&& Var x :== e1 :|| Not p :&& Var x :== e2)-                       return (tVar x)-expr (Div e k)    = fmap fst $ exprDivMod e k-expr (Mod e k)    = fmap snd $ exprDivMod e k--exprDivMod :: Expr -> Integer -> S (Term,Term)-exprDivMod e k =-  do guard (k /= 0) -- Always unsat-     q <- newVar-     r <- newVar-     let er = Var r-     prop (k :* Var q :+ er :== e :&& er :< K k :&& K 0 :<= er)-     return (tVar q, tVar r)----------------------------------------------------------------------------------------data RW = RW { nameSource :: !Int-             , inerts     :: Inerts-             } deriving Show--initRW :: RW-initRW = RW { nameSource = 0, inerts = iNone }------------------------------------------------------------------------------------- Constraints and Bound on Variables--ctLt :: Term -> Term -> Term-ctLt t1 t2 = t1 |-| t2--ctEq :: Term -> Term -> Term-ctEq t1 t2 = t1 |-| t2--data Bound      = Bound Integer Term  -- ^ The integer is strictly positive-                  deriving Show--data BoundType  = Lower | Upper-                  deriving Show--toCt :: BoundType -> Name -> Bound -> Term-toCt Lower x (Bound c t) = ctLt t              (c |*| tVar x)-toCt Upper x (Bound c t) = ctLt (c |*| tVar x) t--------------------------------------------------------------------------------------- Inert set---- | The inert contains the solver state on one possible path.-data Inerts = Inerts-  { bounds :: NameMap ([Bound],[Bound])-    -- ^ Known lower and upper bounds for variables.-    -- Each bound @(c,t)@ in the first list asserts that  @t < c * x@-    -- Each bound @(c,t)@ in the second list asserts that @c * x < t@--  , solved :: NameMap Term-    -- ^ Definitions for resolved variables.-    -- These form an idempotent substitution.-  } deriving Show--ppInerts :: Inerts -> Doc-ppInerts is = vcat $ [ ppLower x b | (x,(ls,_)) <- bnds, b <- ls ] ++-                     [ ppUpper x b | (x,(_,us)) <- bnds, b <- us ] ++-                     [ ppEq e      | e <- Map.toList (solved is) ]-  where-  bnds = Map.toList (bounds is)--  ppT c x                = ppTerm (c |*| tVar x)-  ppLower x (Bound c t)  = ppTerm t <+> text "<" <+> ppT c x-  ppUpper x (Bound c t)  = ppT c x  <+> text "<" <+> ppTerm t-  ppEq (x,t)             = ppName x <+> text "=" <+> ppTerm t------ | An empty inert set.-iNone :: Inerts-iNone = Inerts { bounds = Map.empty-               , solved = Map.empty-               }---- | Rewrite a term using the definitions from an inert set.-iApSubst :: Inerts -> Term -> Term-iApSubst i t = foldr apS t $ Map.toList $ solved i-  where apS (x,t1) t2 = tLet x t1 t2---- | Add a definition.  Upper and lower bound constraints that mention--- the variable are "kicked-out" so that they can be reinserted in the--- context of the new knowledge.------    * Assumes substitution has already been applied.------    * The kicked-out constraints are NOT rewritten, this happens---      when they get inserted in the work queue.--iSolved :: Name -> Term -> Inerts -> ([Term], Inerts)-iSolved x t i =-  ( kickedOut-  , Inerts { bounds = otherBounds-           , solved = Map.insert x t $ Map.map (tLet x t) $ solved i-           }-  )-  where-  (kickedOut, otherBounds) =--        -- First, we eliminate all entries for `x`-    let (mb, mp1) = Map.updateLookupWithKey (\_ _ -> Nothing) x (bounds i)--        -- Next, we elminate all constraints that mentiond `x` in bounds-        mp2 = Map.mapWithKey extractBounds mp1--    in ( [ ct | (lbs,ubs) <- maybeToList mb-              ,  ct <- map (toCt Lower x) lbs ++ map (toCt Upper x) ubs ]-         ++-         [ ct | (_,cts) <- Map.elems mp2, ct <- cts ]--       , fmap fst mp2-       )--  extractBounds y (lbs,ubs) =-    let (lbsStay, lbsKick) = partition stay lbs-        (ubsStay, ubsKick) = partition stay ubs-    in ( (lbsStay,ubsStay)-       , map (toCt Lower y) lbsKick ++-         map (toCt Upper y) ubsKick-       )--  stay (Bound _ bnd) = not (tHasVar x bnd)----- | Given some lower and upper bounds, find the interval the satisfies them.--- Note the upper and lower bounds are strict (i.e., < and >)-boundInterval :: [Bound] -> [Bound] -> Maybe (Maybe Integer, Maybe Integer)-boundInterval lbs ubs =-  do ls <- mapM (normBound Lower) lbs-     us <- mapM (normBound Upper) ubs-     let lb = case ls of-                [] -> Nothing-                _  -> Just (maximum ls + 1)-         ub = case us of-                [] -> Nothing-                _  -> Just (minimum us - 1)-     case (lb,ub) of-       (Just l, Just u) -> guard (l <= u)-       _                -> return ()-     return (lb,ub)-  where-  normBound Lower (Bound c t) = do k <- isConst t-                                   return (div (k + c - 1) c)-  normBound Upper (Bound c t) = do k <- isConst t-                                   return (div k c)--data Solutions = Done-               | TopVar Name Integer (Maybe Integer) (Maybe Integer) Inerts-               | FixedVar Name Integer Solutions-                  deriving Show--slnCurrent :: Solutions -> [(Int,Integer)]-slnCurrent s = [ (x,v) | (UserName x, v) <- go s ]-  where-  go Done                = []-  go (TopVar x v _ _ is) = (x, v) : iModel (iLet x v is)-  go (FixedVar x v i)    = (x, v) : go i---- | Replace occurances of a variable with an integer.--- WARNING: The integer should be a valid value for the variable.-iLet :: Name -> Integer -> Inerts -> Inerts-iLet x v is = Inerts { bounds = fmap updBs (bounds is)-                     , solved = fmap (tLetNum x v) (solved is) }-  where-  updB (Bound c t) = Bound c (tLetNum x v t)-  updBs (ls,us)    = (map updB ls, map updB us)---startIter :: Inerts -> Solutions-startIter is =-  case Map.maxViewWithKey (bounds is) of-    Nothing ->-      case Map.maxViewWithKey (solved is) of-        Nothing -> Done-        Just ((x,t), mp1) ->-          case [ y | y <- tVarList t ] of-            y : _ -> TopVar y 0 Nothing Nothing is-            [] -> let v = tConstPart t-                  in TopVar x v (Just v) (Just v) $ is { solved = mp1 }-    Just ((x,(lbs,ubs)), mp1) ->-      case [ y | Bound _ t <- lbs ++ ubs, y <- tVarList t ] of-        y : _ -> TopVar y 0 Nothing Nothing is-        [] -> case boundInterval lbs ubs of-                Nothing -> error "bug: cannot compute interval?"-                Just (lb,ub) ->-                  let v = fromMaybe 0 (mplus lb ub)-                  in TopVar x v lb ub $ is { bounds = mp1 }--slnEnumerate :: Solutions -> [ Solutions ]-slnEnumerate s0 = go s0 []-  where-  go s k  = case slnNextVar s of-              Nothing -> hor s k-              Just s1 -> go s1 $ case slnNextVal s of-                                   Nothing -> k-                                   Just s2 -> go s2 k--  hor s k = s-          : case slnNextVal s of-              Nothing -> k-              Just s1 -> hor s1 k--slnNextVal :: Solutions -> Maybe Solutions-slnNextVal Done = Nothing-slnNextVal (FixedVar x v i) = FixedVar x v `fmap` slnNextVal i-slnNextVal it@(TopVar _ _ lb _ _) =-  case lb of-    Just _  -> slnNextValWith (+1) it-    Nothing -> slnNextValWith (subtract 1) it---slnNextValWith :: (Integer -> Integer) -> Solutions -> Maybe Solutions-slnNextValWith _ Done = Nothing-slnNextValWith f (FixedVar x v i) = FixedVar x v `fmap` slnNextValWith f i-slnNextValWith f (TopVar x v lb ub is) =-  do let v1 = f v-     case lb of-       Just l  -> guard (l <= v1)-       Nothing -> return ()-     case ub of-       Just u  -> guard (v1 <= u)-       Nothing -> return ()-     return $ TopVar x v1 lb ub is--slnNextVar :: Solutions -> Maybe Solutions-slnNextVar Done                = Nothing-slnNextVar (TopVar x v _ _ is) = Just $ FixedVar x v $ startIter $ iLet x v is-slnNextVar (FixedVar x v i)    = FixedVar x v `fmap` slnNextVar i------- Given a list of lower (resp. upper) bounds, compute the least (resp. largest)--- value that satisfies them all.-iPickBounded :: BoundType -> [Bound] -> Maybe Integer-iPickBounded _ [] = Nothing-iPickBounded bt bs =-  do xs <- mapM (normBound bt) bs-     return $ case bt of-                Lower -> maximum xs-                Upper -> minimum xs-  where-  -- t < c*x-  -- <=> t+1 <= c*x-  -- <=> (t+1)/c <= x-  -- <=> ceil((t+1)/c) <= x-  -- <=> t `div` c + 1 <= x-  normBound Lower (Bound c t) = do k <- isConst t-                                   return (k `div` c + 1)-  -- c*x < t-  -- <=> c*x <= t-1-  -- <=> x   <= (t-1)/c-  -- <=> x   <= floor((t-1)/c)-  -- <=> x   <= (t-1) `div` c-  normBound Upper (Bound c t) = do k <- isConst t-                                   return (div (k-1) c)----- | The largest (resp. least) upper (resp. lower) bound on a term--- that will satisfy the model-iTermBound :: BoundType -> Term -> Inerts -> Maybe Integer-iTermBound bt (T k xs) is = do ks <- mapM summand (Map.toList xs)-                               return $ sum $ k : ks-  where-  summand (x,c) = fmap (c *) (iVarBound (newBt c) x is)-  newBt c = if c > 0 then bt else case bt of-                                    Lower -> Upper-                                    Upper -> Lower----- | The largest (resp. least) upper (resp. lower) bound on a variable--- that will satisfy the model.-iVarBound :: BoundType -> Name -> Inerts -> Maybe Integer-iVarBound bt x is-  | Just t <- Map.lookup x (solved is) = iTermBound bt t is--iVarBound bt x is =-  do both <- Map.lookup x (bounds is)-     case mapMaybe fromBound (chooseBounds both) of-       [] -> Nothing-       bs -> return (combineBounds bs)-  where-  fromBound (Bound c t) = fmap (scaleBound c) (iTermBound bt t is)--  combineBounds = case bt of-                    Upper -> minimum-                    Lower -> maximum--  chooseBounds = case bt of-                   Upper -> snd-                   Lower -> fst--  scaleBound c b = case bt of-                     Upper -> div (b-1) c-                     Lower -> div b c + 1-----iModel :: Inerts -> [(Name,Integer)]-iModel i = goBounds [] (bounds i)-  where-  goBounds su mp =-    case Map.maxViewWithKey mp of-      Nothing -> goEqs su $ Map.toList $ solved i-      Just ((x,(lbs0,ubs0)), mp1) ->-        let lbs = [ Bound c (tLetNums su t) | Bound c t <- lbs0 ]-            ubs = [ Bound c (tLetNums su t) | Bound c t <- ubs0 ]-            sln = fromMaybe 0-                $ mplus (iPickBounded Lower lbs) (iPickBounded Upper ubs)-        in goBounds ((x,sln) : su) mp1--  goEqs su [] = su-  goEqs su ((x,t) : more) =-    let t1  = tLetNums su t-        vs  = tVarList t1-        su1 = [ (v,0) | v <- vs ] ++ (x,tConstPart t1) : su-    in goEqs su1 more-------------------------------------------------------------------------------------- Solving constraints--solveIs0 :: Term -> S ()-solveIs0 t = solveIs0' =<< apSubst t---- | Solve a constraint if the form @t = 0@.--- Assumes substitution has already been applied.-solveIs0' :: Term -> S ()-solveIs0' t--  -- A == 0-  | Just a <- isConst t = guard (a == 0)--  -- A + B * x = 0-  | Just (a,b,x) <- tIsOneVar t =-    case divMod (-a) b of-      (q,0) -> addDef x (tConst q)-      _     -> mzero--  --  x + S = 0-  -- -x + S = 0-  | Just (xc,x,s) <- tGetSimpleCoeff t =-    addDef x (if xc > 0 then tNeg s else s)--  -- A * S = 0-  | Just (_, s) <- tFactor t  = solveIs0 s--  -- See Section 3.1 of paper for details.-  -- We obtain an equivalent formulation but with smaller coefficients.-  | Just (ak,xk,s) <- tLeastAbsCoeff t =-      do let m = abs ak + 1-         v <- newVar-         let sgn  = signum ak-             soln =     (negate sgn * m) |*| tVar v-                    |+| tMapCoeff (\c -> sgn * modulus c m) s-         addDef xk soln--         let upd i = div (2*i + m) (2*m) + modulus i m-         solveIs0 (negate (abs ak) |*| tVar v |+| tMapCoeff upd s)--  | otherwise = error "solveIs0: unreachable"--modulus :: Integer -> Integer -> Integer-modulus a m = a - m * div (2 * a + m) (2 * m)---solveIsNeg :: Term -> S ()-solveIsNeg t = solveIsNeg' =<< apSubst t----- | Solve a constraint of the form @t < 0@.--- Assumes that substitution has been applied-solveIsNeg' :: Term -> S ()-solveIsNeg' t--  -- A < 0-  | Just a <- isConst t = guard (a < 0)--  -- A * S < 0-  | Just (_,s) <- tFactor t = solveIsNeg s--  -- See Section 5.1 of the paper-  | Just (xc,x,s) <- tLeastVar t =--    do ctrs <- if xc < 0-               -- -XC*x + S < 0-               -- S < XC*x-               then do ubs <- getBounds Upper x-                       let b    = negate xc-                           beta = s-                       addBound Lower x (Bound b beta)-                       return [ (a,alpha,b,beta) | Bound a alpha <- ubs ]-               -- XC*x + S < 0-               -- XC*x < -S-               else do lbs <- getBounds Lower x-                       let a     = xc-                           alpha = tNeg s-                       addBound Upper x (Bound a alpha)-                       return [ (a,alpha,b,beta) | Bound b beta <- lbs ]--      -- See Note [Shadows]-       mapM_ (\(a,alpha,b,beta) ->-          do let real = ctLt (a |*| beta) (b |*| alpha)-                 dark = ctLt (tConst (a * b)) (b |*| alpha |-| a |*| beta)-                 gray = [ ctEq (b |*| tVar x) (tConst i |+| beta)-                                                      | i <- [ 1 .. b - 1 ] ]-             solveIsNeg real-             foldl orElse (solveIsNeg dark) (map solveIs0 gray)-             ) ctrs--  | otherwise = error "solveIsNeg: unreachable"--orElse :: S () -> S () -> S ()-orElse x y = mplus x y--{- Note [Shadows]--  P: beta < b * x-  Q: a * x < alpha--real: a * beta < b * alpha--  beta     < b * x      -- from P-  a * beta < a * b * x  -- (a *)-  a * beta < b * alpha  -- comm. and Q---dark: b * alpha - a * beta > a * b---gray: b * x = beta + 1 \/-      b * x = beta + 2 \/-      ...-      b * x = beta + (b-1)--We stop at @b - 1@ because if:--> b * x                >= beta + b-> a * b * x            >= a * (beta + b)     -- (a *)-> a * b * x            >= a * beta + a * b   -- distrib.-> b * alpha            >  a * beta + a * b   -- comm. and Q-> b * alpha - a * beta > a * b               -- subtract (a * beta)--which is covered by the dark shadow.--}-------------------------------------------------------------------------------------- Monads--data Answer a = None | One a | Choice (Answer a) (Answer a)-                deriving Show---answerSize :: Answer a -> (Integer,Integer,Integer)-answerSize = go 0 0 0-  where-  go !n !o !c ans =-    case ans of-      None  -> (n+1, o, c)-      One _ -> (n, o + 1, c)-      Choice x y ->-        case go n o (c+1) x of-          (n',o',c') -> go n' o' c' y---dotAnswer :: (a -> Doc) -> Answer a -> Doc-dotAnswer pp g0 = vcat [text "digraph {", nest 2 (fst $ go 0 g0), text "}"]-  where-  node x d            = integer x <+> brackets (text "label=" <> text (show d))-                                                              <> semi-  edge x y            = integer x <+> text "->" <+> integer y--  go x None           = let x' = x + 1-                        in seq x' ( node x "", x' )-  go x (One a)        = let x' = x + 1-                        in seq x' ( node x (show (pp a)), x' )-  go x (Choice c1 c2) = let x'       = x + 1-                            (ls1,x1) = go x' c1-                            (ls2,x2) = go x1    c2-                        in seq x'-                           ( vcat [ node x "|"-                                  , edge x x'-                                  , edge x x1-                                  , ls1-                                  , ls2-                                  ], x2 )-toList :: Answer a -> [a]-toList a = go a []-  where-  go (Choice xs ys) zs = go xs (go ys zs)-  go (One x) xs        = x : xs-  go None xs           = xs---instance Monad Answer where-  return a           = One a-  fail _             = None-  None >>= _         = None-  One a >>= k        = k a-  Choice m1 m2 >>= k = mplus (m1 >>= k) (m2 >>= k)--instance Alternative Answer where-  empty = mzero-  (<|>) = mplus--instance MonadPlus Answer where-  mzero                = None-  mplus None x = x-  -- mplus (Choice x y) z = mplus x (mplus y z)-  mplus x y    = Choice x y--instance Functor Answer where-  fmap _ None           = None-  fmap f (One x)        = One (f x)-  fmap f (Choice x1 x2) = Choice (fmap f x1) (fmap f x2)--instance Applicative Answer where-  pure  = return-  (<*>) = ap---newtype S a = S (RW -> Answer (a,RW))--instance Monad S where-  return a      = S $ \s -> return (a,s)-  S m >>= k     = S $ \s -> do (a,s1) <- m s-                               let S m1 = k a-                               m1 s1--instance Alternative S where-  empty = mzero-  (<|>) = mplus--instance MonadPlus S where-  mzero               = S $ \_ -> mzero-  mplus (S m1) (S m2) = S $ \s -> mplus (m1 s) (m2 s)--instance Functor S where-  fmap = liftM--instance Applicative S where-  pure  = return-  (<*>) = ap--updS :: (RW -> (a,RW)) -> S a-updS f = S $ \s -> return (f s)--updS_ :: (RW -> RW) -> S ()-updS_ f = updS $ \rw -> ((),f rw)--get :: (RW -> a) -> S a-get f = updS $ \rw -> (f rw, rw)--newVar :: S Name-newVar = updS $ \rw -> ( SysName (nameSource rw)-                       , rw { nameSource = nameSource rw + 1 }-                       )---- | Get lower ('fst'), or upper ('snd') bounds for a variable.-getBounds :: BoundType -> Name -> S [Bound]-getBounds f x = get $ \rw -> case Map.lookup x $ bounds $ inerts rw of-                               Nothing -> []-                               Just bs -> case f of-                                            Lower -> fst bs-                                            Upper -> snd bs--addBound :: BoundType -> Name -> Bound -> S ()-addBound bt x b = updS_ $ \rw ->-  let i = inerts rw-      entry = case bt of-                Lower -> ([b],[])-                Upper -> ([],[b])-      jn (newL,newU) (oldL,oldU) = (newL++oldL, newU++oldU)-  in rw { inerts = i { bounds = Map.insertWith jn x entry (bounds i) }}---- | Add a new definition.--- Assumes substitution has already been applied-addDef :: Name -> Term -> S ()-addDef x t =-  do newWork <- updS $ \rw -> let (newWork,newInerts) = iSolved x t (inerts rw)-                              in (newWork, rw { inerts = newInerts })-     mapM_ solveIsNeg newWork--apSubst :: Term -> S Term-apSubst t =-  do i <- get inerts-     return (iApSubst i t)----------------------------------------------------------------------------------------data Name = UserName !Int | SysName !Int-            deriving (Read,Show,Eq,Ord)--ppName :: Name -> Doc-ppName (UserName x) = text "u" <> int x-ppName (SysName x)  = text "s" <> int x--toName :: Int -> Name-toName = UserName--fromName :: Name -> Maybe Int-fromName (UserName x) = Just x-fromName (SysName _)  = Nothing-----type NameMap = Map Name---- | The type of terms.  The integer is the constant part of the term,--- and the `Map` maps variables (represented by @Int@ to their coefficients).--- The term is a sum of its parts.--- INVARIANT: the `Map` does not map anything to 0.-data Term = T !Integer (NameMap Integer)-              deriving (Eq,Ord)--infixl 6 |+|, |-|-infixr 7 |*|---- | A constant term.-tConst :: Integer -> Term-tConst k = T k Map.empty---- | Construct a term with a single variable.-tVar :: Name -> Term-tVar x = T 0 (Map.singleton x 1)--(|+|) :: Term -> Term -> Term-T n1 m1 |+| T n2 m2 = T (n1 + n2)-                    $ if Map.null m1 then m2 else-                      if Map.null m2 then m1 else-                      Map.filter (/= 0) $ Map.unionWith (+) m1 m2--(|*|) :: Integer -> Term -> Term-0 |*| _     = tConst 0-1 |*| t     = t-k |*| T n m = T (k * n) (fmap (k *) m)--tNeg :: Term -> Term-tNeg t = (-1) |*| t--(|-|) :: Term -> Term -> Term-t1 |-| t2 = t1 |+| tNeg t2----- | Replace a variable with a term.-tLet :: Name -> Term -> Term -> Term-tLet x t1 t2 = let (a,t) = tSplitVar x t2-               in a |*| t1 |+| t---- | Replace a variable with a constant.-tLetNum :: Name -> Integer -> Term -> Term-tLetNum x k t = let (c,T n m) = tSplitVar x t-                in T (c * k + n) m---- | Replace the given variables with constants.-tLetNums :: [(Name,Integer)] -> Term -> Term-tLetNums xs t = foldr (\(x,i) t1 -> tLetNum x i t1) t xs-----instance Show Term where-  showsPrec c t = showsPrec c (show (ppTerm t))--ppTerm :: Term -> Doc-ppTerm (T k m) =-  case Map.toList m of-    []     -> integer k-    xs     | k /= 0 -> hsep (integer k : map ppProd xs)-    x : xs -> hsep (ppFst x   : map ppProd xs)--  where-  ppFst (x,1)  = ppName x-  ppFst (x,-1) = text "-" <> ppName x-  ppFst (x,n)  = ppMul n x--  ppProd (x,1)  = text "+" <+> ppName x-  ppProd (x,-1) = text "-" <+> ppName x-  ppProd (x,n) | n > 0      = text "+" <+> ppMul n x-               | otherwise  = text "-" <+> ppMul (abs n) x--  ppMul n x = integer n <+> text "*" <+> ppName x---- | Remove a variable from the term, and return its coefficient.--- If the variable is not present in the term, the coefficient is 0.-tSplitVar :: Name -> Term -> (Integer, Term)-tSplitVar x t@(T n m) =-  case Map.updateLookupWithKey (\_ _ -> Nothing) x m of-    (Nothing,_) -> (0,t)-    (Just k,m1) -> (k, T n m1)---- | Does the term contain this varibale?-tHasVar :: Name -> Term -> Bool-tHasVar x (T _ m) = Map.member x m---- | Is this terms just an integer.-isConst :: Term -> Maybe Integer-isConst (T n m)-  | Map.null m  = Just n-  | otherwise   = Nothing--tConstPart :: Term -> Integer-tConstPart (T n _) = n---- | Returns: @Just (a, b, x)@ if the term is the form: @a + b * x@-tIsOneVar :: Term -> Maybe (Integer, Integer, Name)-tIsOneVar (T a m) = case Map.toList m of-                      [ (x,b) ] -> Just (a, b, x)-                      _         -> Nothing---- | Spots terms that contain variables with unit coefficients--- (i.e., of the form @x + t@ or @t - x@).--- Returns (coeff, var, rest of term)-tGetSimpleCoeff :: Term -> Maybe (Integer, Name, Term)-tGetSimpleCoeff (T a m) =-  do let (m1,m2) = Map.partition (\x -> x == 1 || x == -1) m-     ((x,xc), m3) <- Map.minViewWithKey m1-     return (xc, x, T a (Map.union m3 m2))--tVarList :: Term -> [Name]-tVarList (T _ m) = Map.keys m----- | Try to factor-out a common consant (> 1) from a term.--- For example, @2 + 4x@ becomes @2 * (1 + 2x)@.-tFactor :: Term -> Maybe (Integer, Term)-tFactor (T c m) =-  do d <- common (c : Map.elems m)-     return (d, T (div c d) (fmap (`div` d) m))-  where-  common :: [Integer] -> Maybe Integer-  common []  = Nothing-  common [x] = Just x-  common (x : y : zs) =-    case gcd x y of-      1 -> Nothing-      n -> common (n : zs)---- | Extract a variable with a coefficient whose absolute value is minimal.-tLeastAbsCoeff :: Term -> Maybe (Integer, Name, Term)-tLeastAbsCoeff (T c m) = do (xc,x,m1) <- Map.foldWithKey step Nothing m-                            return (xc, x, T c m1)-  where-  step x xc Nothing   = Just (xc, x, Map.delete x m)-  step x xc (Just (yc,_,_))-    | abs xc < abs yc = Just (xc, x, Map.delete x m)-  step _ _ it         = it---- | Extract the least variable from a term-tLeastVar :: Term -> Maybe (Integer, Name, Term)-tLeastVar (T c m) =-  do ((x,xc), m1) <- Map.minViewWithKey m-     return (xc, x, T c m1)---- | Apply a function to all coefficients, including the constnat-tMapCoeff :: (Integer -> Integer) -> Term -> Term-tMapCoeff f (T c m) = T (f c) (fmap f m)-------
+ src/Data/Integer/SAT.hs view
@@ -0,0 +1,980 @@+{-# LANGUAGE BangPatterns, CPP, PatternGuards, Safe #-}+{-|+This module implements a decision procedure for quantifier-free linear+arithmetic.  The algorithm is based on the following paper:++  An Online Proof-Producing Decision Procedure for+  Mixed-Integer Linear Arithmetic+  by+  Sergey Berezin, Vijay Ganesh, and David L. Dill+-}+module Data.Integer.SAT+  ( PropSet+  , noProps+  , checkSat+  , assert+  , Prop(..)+  , Expr(..)+  , BoundType(..)+  , getExprBound+  , getExprRange+  , Name+  , toName+  , fromName+  -- * Iterators+  , allSolutions+  , slnCurrent+  , slnNextVal+  , slnNextVar+  , slnEnumerate+++  -- * Debug+  , dotPropSet+  , sizePropSet+  , allInerts+  , ppInerts++  -- * For QuickCheck+  , iPickBounded+  , Bound(..)+  , tConst+  ) where+import           Control.Applicative (Alternative (..), Applicative (..), (<$>))+import           Control.Monad       (MonadPlus (..), ap, guard, liftM)+import           Data.List           (partition)+import           Data.Map            (Map)+import qualified Data.Map            as Map+import           Data.Maybe          (fromMaybe, mapMaybe, maybeToList)+import           Prelude             hiding ((<>))+import           Text.PrettyPrint++infixr 2 :||+infixr 3 :&&+infix  4 :==, :/=, :<, :<=, :>, :>=+infixl 6 :+, :-+infixl 7 :*++--------------------------------------------------------------------------------+-- Solver interface++-- | A collection of propositions.+newtype PropSet = State (Answer RW)+                  deriving Show++dotPropSet :: PropSet -> Doc+dotPropSet (State a) = dotAnswer (ppInerts . inerts) a++sizePropSet :: PropSet -> (Integer,Integer,Integer)+sizePropSet (State a) = answerSize a++-- | An empty collection of propositions.+noProps :: PropSet+noProps = State $ return initRW++-- | Add a new proposition to an existing collection.+assert :: Prop -> PropSet -> PropSet+assert p (State rws) = State $ fmap snd $ m =<< rws+  where S m = prop p++-- | Extract a model from a consistent set of propositions.+-- Returns 'Nothing' if the assertions have no model.+-- If a variable does not appear in the assignment, then it is 0 (?).+checkSat :: PropSet -> Maybe [(Int,Integer)]+checkSat (State m) = go m+  where+  go None           = mzero+  go (One rw)       = return [ (x,v) | (UserName x, v) <- iModel (inerts rw) ]+  go (Choice m1 m2) = mplus (go m1) (go m2)++allInerts :: PropSet -> [Inerts]+allInerts (State m) = map inerts (toList m)++allSolutions :: PropSet -> [Solutions]+allSolutions = map startIter . allInerts+++-- | Computes bounds on the expression that are compatible with the model.+-- Returns `Nothing` if the bound is not known.+getExprBound :: BoundType -> Expr -> PropSet -> Maybe Integer+getExprBound bt e (State s) =+  do let S m          = expr e+         check (t,s1) = iTermBound bt t (inerts s1)+     bs <- mapM check $ toList $ s >>= m+     case bs of+       [] -> Nothing+       _  -> Just (maximum bs)++-- | Compute the range of possible values for an expression.+-- Returns `Nothing` if the bound is not known.+getExprRange :: Expr -> PropSet -> Maybe [Integer]+getExprRange e (State s) =+  do let S m          = expr e+         check (t,s1) = do l <- iTermBound Lower t (inerts s1)+                           u <- iTermBound Upper t (inerts s1)+                           return (l,u)+     bs <- mapM check $ toList $ s >>= m+     case bs of+       [] -> Nothing+       _  -> let (ls,us) = unzip bs+             in Just [ x | x <- [ minimum ls .. maximum us ] ]++++-- | The type of proposition.+data Prop = PTrue+          | PFalse+          | Prop :|| Prop+          | Prop :&& Prop+          | Not Prop+          | Expr :== Expr+          | Expr :/= Expr+          | Expr :<  Expr+          | Expr :>  Expr+          | Expr :<= Expr+          | Expr :>= Expr+            deriving (Read,Show,Ord, Eq)++-- | The type of integer expressions.+-- Variable names must be non-negative.+data Expr = Expr :+ Expr          -- ^ Addition+          | Expr :- Expr          -- ^ Subtraction+          | Integer :* Expr       -- ^ Multiplication by a constant+          | Negate Expr           -- ^ Negation+          | Var Name              -- ^ Variable+          | K Integer             -- ^ Constant+          | If Prop Expr Expr     -- ^ A conditional expression+          | Div Expr Integer      -- ^ Division, rounds down+          | Mod Expr Integer      -- ^ Non-negative remainder+            deriving (Read,Show, Ord, Eq)++prop :: Prop -> S ()+prop PTrue       = return ()+prop PFalse      = mzero+prop (p1 :|| p2) = prop p1 `mplus` prop p2+prop (p1 :&& p2) = prop p1 >> prop p2+prop (Not p)     = prop (neg p)+  where+  neg PTrue       = PFalse+  neg PFalse      = PTrue+  neg (p1 :&& p2) = neg p1 :|| neg p2+  neg (p1 :|| p2) = neg p1 :&& neg p2+  neg (Not q)     = q+  neg (e1 :== e2) = e1 :/= e2+  neg (e1 :/= e2) = e1 :== e2+  neg (e1 :<  e2) = e1 :>= e2+  neg (e1 :<= e2) = e1 :>  e2+  neg (e1 :>  e2) = e1 :<= e2+  neg (e1 :>= e2) = e1 :<  e2++prop (e1 :== e2) = do t1 <- expr e1+                      t2 <- expr e2+                      solveIs0 (t1 |-| t2)++prop (e1 :/= e2)  = do t1 <- expr e1+                       t2 <- expr e2+                       let t = t1 |-| t2+                       solveIsNeg t `orElse` solveIsNeg (tNeg t)++prop (e1 :< e2)   = do t1 <- expr e1+                       t2 <- expr e2+                       solveIsNeg (t1 |-| t2)++prop (e1 :<= e2)  = do t1 <- expr e1+                       t2 <- expr e2+                       let t = t1 |-| t2 |-| tConst 1+                       solveIsNeg t++prop (e1 :> e2)   = prop (e2 :<  e1)+prop (e1 :>= e2)  = prop (e2 :<= e1)+++expr :: Expr -> S Term+expr (e1 :+ e2)   = (|+|)   <$> expr e1 <*> expr e2+expr (e1 :- e2)   = (|-|)   <$> expr e1 <*> expr e2+expr (k  :* e2)   = (k |*|) <$> expr e2+expr (Negate e)   = tNeg    <$> expr e+expr (Var x)      = pure (tVar x)+expr (K x)        = pure (tConst x)+expr (If p e1 e2) = do x <- newVar+                       prop (p :&& Var x :== e1 :|| Not p :&& Var x :== e2)+                       return (tVar x)+expr (Div e k)    = fmap fst $ exprDivMod e k+expr (Mod e k)    = fmap snd $ exprDivMod e k++exprDivMod :: Expr -> Integer -> S (Term,Term)+exprDivMod e k =+  do guard (k /= 0) -- Always unsat+     q <- newVar+     r <- newVar+     let er = Var r+     prop (k :* Var q :+ er :== e :&& er :< K k :&& K 0 :<= er)+     return (tVar q, tVar r)++++++--------------------------------------------------------------------------------++data RW = RW { nameSource :: !Int+             , inerts     :: Inerts+             } deriving Show++initRW :: RW+initRW = RW { nameSource = 0, inerts = iNone }++--------------------------------------------------------------------------------+-- Constraints and Bound on Variables++ctLt :: Term -> Term -> Term+ctLt t1 t2 = t1 |-| t2++ctEq :: Term -> Term -> Term+ctEq t1 t2 = t1 |-| t2++data Bound      = Bound Integer Term  -- ^ The integer is strictly positive+                  deriving Show++data BoundType  = Lower | Upper+                  deriving Show++toCt :: BoundType -> Name -> Bound -> Term+toCt Lower x (Bound c t) = ctLt t              (c |*| tVar x)+toCt Upper x (Bound c t) = ctLt (c |*| tVar x) t++++--------------------------------------------------------------------------------+-- Inert set++-- | The inert contains the solver state on one possible path.+data Inerts = Inerts+  { bounds :: NameMap ([Bound],[Bound])+    -- ^ Known lower and upper bounds for variables.+    -- Each bound @(c,t)@ in the first list asserts that  @t < c * x@+    -- Each bound @(c,t)@ in the second list asserts that @c * x < t@++  , solved :: NameMap Term+    -- ^ Definitions for resolved variables.+    -- These form an idempotent substitution.+  } deriving Show++ppInerts :: Inerts -> Doc+ppInerts is = vcat $ [ ppLower x b | (x,(ls,_)) <- bnds, b <- ls ] +++                     [ ppUpper x b | (x,(_,us)) <- bnds, b <- us ] +++                     [ ppEq e      | e <- Map.toList (solved is) ]+  where+  bnds = Map.toList (bounds is)++  ppT c x                = ppTerm (c |*| tVar x)+  ppLower x (Bound c t)  = ppTerm t <+> text "<" <+> ppT c x+  ppUpper x (Bound c t)  = ppT c x  <+> text "<" <+> ppTerm t+  ppEq (x,t)             = ppName x <+> text "=" <+> ppTerm t++++-- | An empty inert set.+iNone :: Inerts+iNone = Inerts { bounds = Map.empty+               , solved = Map.empty+               }++-- | Rewrite a term using the definitions from an inert set.+iApSubst :: Inerts -> Term -> Term+iApSubst i t = foldr apS t $ Map.toList $ solved i+  where apS (x,t1) t2 = tLet x t1 t2++-- | Add a definition.  Upper and lower bound constraints that mention+-- the variable are "kicked-out" so that they can be reinserted in the+-- context of the new knowledge.+--+--    * Assumes substitution has already been applied.+--+--    * The kicked-out constraints are NOT rewritten, this happens+--      when they get inserted in the work queue.++iSolved :: Name -> Term -> Inerts -> ([Term], Inerts)+iSolved x t i =+  ( kickedOut+  , Inerts { bounds = otherBounds+           , solved = Map.insert x t $ Map.map (tLet x t) $ solved i+           }+  )+  where+  (kickedOut, otherBounds) =++        -- First, we eliminate all entries for `x`+    let (mb, mp1) = Map.updateLookupWithKey (\_ _ -> Nothing) x (bounds i)++        -- Next, we elminate all constraints that mentiond `x` in bounds+        mp2 = Map.mapWithKey extractBounds mp1++    in ( [ ct | (lbs,ubs) <- maybeToList mb+              ,  ct <- map (toCt Lower x) lbs ++ map (toCt Upper x) ubs ]+         +++         [ ct | (_,cts) <- Map.elems mp2, ct <- cts ]++       , fmap fst mp2+       )++  extractBounds y (lbs,ubs) =+    let (lbsStay, lbsKick) = partition stay lbs+        (ubsStay, ubsKick) = partition stay ubs+    in ( (lbsStay,ubsStay)+       , map (toCt Lower y) lbsKick +++         map (toCt Upper y) ubsKick+       )++  stay (Bound _ bnd) = not (tHasVar x bnd)+++-- | Given some lower and upper bounds, find the interval the satisfies them.+-- Note the upper and lower bounds are strict (i.e., < and >)+boundInterval :: [Bound] -> [Bound] -> Maybe (Maybe Integer, Maybe Integer)+boundInterval lbs ubs =+  do ls <- mapM (normBound Lower) lbs+     us <- mapM (normBound Upper) ubs+     let lb = case ls of+                [] -> Nothing+                _  -> Just (maximum ls + 1)+         ub = case us of+                [] -> Nothing+                _  -> Just (minimum us - 1)+     case (lb,ub) of+       (Just l, Just u) -> guard (l <= u)+       _                -> return ()+     return (lb,ub)+  where+  normBound Lower (Bound c t) = do k <- isConst t+                                   return (div (k + c - 1) c)+  normBound Upper (Bound c t) = do k <- isConst t+                                   return (div k c)++data Solutions = Done+               | TopVar Name Integer (Maybe Integer) (Maybe Integer) Inerts+               | FixedVar Name Integer Solutions+                  deriving Show++slnCurrent :: Solutions -> [(Int,Integer)]+slnCurrent s = [ (x,v) | (UserName x, v) <- go s ]+  where+  go Done                = []+  go (TopVar x v _ _ is) = (x, v) : iModel (iLet x v is)+  go (FixedVar x v i)    = (x, v) : go i++-- | Replace occurances of a variable with an integer.+-- WARNING: The integer should be a valid value for the variable.+iLet :: Name -> Integer -> Inerts -> Inerts+iLet x v is = Inerts { bounds = fmap updBs (bounds is)+                     , solved = fmap (tLetNum x v) (solved is) }+  where+  updB (Bound c t) = Bound c (tLetNum x v t)+  updBs (ls,us)    = (map updB ls, map updB us)+++startIter :: Inerts -> Solutions+startIter is =+  case Map.maxViewWithKey (bounds is) of+    Nothing ->+      case Map.maxViewWithKey (solved is) of+        Nothing -> Done+        Just ((x,t), mp1) ->+          case [ y | y <- tVarList t ] of+            y : _ -> TopVar y 0 Nothing Nothing is+            [] -> let v = tConstPart t+                  in TopVar x v (Just v) (Just v) $ is { solved = mp1 }+    Just ((x,(lbs,ubs)), mp1) ->+      case [ y | Bound _ t <- lbs ++ ubs, y <- tVarList t ] of+        y : _ -> TopVar y 0 Nothing Nothing is+        [] -> case boundInterval lbs ubs of+                Nothing -> error "bug: cannot compute interval?"+                Just (lb,ub) ->+                  let v = fromMaybe 0 (mplus lb ub)+                  in TopVar x v lb ub $ is { bounds = mp1 }++slnEnumerate :: Solutions -> [ Solutions ]+slnEnumerate s0 = go s0 []+  where+  go s k  = case slnNextVar s of+              Nothing -> hor s k+              Just s1 -> go s1 $ case slnNextVal s of+                                   Nothing -> k+                                   Just s2 -> go s2 k++  hor s k = s+          : case slnNextVal s of+              Nothing -> k+              Just s1 -> hor s1 k++slnNextVal :: Solutions -> Maybe Solutions+slnNextVal Done = Nothing+slnNextVal (FixedVar x v i) = FixedVar x v `fmap` slnNextVal i+slnNextVal it@(TopVar _ _ lb _ _) =+  case lb of+    Just _  -> slnNextValWith (+1) it+    Nothing -> slnNextValWith (subtract 1) it+++slnNextValWith :: (Integer -> Integer) -> Solutions -> Maybe Solutions+slnNextValWith _ Done = Nothing+slnNextValWith f (FixedVar x v i) = FixedVar x v `fmap` slnNextValWith f i+slnNextValWith f (TopVar x v lb ub is) =+  do let v1 = f v+     case lb of+       Just l  -> guard (l <= v1)+       Nothing -> return ()+     case ub of+       Just u  -> guard (v1 <= u)+       Nothing -> return ()+     return $ TopVar x v1 lb ub is++slnNextVar :: Solutions -> Maybe Solutions+slnNextVar Done                = Nothing+slnNextVar (TopVar x v _ _ is) = Just $ FixedVar x v $ startIter $ iLet x v is+slnNextVar (FixedVar x v i)    = FixedVar x v `fmap` slnNextVar i+++++-- Given a list of lower (resp. upper) bounds, compute the least (resp. largest)+-- value that satisfies them all.+iPickBounded :: BoundType -> [Bound] -> Maybe Integer+iPickBounded _ [] = Nothing+iPickBounded bt bs =+  do xs <- mapM (normBound bt) bs+     return $ case bt of+                Lower -> maximum xs+                Upper -> minimum xs+  where+  -- t < c*x+  -- <=> t+1 <= c*x+  -- <=> (t+1)/c <= x+  -- <=> ceil((t+1)/c) <= x+  -- <=> t `div` c + 1 <= x+  normBound Lower (Bound c t) = do k <- isConst t+                                   return (k `div` c + 1)+  -- c*x < t+  -- <=> c*x <= t-1+  -- <=> x   <= (t-1)/c+  -- <=> x   <= floor((t-1)/c)+  -- <=> x   <= (t-1) `div` c+  normBound Upper (Bound c t) = do k <- isConst t+                                   return (div (k-1) c)+++-- | The largest (resp. least) upper (resp. lower) bound on a term+-- that will satisfy the model+iTermBound :: BoundType -> Term -> Inerts -> Maybe Integer+iTermBound bt (T k xs) is = do ks <- mapM summand (Map.toList xs)+                               return $ sum $ k : ks+  where+  summand (x,c) = fmap (c *) (iVarBound (newBt c) x is)+  newBt c = if c > 0 then bt else case bt of+                                    Lower -> Upper+                                    Upper -> Lower+++-- | The largest (resp. least) upper (resp. lower) bound on a variable+-- that will satisfy the model.+iVarBound :: BoundType -> Name -> Inerts -> Maybe Integer+iVarBound bt x is+  | Just t <- Map.lookup x (solved is) = iTermBound bt t is++iVarBound bt x is =+  do both <- Map.lookup x (bounds is)+     case mapMaybe fromBound (chooseBounds both) of+       [] -> Nothing+       bs -> return (combineBounds bs)+  where+  fromBound (Bound c t) = fmap (scaleBound c) (iTermBound bt t is)++  combineBounds = case bt of+                    Upper -> minimum+                    Lower -> maximum++  chooseBounds = case bt of+                   Upper -> snd+                   Lower -> fst++  scaleBound c b = case bt of+                     Upper -> div (b-1) c+                     Lower -> div b c + 1+++++iModel :: Inerts -> [(Name,Integer)]+iModel i = goBounds [] (bounds i)+  where+  goBounds su mp =+    case Map.maxViewWithKey mp of+      Nothing -> goEqs su $ Map.toList $ solved i+      Just ((x,(lbs0,ubs0)), mp1) ->+        let lbs = [ Bound c (tLetNums su t) | Bound c t <- lbs0 ]+            ubs = [ Bound c (tLetNums su t) | Bound c t <- ubs0 ]+            sln = fromMaybe 0+                $ mplus (iPickBounded Lower lbs) (iPickBounded Upper ubs)+        in goBounds ((x,sln) : su) mp1++  goEqs su [] = su+  goEqs su ((x,t) : more) =+    let t1  = tLetNums su t+        vs  = tVarList t1+        su1 = [ (v,0) | v <- vs ] ++ (x,tConstPart t1) : su+    in goEqs su1 more+++--------------------------------------------------------------------------------+-- Solving constraints++solveIs0 :: Term -> S ()+solveIs0 t = solveIs0' =<< apSubst t++-- | Solve a constraint if the form @t = 0@.+-- Assumes substitution has already been applied.+solveIs0' :: Term -> S ()+solveIs0' t++  -- A == 0+  | Just a <- isConst t = guard (a == 0)++  -- A + B * x = 0+  | Just (a,b,x) <- tIsOneVar t =+    case divMod (-a) b of+      (q,0) -> addDef x (tConst q)+      _     -> mzero++  --  x + S = 0+  -- -x + S = 0+  | Just (xc,x,s) <- tGetSimpleCoeff t =+    addDef x (if xc > 0 then tNeg s else s)++  -- A * S = 0+  | Just (_, s) <- tFactor t  = solveIs0 s++  -- See Section 3.1 of paper for details.+  -- We obtain an equivalent formulation but with smaller coefficients.+  | Just (ak,xk,s) <- tLeastAbsCoeff t =+      do let m = abs ak + 1+         v <- newVar+         let sgn  = signum ak+             soln =     (negate sgn * m) |*| tVar v+                    |+| tMapCoeff (\c -> sgn * modulus c m) s+         addDef xk soln++         let upd i = div (2*i + m) (2*m) + modulus i m+         solveIs0 (negate (abs ak) |*| tVar v |+| tMapCoeff upd s)++  | otherwise = error "solveIs0: unreachable"++modulus :: Integer -> Integer -> Integer+modulus a m = a - m * div (2 * a + m) (2 * m)+++solveIsNeg :: Term -> S ()+solveIsNeg t = solveIsNeg' =<< apSubst t+++-- | Solve a constraint of the form @t < 0@.+-- Assumes that substitution has been applied+solveIsNeg' :: Term -> S ()+solveIsNeg' t++  -- A < 0+  | Just a <- isConst t = guard (a < 0)++  -- A * S < 0+  | Just (_,s) <- tFactor t = solveIsNeg s++  -- See Section 5.1 of the paper+  | Just (xc,x,s) <- tLeastVar t =++    do ctrs <- if xc < 0+               -- -XC*x + S < 0+               -- S < XC*x+               then do ubs <- getBounds Upper x+                       let b    = negate xc+                           beta = s+                       addBound Lower x (Bound b beta)+                       return [ (a,alpha,b,beta) | Bound a alpha <- ubs ]+               -- XC*x + S < 0+               -- XC*x < -S+               else do lbs <- getBounds Lower x+                       let a     = xc+                           alpha = tNeg s+                       addBound Upper x (Bound a alpha)+                       return [ (a,alpha,b,beta) | Bound b beta <- lbs ]++      -- See Note [Shadows]+       mapM_ (\(a,alpha,b,beta) ->+          do let real = ctLt (a |*| beta) (b |*| alpha)+                 dark = ctLt (tConst (a * b)) (b |*| alpha |-| a |*| beta)+                 gray = [ ctEq (b |*| tVar x) (tConst i |+| beta)+                                                      | i <- [ 1 .. b - 1 ] ]+             solveIsNeg real+             foldl orElse (solveIsNeg dark) (map solveIs0 gray)+             ) ctrs++  | otherwise = error "solveIsNeg: unreachable"++orElse :: S () -> S () -> S ()+orElse x y = mplus x y++{- Note [Shadows]++  P: beta < b * x+  Q: a * x < alpha++real: a * beta < b * alpha++  beta     < b * x      -- from P+  a * beta < a * b * x  -- (a *)+  a * beta < b * alpha  -- comm. and Q+++dark: b * alpha - a * beta > a * b+++gray: b * x = beta + 1 \/+      b * x = beta + 2 \/+      ...+      b * x = beta + (b-1)++We stop at @b - 1@ because if:++> b * x                >= beta + b+> a * b * x            >= a * (beta + b)     -- (a *)+> a * b * x            >= a * beta + a * b   -- distrib.+> b * alpha            >  a * beta + a * b   -- comm. and Q+> b * alpha - a * beta > a * b               -- subtract (a * beta)++which is covered by the dark shadow.+-}+++--------------------------------------------------------------------------------+-- Monads++data Answer a = None | One a | Choice (Answer a) (Answer a)+                deriving Show+++answerSize :: Answer a -> (Integer,Integer,Integer)+answerSize = go 0 0 0+  where+  go !n !o !c ans =+    case ans of+      None  -> (n+1, o, c)+      One _ -> (n, o + 1, c)+      Choice x y ->+        case go n o (c+1) x of+          (n',o',c') -> go n' o' c' y+++dotAnswer :: (a -> Doc) -> Answer a -> Doc+dotAnswer pp g0 = vcat [text "digraph {", nest 2 (fst $ go 0 g0), text "}"]+  where+  node x d            = integer x <+> brackets (text "label=" <> text (show d))+                                                              <> semi+  edge x y            = integer x <+> text "->" <+> integer y++  go x None           = let x' = x + 1+                        in seq x' ( node x "", x' )+  go x (One a)        = let x' = x + 1+                        in seq x' ( node x (show (pp a)), x' )+  go x (Choice c1 c2) = let x'       = x + 1+                            (ls1,x1) = go x' c1+                            (ls2,x2) = go x1    c2+                        in seq x'+                           ( vcat [ node x "|"+                                  , edge x x'+                                  , edge x x1+                                  , ls1+                                  , ls2+                                  ], x2 )+toList :: Answer a -> [a]+toList a = go a []+  where+  go (Choice xs ys) zs = go xs (go ys zs)+  go (One x) xs        = x : xs+  go None xs           = xs+++instance Monad Answer where+  return a           = One a+#if !MIN_VERSION_ghc(8,8,1)+  fail _             = None+#endif+  None >>= _         = None+  One a >>= k        = k a+  Choice m1 m2 >>= k = mplus (m1 >>= k) (m2 >>= k)++instance Alternative Answer where+  empty = mzero+  (<|>) = mplus++instance MonadPlus Answer where+  mzero                = None+  mplus None x = x+  -- mplus (Choice x y) z = mplus x (mplus y z)+  mplus x y    = Choice x y++instance Functor Answer where+  fmap _ None           = None+  fmap f (One x)        = One (f x)+  fmap f (Choice x1 x2) = Choice (fmap f x1) (fmap f x2)++instance Applicative Answer where+  pure  = return+  (<*>) = ap+++newtype S a = S (RW -> Answer (a,RW))++instance Monad S where+  return a      = S $ \s -> return (a,s)+  S m >>= k     = S $ \s -> do (a,s1) <- m s+                               let S m1 = k a+                               m1 s1++instance Alternative S where+  empty = mzero+  (<|>) = mplus++instance MonadPlus S where+  mzero               = S $ \_ -> mzero+  mplus (S m1) (S m2) = S $ \s -> mplus (m1 s) (m2 s)++instance Functor S where+  fmap = liftM++instance Applicative S where+  pure  = return+  (<*>) = ap++updS :: (RW -> (a,RW)) -> S a+updS f = S $ \s -> return (f s)++updS_ :: (RW -> RW) -> S ()+updS_ f = updS $ \rw -> ((),f rw)++get :: (RW -> a) -> S a+get f = updS $ \rw -> (f rw, rw)++newVar :: S Name+newVar = updS $ \rw -> ( SysName (nameSource rw)+                       , rw { nameSource = nameSource rw + 1 }+                       )++-- | Get lower ('fst'), or upper ('snd') bounds for a variable.+getBounds :: BoundType -> Name -> S [Bound]+getBounds f x = get $ \rw -> case Map.lookup x $ bounds $ inerts rw of+                               Nothing -> []+                               Just bs -> case f of+                                            Lower -> fst bs+                                            Upper -> snd bs++addBound :: BoundType -> Name -> Bound -> S ()+addBound bt x b = updS_ $ \rw ->+  let i = inerts rw+      entry = case bt of+                Lower -> ([b],[])+                Upper -> ([],[b])+      jn (newL,newU) (oldL,oldU) = (newL++oldL, newU++oldU)+  in rw { inerts = i { bounds = Map.insertWith jn x entry (bounds i) }}++-- | Add a new definition.+-- Assumes substitution has already been applied+addDef :: Name -> Term -> S ()+addDef x t =+  do newWork <- updS $ \rw -> let (newWork,newInerts) = iSolved x t (inerts rw)+                              in (newWork, rw { inerts = newInerts })+     mapM_ solveIsNeg newWork++apSubst :: Term -> S Term+apSubst t =+  do i <- get inerts+     return (iApSubst i t)+++++--------------------------------------------------------------------------------+++data Name = UserName !Int | SysName !Int+            deriving (Read,Show,Eq,Ord)++ppName :: Name -> Doc+ppName (UserName x) = text "u" <> int x+ppName (SysName x)  = text "s" <> int x++toName :: Int -> Name+toName = UserName++fromName :: Name -> Maybe Int+fromName (UserName x) = Just x+fromName (SysName _)  = Nothing+++++type NameMap = Map Name++-- | The type of terms.  The integer is the constant part of the term,+-- and the `Map` maps variables (represented by @Int@ to their coefficients).+-- The term is a sum of its parts.+-- INVARIANT: the `Map` does not map anything to 0.+data Term = T !Integer (NameMap Integer)+              deriving (Eq,Ord)++infixl 6 |+|, |-|+infixr 7 |*|++-- | A constant term.+tConst :: Integer -> Term+tConst k = T k Map.empty++-- | Construct a term with a single variable.+tVar :: Name -> Term+tVar x = T 0 (Map.singleton x 1)++(|+|) :: Term -> Term -> Term+T n1 m1 |+| T n2 m2 = T (n1 + n2)+                    $ if Map.null m1 then m2 else+                      if Map.null m2 then m1 else+                      Map.filter (/= 0) $ Map.unionWith (+) m1 m2++(|*|) :: Integer -> Term -> Term+0 |*| _     = tConst 0+1 |*| t     = t+k |*| T n m = T (k * n) (fmap (k *) m)++tNeg :: Term -> Term+tNeg t = (-1) |*| t++(|-|) :: Term -> Term -> Term+t1 |-| t2 = t1 |+| tNeg t2+++-- | Replace a variable with a term.+tLet :: Name -> Term -> Term -> Term+tLet x t1 t2 = let (a,t) = tSplitVar x t2+               in a |*| t1 |+| t++-- | Replace a variable with a constant.+tLetNum :: Name -> Integer -> Term -> Term+tLetNum x k t = let (c,T n m) = tSplitVar x t+                in T (c * k + n) m++-- | Replace the given variables with constants.+tLetNums :: [(Name,Integer)] -> Term -> Term+tLetNums xs t = foldr (\(x,i) t1 -> tLetNum x i t1) t xs+++++instance Show Term where+  showsPrec c t = showsPrec c (show (ppTerm t))++ppTerm :: Term -> Doc+ppTerm (T k m) =+  case Map.toList m of+    []              -> integer k+    xs     | k /= 0 -> hsep (integer k : map ppProd xs)+    x : xs          -> hsep (ppFst x   : map ppProd xs)++  where+  ppFst (x,1)  = ppName x+  ppFst (x,-1) = text "-" <> ppName x+  ppFst (x,n)  = ppMul n x++  ppProd (x,1)  = text "+" <+> ppName x+  ppProd (x,-1) = text "-" <+> ppName x+  ppProd (x,n) | n > 0      = text "+" <+> ppMul n x+               | otherwise  = text "-" <+> ppMul (abs n) x++  ppMul n x = integer n <+> text "*" <+> ppName x++-- | Remove a variable from the term, and return its coefficient.+-- If the variable is not present in the term, the coefficient is 0.+tSplitVar :: Name -> Term -> (Integer, Term)+tSplitVar x t@(T n m) =+  case Map.updateLookupWithKey (\_ _ -> Nothing) x m of+    (Nothing,_) -> (0,t)+    (Just k,m1) -> (k, T n m1)++-- | Does the term contain this varibale?+tHasVar :: Name -> Term -> Bool+tHasVar x (T _ m) = Map.member x m++-- | Is this terms just an integer.+isConst :: Term -> Maybe Integer+isConst (T n m)+  | Map.null m  = Just n+  | otherwise   = Nothing++tConstPart :: Term -> Integer+tConstPart (T n _) = n++-- | Returns: @Just (a, b, x)@ if the term is the form: @a + b * x@+tIsOneVar :: Term -> Maybe (Integer, Integer, Name)+tIsOneVar (T a m) = case Map.toList m of+                      [ (x,b) ] -> Just (a, b, x)+                      _         -> Nothing++-- | Spots terms that contain variables with unit coefficients+-- (i.e., of the form @x + t@ or @t - x@).+-- Returns (coeff, var, rest of term)+tGetSimpleCoeff :: Term -> Maybe (Integer, Name, Term)+tGetSimpleCoeff (T a m) =+  do let (m1,m2) = Map.partition (\x -> x == 1 || x == -1) m+     ((x,xc), m3) <- Map.minViewWithKey m1+     return (xc, x, T a (Map.union m3 m2))++tVarList :: Term -> [Name]+tVarList (T _ m) = Map.keys m+++-- | Try to factor-out a common consant (> 1) from a term.+-- For example, @2 + 4x@ becomes @2 * (1 + 2x)@.+tFactor :: Term -> Maybe (Integer, Term)+tFactor (T c m) =+  do d <- common (c : Map.elems m)+     return (d, T (div c d) (fmap (`div` d) m))+  where+  common :: [Integer] -> Maybe Integer+  common []  = Nothing+  common [x] = Just x+  common (x : y : zs) =+    case gcd x y of+      1 -> Nothing+      n -> common (n : zs)++-- | Extract a variable with a coefficient whose absolute value is minimal.+tLeastAbsCoeff :: Term -> Maybe (Integer, Name, Term)+tLeastAbsCoeff (T c m) = do (xc,x,m1) <- Map.foldrWithKey step Nothing m+                            return (xc, x, T c m1)+  where+  step x xc Nothing   = Just (xc, x, Map.delete x m)+  step x xc (Just (yc,_,_))+    | abs xc < abs yc = Just (xc, x, Map.delete x m)+  step _ _ it         = it++-- | Extract the least variable from a term+tLeastVar :: Term -> Maybe (Integer, Name, Term)+tLeastVar (T c m) =+  do ((x,xc), m1) <- Map.minViewWithKey m+     return (xc, x, T c m1)++-- | Apply a function to all coefficients, including the constnat+tMapCoeff :: (Integer -> Integer) -> Term -> Term+tMapCoeff f (T c m) = T (f c) (fmap f m)+++++++
− src/GHC/Compat.hs
@@ -1,121 +0,0 @@-{-# LANGUAGE CPP, FlexibleInstances, PatternGuards, PatternSynonyms #-}-{-# LANGUAGE TypeSynonymInstances, ViewPatterns                     #-}-{-# OPTIONS_GHC -Wno-orphans #-}-module GHC.Compat (module GHC.Compat) where-import Data.Function       (on)-import FamInst             as GHC.Compat-import FastString          as GHC.Compat (fsLit)-import GHC.TcPluginM.Extra as GHC.Compat (evByFiat, lookupModule, lookupName,-                                          tracePlugin)-import GhcPlugins          as GHC.Compat (EqRel (..), PredTree (..))-import GhcPlugins          as GHC.Compat (classifyPredType, isEqPred,-                                          lookupTyCon, mkTyConTy)-import GhcPlugins          as GHC.Compat (mkTcOcc, ppr, promotedFalseDataCon)-import GhcPlugins          as GHC.Compat (promotedTrueDataCon, text)-import GhcPlugins          as GHC.Compat (tyConAppTyCon_maybe, typeKind)-import GhcPlugins          as GHC.Compat (typeNatKind)-import Module              as GHC.Compat (ModuleName, mkModuleName)-import OccName             as GHC.Compat (emptyOccSet, mkInstTyTcOcc)-import Plugins             as GHC.Compat (Plugin (..), defaultPlugin)-import TcEvidence          as GHC.Compat (EvTerm)-import TcHsType            as GHC.Compat (tcInferApps)-import TcPluginM           as GHC.Compat (TcPluginM, tcLookupTyCon,-                                          tcPluginTrace)-import TcRnMonad           as GHC.Compat (Ct, TcPluginResult (..), isWanted)-import TcRnTypes           as GHC.Compat (TcPlugin (..), ctEvPred, ctEvidence)-import TcType              as GHC.Compat (tcTyFamInsts)-import TcTypeNats          as GHC.Compat-import TyCon               as GHC.Compat-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 800-import           GhcPlugins (InScopeSet, Outputable, emptyUFM)-import qualified PrelNames  as Old-import           TyCoRep    as GHC.Compat (TyLit (NumTyLit), Type (..))-import           Type       as GHC.Compat (TCvSubst (..), TvSubstEnv,-                                           emptyTCvSubst)-import           Type       as GHC.Compat (eqType, unionTCvSubst)-import qualified Type       as Old-import           TysWiredIn as GHC.Compat (boolTyCon)-import           Unify      as Old (tcUnifyTy)-#else-import Type       as GHC.Compat (TvSubst, emptyTvSubst)-import Type       as GHC.Compat (substTy, unionTvSubst)-import TypeRep    as GHC.Compat (TyLit (NumTyLit), Type (..))-import TysWiredIn as Old (eqTyCon)-import TysWiredIn as GHC.Compat (promotedBoolTyCon)-import Unify      as GHC.Compat (tcUnifyTy)-#endif-import Data.Generics.Twins-import TcPluginM           (lookupOrig)-import TyCoRep             ()-import Type                as GHC.Compat (splitTyConApp_maybe)-import Unique              as GHC.Compat (getKey, getUnique)--#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 800-data TvSubst = TvSubst InScopeSet TvSubstEnv--instance Outputable  TvSubst where-  ppr = ppr . toTCv--emptyTvSubst :: TvSubst-emptyTvSubst = case emptyTCvSubst of-  TCvSubst set tvsenv _ -> TvSubst set tvsenv--toTCv :: TvSubst -> TCvSubst-toTCv (TvSubst set tvenv) = TCvSubst set tvenv emptyUFM--substTy :: TvSubst -> Type -> Type-substTy tvs = Old.substTy (toTCv tvs)--unionTvSubst :: TvSubst -> TvSubst -> TvSubst-unionTvSubst s1 s2 =-  fromTCv $ unionTCvSubst (toTCv s1) (toTCv s2)-fromTCv :: TCvSubst -> TvSubst-fromTCv (TCvSubst set tvsenv _) = TvSubst set tvsenv--promotedBoolTyCon :: TyCon-promotedBoolTyCon = boolTyCon--viewFunTy :: Type -> Maybe (Type, Type)-viewFunTy t@(TyConApp _ [t1, t2])-  | Old.isFunTy t = Just (t1, t2)-viewFunTy _ = Nothing--#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 802-#else-pattern FunTy :: Type -> Type -> Type-pattern FunTy t1 t2 <- (viewFunTy -> Just (t1, t2)) where-  FunTy t1 t2 = Old.mkFunTy t1 t2-#endif--tcUnifyTy :: Type -> Type -> Maybe TvSubst-tcUnifyTy t1 t2 = fromTCv <$> Old.tcUnifyTy t1 t2--getEqTyCon :: TcPluginM TyCon-getEqTyCon = tcLookupTyCon Old.eqTyConName--#else-eqType :: Type -> Type -> Bool-eqType = (==)--getEqTyCon :: TcPluginM TyCon-getEqTyCon = return Old.eqTyCon--#endif---getEqWitnessTyCon :: TcPluginM TyCon-getEqWitnessTyCon = do-  md <- lookupModule (mkModuleName "Data.Type.Equality") (fsLit "base")-  tcLookupTyCon =<< lookupOrig md (mkTcOcc ":~:")--decompFunTy :: Type -> [Type]-decompFunTy (FunTy t1 t2) = t1 : decompFunTy t2-decompFunTy t             = [t]--newtype TypeEq = TypeEq { runTypeEq :: Type }--instance Eq TypeEq where-  (==) = geq `on` runTypeEq--instance Ord TypeEq where-  compare = gcompare `on` runTypeEq
src/GHC/TypeLits/Presburger.hs view
@@ -1,389 +1,10 @@-{-# LANGUAGE CPP, DataKinds, FlexibleContexts, FlexibleInstances      #-}-{-# LANGUAGE LambdaCase, MultiWayIf, OverloadedStrings, PatternGuards #-}-{-# LANGUAGE RankNTypes, RecordWildCards, TypeOperators               #-}-{-# LANGUAGE TypeSynonymInstances                                     #-}-{-# OPTIONS_GHC -Wno-unused-imports #-}+-- | Provides a plain Presburger solver plugin for @'GHC.TypeNats.Nat'@.+--+--   For an interface for extension, see+--   "GHC.TypeLits.Presburger.Types". module GHC.TypeLits.Presburger (plugin) where-import GHC.Compat--import           Class                     (Class, classTyCon)-import           Control.Applicative       ((<|>))-import           Control.Monad             (forM_, mzero)-import           Control.Monad.State.Class-import           Control.Monad.Trans.Class-import           Control.Monad.Trans.Maybe (MaybeT (..))-import           Control.Monad.Trans.State (StateT, runStateT)-import           Data.Foldable             (asum)-import           Data.Integer.SAT          (Expr (..), Prop (..), PropSet,-                                            assert)-import           Data.Integer.SAT          (checkSat, noProps, toName)-import qualified Data.Integer.SAT          as SAT-import           Data.List                 (nub)-import qualified Data.Map.Strict           as M-import qualified Data.Map.Strict           as M-import           Data.Maybe                (catMaybes, fromJust)-import           Data.Maybe                (fromMaybe, isNothing, mapMaybe)-import           Data.Reflection           (Given, give, given)-import           GHC.TypeLits              (Nat)-import           Outputable                (showSDocUnsafe)-import           TcPluginM                 (getFamInstEnvs, lookupOrig,-                                            matchFam, newFlexiTyVar, newWanted,-                                            tcLookupClass, unsafeTcPluginTcM)-import           TcRnTypes-import           TyCoRep                   (Coercion (..), KindCoercion (..))-import           Type                      (mkPrimEqPredRole, mkTyVarTy,-                                            splitTyConApp)-import           TysWiredIn                (promotedEQDataCon,-                                            promotedGTDataCon,-                                            promotedLTDataCon)-import           Var--assert' :: Prop -> PropSet -> PropSet-assert' p ps = foldr assert ps (p : varPos)-  where-    varPos = [K 0 :<= Var i | i <- varsProp p ]--data Proof = Proved | Disproved [(Int, Integer)]-           deriving (Read, Show, Eq, Ord)--isProved :: Proof -> Bool-isProved Proved = True-isProved _      = False--varsProp :: Prop -> [SAT.Name]-varsProp (p :|| q) = nub $ varsProp p ++ varsProp q-varsProp (p :&& q) = nub $ varsProp p ++ varsProp q-varsProp (Not p)   = varsProp p-varsProp (e :== v) = nub $ varsExpr e ++ varsExpr v-varsProp (e :/= v) = nub $ varsExpr e ++ varsExpr v-varsProp (e :< v)  = nub $ varsExpr e ++ varsExpr v-varsProp (e :> v)  = nub $ varsExpr e ++ varsExpr v-varsProp (e :<= v) = nub $ varsExpr e ++ varsExpr v-varsProp (e :>= v) = nub $ varsExpr e ++ varsExpr v-varsProp _         = []--varsExpr :: Expr -> [SAT.Name]-varsExpr (e :+ v)   = nub $ varsExpr e ++ varsExpr v-varsExpr (e :- v)   = nub $ varsExpr e ++ varsExpr v-varsExpr (_ :* v)   = varsExpr v-varsExpr (Negate e) = varsExpr e-varsExpr (Var i)    = [i]-varsExpr (K _)      = []-varsExpr (If p e v) = nub $ varsProp p ++ varsExpr e ++ varsExpr v-varsExpr (Div e _)  = varsExpr e-varsExpr (Mod e _)  = varsExpr e+import GHC.TypeLits.Presburger.Types+import GhcPlugins  plugin :: Plugin-plugin = defaultPlugin { tcPlugin = const $ Just presburgerPlugin }--presburgerPlugin :: TcPlugin-presburgerPlugin =-  tracePlugin "typelits-presburger"-  TcPlugin { tcPluginInit  = return () -- tcPluginIO $ newIORef emptyTvSubst-           , tcPluginSolve = decidePresburger-           , tcPluginStop  = const $ return ()-           }--testIf :: PropSet -> Prop -> Proof-testIf ps q = maybe Proved Disproved $ checkSat (Not q `assert'` ps)--type PresState = ()--data MyEnv  = MyEnv { emptyClsTyCon       :: TyCon-                    , eqTyCon_            :: TyCon-                    , eqWitCon_           :: TyCon-                    , isTrueCon_          :: TyCon-                    , voidTyCon           :: TyCon-                    , typeLeqBoolTyCon_   :: TyCon-                    , singCompareCon_     :: TyCon-                    , caseNameForSingLeq_ :: TyCon-                    , caseNameForSingGeq_ :: TyCon-                    , caseNameForSingLt_  :: TyCon-                    , caseNameForSingGt_  :: TyCon-                    }-caseNameForSingLeq :: Given MyEnv => TyCon-caseNameForSingLeq = caseNameForSingLeq_ given-caseNameForSingGeq :: Given MyEnv => TyCon-caseNameForSingGeq = caseNameForSingGeq_ given-caseNameForSingLt  :: Given MyEnv => TyCon-caseNameForSingLt = caseNameForSingLt_ given-caseNameForSingGt  :: Given MyEnv => TyCon-caseNameForSingGt = caseNameForSingGt_ given--eqTyCon :: Given MyEnv => TyCon-eqTyCon = eqTyCon_ given--eqWitnessTyCon :: Given MyEnv => TyCon-eqWitnessTyCon = eqWitCon_ given--isTrueTyCon :: Given MyEnv => TyCon-isTrueTyCon = isTrueCon_ given--typeLeqBoolTyCon :: Given MyEnv => TyCon-typeLeqBoolTyCon = typeLeqBoolTyCon_ given--singCompareCon :: Given MyEnv => TyCon-singCompareCon = singCompareCon_ given--decidePresburger :: PresState -> [Ct] -> [Ct] -> [Ct] -> TcPluginM TcPluginResult-decidePresburger _ref gs [] [] = do-  tcPluginTrace "Started givens with: " (ppr $ map (ctEvPred . ctEvidence) gs)-  withTyCons $ do-    let subst = emptyTvSubst-                -- foldr unionTvSubst emptyTvSubst $ map genSubst gs-    ngs <- mapM (\a -> runMachine $ (,) a <$> toPresburgerPred subst (deconsPred a)) gs-    let givens = catMaybes ngs-        prems0 = map snd givens-        prems  = foldr assert' noProps prems0-        (solved, _) = foldr go ([], noProps) givens-    if isNothing (checkSat prems)-      then return $ TcPluginContradiction gs-      else return $ TcPluginOk (map withEv solved) []-    where-      go (ct, p) (ss, prem)-        | Proved <- testIf prem p = (ct : ss, prem)-        | otherwise = (ss, assert' p prem)-decidePresburger _ref gs ds ws = withTyCons $ do-  tcPluginTrace "Env" $ ppr (emptyTyCon, eqTyCon, eqWitnessTyCon, isTrueTyCon)-  let subst = foldr (unionTvSubst . genSubst) emptyTvSubst (gs ++ ds)-  tcPluginTrace "Current subst" (ppr subst)-  tcPluginTrace "wanteds" $ ppr $ map deconsPred ws-  tcPluginTrace "givens" $ ppr $ map (substTy subst . deconsPred) gs-  tcPluginTrace "deriveds" $ ppr $ map deconsPred ds-  (prems, wants) <- do-    wants <- catMaybes <$>-             mapM-             (\ct -> runMachine $ (,) ct <$> toPresburgerPred subst (substTy subst $ deconsPred ct))-             (filter (isWanted . ctEvidence) ws)-    resls <- mapM (runMachine . toPresburgerPred subst . substTy subst . deconsPred)-                     (gs ++ ds)-    let prems = foldr assert' noProps $ catMaybes resls-    return (prems, wants)-  let solved = map fst $ filter (isProved . testIf prems . snd) wants-      coerced = [(evByFiat "ghc-typelits-presburger" t1 t2, ct)-                | ct <- solved-                , EqPred NomEq t1 t2 <- return (classifyPredType $ deconsPred ct)-                ]-  -- tcPluginTrace "prems" (text $ show $ map (toPresburgerPred subst .substTy subst . deconsPred) (gs ++ ds))-  tcPluginTrace "final goals" (text $ show $ map snd wants)-  case testIf prems (foldr ((:&&) . snd) PTrue wants) of-    Proved -> do-      tcPluginTrace "Proved" (text $ show $ map snd wants)-      return $ TcPluginOk coerced []-    Disproved wit -> do-      tcPluginTrace "Failed! " (text $ show wit)-      return $ TcPluginContradiction $ map fst wants--withTyCons :: (Given MyEnv => TcPluginM a) -> TcPluginM a-withTyCons act = do-  emd <- lookupModule (mkModuleName "Proof.Propositional.Empty") (fsLit "equational-reasoning")-  emptyClsTyCon <- classTyCon <$> (tcLookupClass =<< lookupOrig emd (mkTcOcc "Empty"))-  eqTyCon_ <- getEqTyCon-  eqWitCon_ <- getEqWitnessTyCon-  pmd <- lookupModule (mkModuleName "Proof.Propositional") (fsLit "equational-reasoning")-  isTrueCon_ <- tcLookupTyCon =<< lookupOrig pmd (mkTcOcc "IsTrue")-  vmd <- lookupModule (mkModuleName "Data.Void") (fsLit "base")-  voidTyCon <- tcLookupTyCon =<< lookupOrig vmd (mkTcOcc "Void")-  singletons <- lookupModule (mkModuleName "Data.Singletons.Prelude.Ord") (fsLit "singletons")-#if MIN_VERSION_singletons(2,4,1)-  typeLeqBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc "<=")-  typeLtBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc "<")-  typeGeqBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc ">=")-  typeGtBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc ">")-#else-  typeLeqBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc ":<=")-  typeLtBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc ":<")-  typeGeqBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc ":>=")-  typeGtBoolTyCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc ":>")-#endif-  caseNameForSingLeq_ <- getCaseNameForSingletonOp typeLeqBoolTyCon_-  caseNameForSingLt_ <- getCaseNameForSingletonOp typeLtBoolTyCon_-  caseNameForSingGeq_ <- getCaseNameForSingletonOp typeGeqBoolTyCon_-  caseNameForSingGt_ <- getCaseNameForSingletonOp typeGtBoolTyCon_-  singCompareCon_ <- tcLookupTyCon =<< lookupOrig singletons (mkTcOcc "Compare")-  give MyEnv{..} act--getCaseNameForSingletonOp :: TyCon -> TcPluginM TyCon-getCaseNameForSingletonOp con = do-  let vars = [typeNatKind, LitTy (NumTyLit 0), LitTy (NumTyLit 0)]-  Just (appTy0, [n,b,bdy,r]) <- fmap (splitTyConApp . snd) <$> matchFam  con vars-  let (appTy, args) = splitTyConApp bdy-  Just innermost <- fmap snd <$> matchFam appTy args-  Just (_, dat) <- matchFam appTy0 [n,b,innermost,r]-  Just dat' <- fmap snd <$> uncurry matchFam (splitTyConApp dat)-  return $ fst $ splitTyConApp dat'--(<=>) :: Prop -> Prop -> Prop-p <=> q =  (p :&& q) :|| (Not p :&& Not q)--genSubst :: Ct -> TvSubst-genSubst ct = case classifyPredType (deconsPred ct) of-  EqPred NomEq t u -> fromMaybe emptyTvSubst $ tcUnifyTy t u-  _                -> emptyTvSubst--withEv :: Ct -> (EvTerm, Ct)-withEv ct-  | EqPred _ t1 t2 <- classifyPredType (deconsPred ct) =-      (evByFiat "ghc-typelits-presburger" t1 t2, ct)-  | otherwise = undefined--deconsPred :: Ct -> Type-deconsPred = ctEvPred . ctEvidence--emptyTyCon :: Given MyEnv => TyCon-emptyTyCon = emptyClsTyCon given--toPresburgerPred :: Given MyEnv => TvSubst -> Type -> Machine Prop-toPresburgerPred subst (TyConApp con [t1, t2])-  | con == typeNatLeqTyCon = (:<=) <$> toPresburgerExp subst t1 <*> toPresburgerExp subst t2-toPresburgerPred subst ty-  | isEqPred ty = toPresburgerPredTree subst $ classifyPredType ty-  | Just (con, [l, r]) <- splitTyConApp_maybe ty -- l ~ r-  , con == eqTyCon = toPresburgerPredTree subst $ EqPred NomEq l r-  | Just (con, [_k, l, r]) <- splitTyConApp_maybe ty -- l (:~: {k}) r-  , con == eqWitnessTyCon = toPresburgerPredTree subst $ EqPred NomEq l r-  | Just (con, [l]) <- splitTyConApp_maybe ty -- Empty l => ...-  , con == emptyTyCon = Not <$> toPresburgerPred subst l-  | Just (con, [l]) <- splitTyConApp_maybe ty -- IsTrue l =>-  , con == isTrueTyCon = toPresburgerPred subst l-  | otherwise = mzero--boolLeqs :: Given MyEnv => [TyCon]-boolLeqs = [typeNatLeqTyCon, typeLeqBoolTyCon]--toPresburgerPredTree :: Given MyEnv => TvSubst -> PredTree -> Machine Prop-toPresburgerPredTree subst (EqPred NomEq p false) -- P ~ 'False <=> Not P ~ 'True-  | Just promotedFalseDataCon  == tyConAppTyCon_maybe (substTy subst false) =-    Not <$> toPresburgerPredTree subst (EqPred NomEq p (mkTyConTy promotedTrueDataCon))-toPresburgerPredTree subst (EqPred NomEq p b)  -- (n :<=? m) ~ 'True-  | Just promotedTrueDataCon  == tyConAppTyCon_maybe (substTy subst b)-  , Just (con, [t1, t2]) <- splitTyConApp_maybe (substTy subst p)-  , con `elem` boolLeqs = (:<=) <$> toPresburgerExp subst t1  <*> toPresburgerExp subst t2-  | Just promotedTrueDataCon  == tyConAppTyCon_maybe (substTy subst b) -- Singleton's <=...-  , Just (con, [_,_,_,_,cmpTy]) <- splitTyConApp_maybe p-  , con == caseNameForSingLeq-  , Just (cmp, [l, r]) <- splitTyConApp_maybe cmpTy-  , cmp `elem` [singCompareCon, typeNatCmpTyCon] =-    (:<=) <$> toPresburgerExp subst l <*> toPresburgerExp subst r-  | Just promotedTrueDataCon  == tyConAppTyCon_maybe (substTy subst b) -- Singleton's <...-  , Just (con, [_,_,_,_,cmpTy]) <- splitTyConApp_maybe p-  , con == caseNameForSingLt-  , Just (cmp, [l, r]) <- splitTyConApp_maybe cmpTy-  , cmp `elem` [singCompareCon, typeNatCmpTyCon] =-    (:<) <$> toPresburgerExp subst l <*> toPresburgerExp subst r-  | Just promotedTrueDataCon  == tyConAppTyCon_maybe (substTy subst b) -- Singleton's >=...-  , Just (con, [_,_,_,_,cmpTy]) <- splitTyConApp_maybe p-  , con == caseNameForSingGeq-  , Just (cmp, [l, r]) <- splitTyConApp_maybe cmpTy-  , cmp `elem` [singCompareCon, typeNatCmpTyCon] =-    (:>=) <$> toPresburgerExp subst l <*> toPresburgerExp subst r-  | Just promotedTrueDataCon  == tyConAppTyCon_maybe (substTy subst b) -- Singleton's >=...-  , Just (con, [_,_,_,_,cmpTy]) <- splitTyConApp_maybe p-  , con == caseNameForSingGt-  , Just (cmp, [l, r]) <- splitTyConApp_maybe cmpTy-  , cmp `elem` [singCompareCon, typeNatCmpTyCon] =-    (:>) <$> toPresburgerExp subst l <*> toPresburgerExp subst r-toPresburgerPredTree subst (EqPred NomEq p q)  -- (p :: Bool) ~ (q :: Bool)-  | typeKind p `eqType` mkTyConTy promotedBoolTyCon =-    (<=>) <$> toPresburgerPred subst p-          <*> toPresburgerPred subst q-toPresburgerPredTree subst (EqPred NomEq n m)  -- (n :: Nat) ~ (m :: Nat)-  | typeKind n `eqType` typeNatKind =-    (:==) <$> toPresburgerExp subst n-          <*> toPresburgerExp subst m-toPresburgerPredTree subst (EqPred _ t1 t2) -- CmpNat a b ~ CmpNat c d-  | Just (con,  [a, b]) <- splitTyConApp_maybe (substTy subst t1)-  , Just (con', [c, d]) <- splitTyConApp_maybe (substTy subst t2)-  , con `elem` [singCompareCon, typeNatCmpTyCon], con' `elem` [typeNatCmpTyCon, singCompareCon]-  = (<=>) <$> ((:<) <$> toPresburgerExp subst a <*> toPresburgerExp subst b)-          <*> ((:<) <$> toPresburgerExp subst c <*> toPresburgerExp subst d)-toPresburgerPredTree subst (EqPred NomEq t1 t2) -- CmpNat a b ~ x-  | Just (con, [a, b]) <- splitTyConApp_maybe (substTy subst t1)-  , con `elem` [typeNatCmpTyCon, singCompareCon]-  , Just cmp <- tyConAppTyCon_maybe (substTy subst t2) =-    let dic = [(promotedLTDataCon, (:<))-              ,(promotedEQDataCon, (:==))-              ,(promotedGTDataCon, (:>))-              ]-    in MaybeT (return $ lookup cmp dic)-       <*> toPresburgerExp subst a-       <*> toPresburgerExp subst b-toPresburgerPredTree subst (EqPred NomEq t1 t2) -- x ~ CmpNat a b-  | Just (con, [a, b]) <- splitTyConApp_maybe (substTy subst t2)-  , con `elem` [singCompareCon, typeNatCmpTyCon]-  , Just cmp <- tyConAppTyCon_maybe (substTy subst t1) =-    let dic = [(promotedLTDataCon, (:<))-              ,(promotedEQDataCon, (:==))-              ,(promotedGTDataCon, (:>))-              ]-    in MaybeT (return $ lookup cmp dic)-       <*> toPresburgerExp subst a-       <*> toPresburgerExp subst b-toPresburgerPredTree subst (ClassPred con [t1, t2]) -- (n :: Nat) <= (m :: Nat)-  | typeNatLeqTyCon == classTyCon con-  , typeKind t1 `eqType` typeNatKind = (:<=) <$> toPresburgerExp subst t1 <*> toPresburgerExp subst t2-toPresburgerPredTree _ _ = mzero--toPresburgerExp :: TvSubst -> Type -> Machine Expr-toPresburgerExp dic ty = case substTy dic ty of-  TyVarTy t          -> return $ Var $ toName $ getKey $ getUnique t-  t@(TyConApp tc ts) -> body tc ts <|> Var . toName . getKey . getUnique <$> toVar t-  LitTy (NumTyLit n) -> return (K n)-  LitTy _            -> mzero-  t                  -> Var . toName . getKey .getUnique <$> toVar t-  where-    body tc ts =-      let step con op-            | tc == con, [tl, tr] <- ts =-              op <$> toPresburgerExp dic tl <*> toPresburgerExp dic tr-            | otherwise = mzero-      in case ts of-        [tl, tr] | tc == typeNatMulTyCon ->-          case (simpleExp tl, simpleExp tr) of-            (LitTy (NumTyLit n), LitTy (NumTyLit m)) -> return $ K $ n * m-            (LitTy (NumTyLit n), x) -> (:*) <$> pure n <*> toPresburgerExp dic x-            (x, LitTy (NumTyLit n)) -> (:*) <$> pure n <*> toPresburgerExp dic x-            _ -> mzero-        _ ->  asum [ step con op-                   | (con, op) <- [(typeNatAddTyCon, (:+)), (typeNatSubTyCon, (:-))]]---- simplTypeCmp :: Type -> Type--simpleExp :: Type -> Type-simpleExp (AppTy t1 t2) = AppTy (simpleExp t1) (simpleExp t2)-simpleExp (FunTy t1 t2) = FunTy (simpleExp t1) (simpleExp t2)-simpleExp (ForAllTy t1 t2) = ForAllTy t1 (simpleExp t2)-simpleExp (TyConApp tc ts) = fromMaybe (TyConApp tc (map simpleExp ts)) $-  asum (map simpler [(typeNatAddTyCon, (+))-                    ,(typeNatSubTyCon, (-))-                    ,(typeNatMulTyCon, (*))-                    ,(typeNatExpTyCon, (^))-                    ])-  where-    simpler (con, op)-      | con == tc, [tl, tr] <- map simpleExp ts =-        Just $-        case (tl, tr) of-          (LitTy (NumTyLit n), LitTy (NumTyLit m)) -> LitTy (NumTyLit (op n m))-          _ -> TyConApp con [tl, tr]-      | otherwise = Nothing-simpleExp t = t--type ParseEnv = M.Map TypeEq TyVar--type Machine = MaybeT (StateT ParseEnv TcPluginM)--runMachine :: Machine a -> TcPluginM (Maybe a)-runMachine act = do-  (ma, dic) <- runStateT (runMaybeT act) M.empty-  forM_ (M.toList dic) $ \(TypeEq ty, var) ->-    newWanted undefined $ mkPrimEqPredRole Nominal (mkTyVarTy var) ty-  return ma--toVar :: Type -> Machine TyVar-toVar ty = gets (M.lookup (TypeEq ty)) >>= \case-  Just v -> return v-  Nothing -> do-    v <- lift $ lift $ newFlexiTyVar $ typeKind ty-    modify $ M.insert (TypeEq ty) v-    return v+plugin = pluginWith defaultTranslation
+ src/GHC/TypeLits/Presburger/Compat.hs view
@@ -0,0 +1,194 @@+{-# LANGUAGE CPP, FlexibleInstances, PatternGuards, PatternSynonyms #-}+{-# LANGUAGE TypeSynonymInstances, ViewPatterns                     #-}+{-# OPTIONS_GHC -Wno-orphans #-}+module GHC.TypeLits.Presburger.Compat (module GHC.TypeLits.Presburger.Compat) where+import Data.Function       (on)+import FamInst             as GHC.TypeLits.Presburger.Compat+import FastString          as GHC.TypeLits.Presburger.Compat (fsLit)+import GHC.TcPluginM.Extra as GHC.TypeLits.Presburger.Compat (evByFiat, lookupModule, lookupName,+                                          tracePlugin)+import GhcPlugins          as GHC.TypeLits.Presburger.Compat (EqRel (..), PredTree (..))+import GhcPlugins          as GHC.TypeLits.Presburger.Compat (classifyPredType, isEqPred,+                                          lookupTyCon, mkTyConTy)+import GhcPlugins          as GHC.TypeLits.Presburger.Compat (mkTcOcc, ppr, promotedFalseDataCon)+import GhcPlugins          as GHC.TypeLits.Presburger.Compat (promotedTrueDataCon, text)+import GhcPlugins          as GHC.TypeLits.Presburger.Compat (tyConAppTyCon_maybe, typeKind)+import GhcPlugins          as GHC.TypeLits.Presburger.Compat (typeNatKind)+import Module              as GHC.TypeLits.Presburger.Compat (ModuleName, mkModuleName)+import OccName             as GHC.TypeLits.Presburger.Compat (emptyOccSet, mkInstTyTcOcc)+import Plugins             as GHC.TypeLits.Presburger.Compat (Plugin (..), defaultPlugin)+import TcEvidence          as GHC.TypeLits.Presburger.Compat (EvTerm)+import TcHsType            as GHC.TypeLits.Presburger.Compat (tcInferApps)+import TcPluginM           as GHC.TypeLits.Presburger.Compat (TcPluginM, tcLookupTyCon,+                                          tcPluginTrace)+import TcRnMonad           as GHC.TypeLits.Presburger.Compat (Ct, TcPluginResult (..), isWanted)+import TcRnTypes           as GHC.TypeLits.Presburger.Compat (TcPlugin (..), ctEvPred, ctEvidence)+import TcType              as GHC.TypeLits.Presburger.Compat (tcTyFamInsts)+import TcTypeNats          as GHC.TypeLits.Presburger.Compat+import TyCon               as GHC.TypeLits.Presburger.Compat+#if MIN_VERSION_ghc(8,4,1)+import TcType (TcTyVar, TcType)+#else+import TcRnTypes (cc_ev, ctev_pred)+import Data.Maybe+import TcPluginM (zonkCt)+#endif+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 800+import           GhcPlugins (InScopeSet, Outputable, emptyUFM)+import qualified PrelNames  as Old+import           TyCoRep    as GHC.TypeLits.Presburger.Compat (TyLit (NumTyLit), Type (..))+import           Type       as GHC.TypeLits.Presburger.Compat (TCvSubst (..), TvSubstEnv,+                                           emptyTCvSubst)+import           Type       as GHC.TypeLits.Presburger.Compat (eqType, unionTCvSubst)+import qualified Type       as Old+import           TysWiredIn as GHC.TypeLits.Presburger.Compat (boolTyCon)+import           Unify      as Old (tcUnifyTy)+#else+import Type       as GHC.TypeLits.Presburger.Compat (TvSubst, emptyTvSubst)+import Type       as GHC.TypeLits.Presburger.Compat (substTy, unionTvSubst)+import TypeRep    as GHC.TypeLits.Presburger.Compat (TyLit (NumTyLit), Type (..))+import TysWiredIn as Old (eqTyCon)+import TysWiredIn as GHC.TypeLits.Presburger.Compat (promotedBoolTyCon)+import Unify      as GHC.TypeLits.Presburger.Compat (tcUnifyTy)+#endif+import Data.Generics.Twins+import TcPluginM           (lookupOrig)+import TyCoRep             ()+import Type                as GHC.TypeLits.Presburger.Compat (splitTyConApp_maybe)+import Unique              as GHC.TypeLits.Presburger.Compat (getKey, getUnique)+#if MIN_VERSION_ghc(8,4,1)+import qualified GHC.TcPluginM.Extra as Extra+#endif+#if MIN_VERSION_ghc(8,8,1)+import qualified TysWiredIn+#endif++#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 800+data TvSubst = TvSubst InScopeSet TvSubstEnv++instance Outputable  TvSubst where+  ppr = ppr . toTCv++emptyTvSubst :: TvSubst+emptyTvSubst = case emptyTCvSubst of+  TCvSubst set tvsenv _ -> TvSubst set tvsenv++toTCv :: TvSubst -> TCvSubst+toTCv (TvSubst set tvenv) = TCvSubst set tvenv emptyUFM++substTy :: TvSubst -> Type -> Type+substTy tvs = Old.substTy (toTCv tvs)++unionTvSubst :: TvSubst -> TvSubst -> TvSubst+unionTvSubst s1 s2 =+  fromTCv $ unionTCvSubst (toTCv s1) (toTCv s2)+fromTCv :: TCvSubst -> TvSubst+fromTCv (TCvSubst set tvsenv _) = TvSubst set tvsenv++promotedBoolTyCon :: TyCon+promotedBoolTyCon = boolTyCon++viewFunTy :: Type -> Maybe (Type, Type)+viewFunTy t@(TyConApp _ [t1, t2])+  | Old.isFunTy t = Just (t1, t2)+viewFunTy _ = Nothing++#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 802+#else+pattern FunTy :: Type -> Type -> Type+pattern FunTy t1 t2 <- (viewFunTy -> Just (t1, t2)) where+  FunTy t1 t2 = Old.mkFunTy t1 t2+#endif++tcUnifyTy :: Type -> Type -> Maybe TvSubst+tcUnifyTy t1 t2 = fromTCv <$> Old.tcUnifyTy t1 t2++getEqTyCon :: TcPluginM TyCon+getEqTyCon =+#if MIN_VERSION_ghc(8,8,1)+  return TysWiredIn.eqTyCon+#else+  tcLookupTyCon Old.eqTyConName+#endif++#else+eqType :: Type -> Type -> Bool+eqType = (==)++getEqTyCon :: TcPluginM TyCon+getEqTyCon = return Old.eqTyCon++#endif+++getEqWitnessTyCon :: TcPluginM TyCon+getEqWitnessTyCon = do+  md <- lookupModule (mkModuleName "Data.Type.Equality") (fsLit "base")+  tcLookupTyCon =<< lookupOrig md (mkTcOcc ":~:")++decompFunTy :: Type -> [Type]+decompFunTy (FunTy t1 t2) = t1 : decompFunTy t2+decompFunTy t             = [t]++newtype TypeEq = TypeEq { runTypeEq :: Type }++instance Eq TypeEq where+  (==) = geq `on` runTypeEq++instance Ord TypeEq where+  compare = gcompare `on` runTypeEq++isTrivial :: Old.PredType -> Bool+isTrivial ty =+  case classifyPredType ty of+    EqPred _ l r -> l `eqType` r+    _ -> False++normaliseGivens+  :: [Ct] -> TcPluginM [Ct]+normaliseGivens =+#if MIN_VERSION_ghc(8,4,1)+  fmap (return . filter (not . isTrivial . ctEvPred . ctEvidence)) +  . (++) <$> id <*> Extra.flattenGivens+#else+  mapM zonkCt +#endif++#if MIN_VERSION_ghc(8,4,1)+type Substitution = [(TcTyVar, TcType)]+#else+type Substitution = TvSubst+#endif++subsCt :: Substitution -> Ct -> Ct+subsCt =+#if MIN_VERSION_ghc(8,4,1)+  Extra.substCt+#else+  \subst ct ->+  ct { cc_ev = (cc_ev ct) {ctev_pred = substTy subst (ctev_pred (cc_ev ct))}+     }+#endif++subsType :: Substitution -> Type -> Type+subsType =+#if MIN_VERSION_ghc(8,4,1)+  Extra.substType+#else+  substTy+#endif++mkSubstitution :: [Ct] -> Substitution+mkSubstitution =+#if MIN_VERSION_ghc(8,4,1)+  fst . unzip . Extra.mkSubst'+#else+  foldr (unionTvSubst . genSubst) emptyTvSubst+#endif++#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 804+genSubst :: Ct -> TvSubst+genSubst ct = case classifyPredType (ctEvPred . ctEvidence $ ct) of+  EqPred NomEq t u -> fromMaybe emptyTvSubst $ GHC.TypeLits.Presburger.Compat.tcUnifyTy t u+  _                -> emptyTvSubst+#endif
+ src/GHC/TypeLits/Presburger/Types.hs view
@@ -0,0 +1,501 @@+{-# LANGUAGE BangPatterns, CPP, DataKinds, FlexibleContexts               #-}+{-# LANGUAGE FlexibleInstances, LambdaCase, MultiWayIf, OverloadedStrings #-}+{-# LANGUAGE PatternGuards, RankNTypes, TypeOperators, ViewPatterns       #-}+-- | Since 0.3.0.0+module GHC.TypeLits.Presburger.Types+  ( pluginWith+  , defaultTranslation+  , Translation(..), ParseEnv, Machine+  , module Data.Integer.SAT+  ) where+import           Class                          (classTyCon)+import           Control.Applicative            ((<|>))+import           Control.Arrow                  (second)+import           Control.Monad                  (forM_, guard, mzero, unless)+import           Control.Monad.State.Class+import           Control.Monad.Trans.Class+import           Control.Monad.Trans.Maybe      (MaybeT (..))+import           Control.Monad.Trans.RWS.Strict (runRWS, tell)+import           Control.Monad.Trans.State      (StateT, runStateT)+import           Data.Foldable                  (asum)+import           Data.Integer.SAT               (Expr (..), Prop (..), PropSet,+                                                 assert)+import           Data.Integer.SAT               (checkSat, noProps, toName)+import qualified Data.Integer.SAT               as SAT+import           Data.List                      (nub)+import qualified Data.Map.Strict                as M+import           Data.Maybe                     (catMaybes, fromMaybe,+                                                 isNothing)+import           Data.Reflection                (Given, give, given)+import qualified Data.Set                       as Set+import           GHC.TypeLits.Presburger.Compat+import           PrelNames+import           TcPluginM                      (lookupOrig, newFlexiTyVar,+                                                 newWanted, tcLookupClass)+import           Type                           (mkPrimEqPredRole, mkTyVarTy)+import           TysWiredIn                     (promotedEQDataCon,+                                                 promotedGTDataCon,+                                                 promotedLTDataCon)+import           Var+#if MIN_VERSION_ghc(8,6,0)+import Plugins (purePlugin)+#endif++assert' :: Prop -> PropSet -> PropSet+assert' p ps = foldr assert ps (p : varPos)+  where+    varPos = [K 0 :<= Var i | i <- varsProp p ]++data Proof = Proved | Disproved [(Int, Integer)]+           deriving (Read, Show, Eq, Ord)++isProved :: Proof -> Bool+isProved Proved = True+isProved _      = False++varsProp :: Prop -> [SAT.Name]+varsProp (p :|| q) = nub $ varsProp p ++ varsProp q+varsProp (p :&& q) = nub $ varsProp p ++ varsProp q+varsProp (Not p)   = varsProp p+varsProp (e :== v) = nub $ varsExpr e ++ varsExpr v+varsProp (e :/= v) = nub $ varsExpr e ++ varsExpr v+varsProp (e :< v)  = nub $ varsExpr e ++ varsExpr v+varsProp (e :> v)  = nub $ varsExpr e ++ varsExpr v+varsProp (e :<= v) = nub $ varsExpr e ++ varsExpr v+varsProp (e :>= v) = nub $ varsExpr e ++ varsExpr v+varsProp _         = []++varsExpr :: Expr -> [SAT.Name]+varsExpr (e :+ v)   = nub $ varsExpr e ++ varsExpr v+varsExpr (e :- v)   = nub $ varsExpr e ++ varsExpr v+varsExpr (_ :* v)   = varsExpr v+varsExpr (Negate e) = varsExpr e+varsExpr (Var i)    = [i]+varsExpr (K _)      = []+varsExpr (If p e v) = nub $ varsProp p ++ varsExpr e ++ varsExpr v+varsExpr (Div e _)  = varsExpr e+varsExpr (Mod e _)  = varsExpr e++data PluginMode = DisallowNegatives+                | AllowNegatives+                deriving (Read, Show, Eq, Ord)++pluginWith :: TcPluginM Translation -> Plugin+pluginWith trans = defaultPlugin+    { tcPlugin = Just . presburgerPlugin trans . procOpts+#if MIN_VERSION_ghc(8,6,0)+    , pluginRecompile = purePlugin+#endif+    }+  where+    procOpts opts+      | "allow-negated-numbers" `elem` opts = AllowNegatives+      | otherwise = DisallowNegatives++presburgerPlugin :: TcPluginM Translation -> PluginMode -> TcPlugin+presburgerPlugin trans mode =+  tracePlugin "typelits-presburger"+  TcPlugin { tcPluginInit  = return ()+           , tcPluginSolve = decidePresburger mode trans+           , tcPluginStop  = const $ return ()+           }++testIf :: PropSet -> Prop -> Proof+testIf ps q = maybe Proved Disproved $ checkSat (Not q `assert'` ps)++-- Replaces every subtraction with new constant,+-- adding order constraint.+handleSubtraction :: PluginMode -> Prop -> Prop+handleSubtraction AllowNegatives p = p+handleSubtraction DisallowNegatives p0 =+  let (p, _, w) = runRWS (loop p0) () Set.empty+  in foldr (:&&) p w+  where+    loop PTrue     = return PTrue+    loop PFalse    = return PFalse+    loop (q :|| r) = (:||) <$> loop q <*> loop r+    loop (q :&& r) = (:&&) <$> loop q <*> loop r+    loop (Not q)   = Not <$> loop q+    loop (l :<= r) = (:<=) <$> loopExp l <*> loopExp r+    loop (l :< r)  = (:<) <$> loopExp l <*> loopExp r+    loop (l :>= r) = (:<=) <$> loopExp l <*> loopExp r+    loop (l :> r)  = (:>) <$> loopExp l <*> loopExp r+    loop (l :== r) = (:==) <$> loopExp l <*> loopExp r+    loop (l :/= r) = (:/=) <$> loopExp l <*> loopExp r+++    withPositive pos = do+      dic <- get+      unless (Set.member pos dic) $ do+        modify $ Set.insert pos+        tell $ Set.fromList [pos :>= K 0]+      return pos++    loopExp e@(Negate _) = withPositive . Negate =<< loopExp e+    loopExp (l :- r)   = do+      e <- (:-) <$> loopExp l <*> loopExp r+      withPositive e+    loopExp (l :+ r)     = (:+) <$> loopExp l <*> loopExp r+    loopExp v@Var {}     = return v+    loopExp (c :* e)+      | c > 0 = (c :*) <$> loopExp e+      | otherwise = (negate c :*) <$> loopExp (Negate e)+    loopExp e@(K _) = return e++data Translation =+  Translation+    { isEmpty     :: [TyCon]+    , isTrue      :: [TyCon]+    , trueData    :: [TyCon]+    , falseData   :: [TyCon]+    , voids       :: [TyCon]+    , tyEq        :: [TyCon]+    , tyEqBool    :: [TyCon]+    , tyEqWitness :: [TyCon]+    , tyNeqBool   :: [TyCon]+    , natPlus     :: [TyCon]+    , natMinus    :: [TyCon]+    , natExp      :: [TyCon]+    , natTimes    :: [TyCon]+    , natLeq      :: [TyCon]+    , natLeqBool  :: [TyCon]+    , natGeq      :: [TyCon]+    , natGeqBool  :: [TyCon]+    , natLt       :: [TyCon]+    , natLtBool   :: [TyCon]+    , natGt       :: [TyCon]+    , natGtBool   :: [TyCon]+    , orderingLT  :: [TyCon]+    , orderingGT  :: [TyCon]+    , orderingEQ  :: [TyCon]+    , natCompare  :: [TyCon]+    , parsePred   :: (Type -> Machine Expr) -> Type -> Machine Prop+    , parseExpr   :: Type -> Machine Expr+    }++instance Semigroup Translation where+  l <> r =+    Translation+      { isEmpty = isEmpty l <> isEmpty r+      , isTrue = isTrue l <> isTrue r+      , voids = voids l <> voids r+      , tyEq = tyEq l <> tyEq r+      , tyEqBool = tyEqBool l <> tyEqBool r+      , tyEqWitness = tyEqWitness l <> tyEqWitness r+      , tyNeqBool = tyNeqBool l <> tyNeqBool r+      , natPlus = natPlus l <> natPlus r+      , natMinus = natMinus l <> natMinus r+      , natTimes = natTimes l <> natTimes r+      , natExp = natExp l <> natExp r+      , natLeq = natLeq l <> natLeq r+      , natGeq = natGeq l <> natGeq r+      , natLt = natLt l <> natLt r+      , natGt = natGt l <> natGt r+      , natLeqBool = natLeqBool l <> natLeqBool r+      , natGeqBool = natGeqBool l <> natGeqBool r+      , natLtBool = natLtBool l <> natLtBool r+      , natGtBool = natGtBool l <> natGtBool r+      , orderingLT = orderingLT l <> orderingLT r+      , orderingGT = orderingGT l <> orderingGT r+      , orderingEQ = orderingEQ l <> orderingEQ r+      , natCompare = natCompare l <> natCompare r+      , trueData = trueData l <> trueData r+      , falseData = falseData l <> falseData r+      , parsePred = \f ty -> parsePred l f ty <|> parsePred r f ty+      , parseExpr = (<|>) <$> parseExpr l <*> parseExpr r+      }++instance Monoid Translation where+  mempty = Translation+    { isEmpty = mempty+    , isTrue = mempty+    , tyEq  = mempty+    , tyEqBool = mempty+    , tyEqWitness = mempty+    , tyNeqBool = mempty+    , voids = mempty+    , natPlus = mempty+    , natMinus = mempty+    , natTimes = mempty+    , natExp = mempty+    , natLeq = mempty+    , natGeq = mempty+    , natLt = mempty+    , natGt = mempty+    , natLeqBool = mempty+    , natGeqBool = mempty+    , natLtBool = mempty+    , natGtBool = mempty+    , orderingLT = mempty+    , orderingGT = mempty+    , orderingEQ = mempty+    , natCompare = mempty+    , trueData = []+    , falseData = []+    , parsePred = const $ const mzero+    , parseExpr = const mzero+    }++decidePresburger :: PluginMode -> TcPluginM Translation -> () -> [Ct] -> [Ct] -> [Ct] -> TcPluginM TcPluginResult+decidePresburger _ genTrans _ gs [] [] = do+  tcPluginTrace "Started givens with: " (ppr $ map (ctEvPred . ctEvidence) gs)+  trans <- genTrans+  give trans $ do+    ngs <- mapM (\a -> runMachine $ (,) a <$> toPresburgerPred (deconsPred a)) gs+    let givens = catMaybes ngs+        prems0 = map snd givens+        prems  = foldr assert' noProps prems0+        (solved, _) = foldr go ([], noProps) givens+    if isNothing (checkSat prems)+      then return $ TcPluginContradiction gs+      else return $ TcPluginOk (map withEv solved) []+    where+      go (ct, p) (ss, prem)+        | Proved <- testIf prem p = (ct : ss, prem)+        | otherwise = (ss, assert' p prem)+decidePresburger mode genTrans _ gs ds ws = do+  trans <- genTrans+  give trans $ do+    gs' <- normaliseGivens gs+    let subst = mkSubstitution (gs' ++ ds)+    tcPluginTrace "Current subst" (ppr subst)+    tcPluginTrace "wanteds" $ ppr $ map deconsPred ws+    tcPluginTrace "givens" $ ppr $ map (subsType subst . deconsPred) gs+    tcPluginTrace "deriveds" $ ppr $ map deconsPred ds+    (prems, wants, prems0) <- do+      wants <- catMaybes <$>+              mapM+              (\ct -> runMachine $ (,) ct <$> toPresburgerPred+                  ( subsType subst+                  $ deconsPred $ subsCt subst ct))+              (filter (isWanted . ctEvidence) ws)++      resls <- mapM (runMachine . toPresburgerPred . subsType subst . deconsPred)+                      (gs ++ ds)+      let prems = foldr assert' noProps $ catMaybes resls+      return (prems, map (second $ handleSubtraction mode) wants, catMaybes resls)+    let solved = map fst $ filter (isProved . testIf prems . snd) wants+        coerced = [(evByFiat "ghc-typelits-presburger" t1 t2, ct)+                  | ct <- solved+                  , EqPred NomEq t1 t2 <- return (classifyPredType $ deconsPred ct)+                  ]+    tcPluginTrace "final premises" (text $ show prems0)+    tcPluginTrace "final goals" (text $ show $ map snd wants)+    case testIf prems (foldr ((:&&) . snd) PTrue wants) of+      Proved -> do+        tcPluginTrace "Proved" (text $ show $ map snd wants)+        tcPluginTrace "... with coercions" (ppr coerced)+        return $ TcPluginOk coerced []+      Disproved wit -> do+        tcPluginTrace "Failed! " (text $ show wit)+        return $ TcPluginContradiction $ map fst wants++defaultTranslation :: TcPluginM Translation+defaultTranslation = do+  emd <- lookupModule (mkModuleName "Proof.Propositional.Empty") (fsLit "equational-reasoning")+  emptyClsTyCon <- classTyCon <$> (tcLookupClass =<< lookupOrig emd (mkTcOcc "Empty"))+  eqTyCon_ <- getEqTyCon+  eqWitCon_ <- getEqWitnessTyCon+  pmd <- lookupModule (mkModuleName "Proof.Propositional") (fsLit "equational-reasoning")+  isTrueCon_ <- tcLookupTyCon =<< lookupOrig pmd (mkTcOcc "IsTrue")+  vmd <- lookupModule (mkModuleName "Data.Void") (fsLit "base")+  voidTyCon <- tcLookupTyCon =<< lookupOrig vmd (mkTcOcc "Void")+  nLeq <- tcLookupTyCon =<< lookupOrig gHC_TYPENATS (mkTcOcc "<=")+  return+    mempty+    { isEmpty = [emptyClsTyCon]+    , tyEq = [eqTyCon_]+    , tyEqWitness = [eqWitCon_]+    , isTrue = [isTrueCon_]+    , voids = [voidTyCon]+    , natMinus = [typeNatSubTyCon]+    , natPlus = [typeNatAddTyCon]+    , natTimes = [typeNatMulTyCon]+    , natExp = [typeNatExpTyCon]+    , falseData = [promotedFalseDataCon]+    , trueData = [promotedTrueDataCon]+    , natLeqBool = [typeNatLeqTyCon]+    , natLeq = [nLeq]+    , natCompare = [typeNatCmpTyCon]+    , orderingEQ = [promotedEQDataCon]+    , orderingLT = [promotedLTDataCon]+    , orderingGT = [promotedGTDataCon]+    }++(<=>) :: Prop -> Prop -> Prop+p <=> q =  (p :&& q) :|| (Not p :&& Not q)++withEv :: Ct -> (EvTerm, Ct)+withEv ct+  | EqPred _ t1 t2 <- classifyPredType (deconsPred ct) =+      (evByFiat "ghc-typelits-presburger" t1 t2, ct)+  | otherwise = undefined++orderingDic :: Given Translation => [(TyCon, Expr -> Expr -> Prop)]+orderingDic =+  [(lt, (:<))  | lt <- orderingLT given ] +++  [(eq, (:==)) | eq <- orderingEQ given ] +++  [(gt, (:>))  | gt <- orderingGT given ]++deconsPred :: Ct -> Type+deconsPred = ctEvPred . ctEvidence++toPresburgerPred :: Given Translation => Type -> Machine Prop+toPresburgerPred (TyConApp con [t1, t2])+  | con `elem` (natLeq given ++ natLeqBool given)+  = (:<=) <$> toPresburgerExp t1 <*> toPresburgerExp t2+toPresburgerPred ty+  | Just (con, []) <- splitTyConApp_maybe ty+  , con `elem` trueData given = return PTrue+  | Just (con, []) <- splitTyConApp_maybe ty+  , con `elem` falseData given = return PFalse+  | isEqPred ty = toPresburgerPredTree $ classifyPredType ty+  | Just (con, [l, r]) <- splitTyConApp_maybe ty -- l ~ r+  , con `elem` (tyEq given ++ tyEqBool given)+  = toPresburgerPredTree $ EqPred NomEq l r+  | Just (con, [_k, l, r]) <- splitTyConApp_maybe ty -- l (:~: {k}) r+  , con `elem` tyEqWitness given = toPresburgerPredTree $ EqPred NomEq l r+  | Just (con, [l]) <- splitTyConApp_maybe ty -- Empty l => ...+  , con `elem` isEmpty given = Not <$> toPresburgerPred l+  | Just (con, [l]) <- splitTyConApp_maybe ty -- IsTrue l =>+  , con `elem` isTrue given = toPresburgerPred l+  | otherwise = parsePred given toPresburgerExp ty++splitTyConAppLastBin :: Type -> Maybe (TyCon, [Type])+splitTyConAppLastBin t = do+  (con, ts) <- splitTyConApp_maybe t+  let !n = length ts+  guard $ n >= 2+  return (con, drop (n - 2) ts)++toPresburgerPredTree :: Given Translation => PredTree -> Machine Prop+toPresburgerPredTree (EqPred NomEq p false) -- P ~ 'False <=> Not P ~ 'True+  | maybe False (`elem` falseData given) $ tyConAppTyCon_maybe false =+    Not <$> toPresburgerPredTree (EqPred NomEq p (mkTyConTy promotedTrueDataCon))+toPresburgerPredTree (EqPred NomEq p b)  -- (n :<=? m) ~ 'True+  | maybe False (`elem` trueData given) $ tyConAppTyCon_maybe b+  , Just (con, [t1, t2]) <- splitTyConAppLastBin p+  , con `elem` natLeqBool given = (:<=) <$> toPresburgerExp t1  <*> toPresburgerExp t2+toPresburgerPredTree (EqPred NomEq p q)  -- (p :: Bool) ~ (q :: Bool)+    | typeKind p `eqType` mkTyConTy promotedBoolTyCon = do+      lift $ lift $ tcPluginTrace "EQBOOL:" $ ppr (p, q)+      (<=>) <$> toPresburgerPred p+            <*> toPresburgerPred q+toPresburgerPredTree (EqPred NomEq n m)  -- (n :: Nat) ~ (m :: Nat)+  | typeKind n `eqType` typeNatKind =+    (:==) <$> toPresburgerExp n+          <*> toPresburgerExp m+toPresburgerPredTree (EqPred _ t1 t2) -- CmpNat a b ~ CmpNat c d+  | Just (con,  lastTwo -> [a, b]) <- splitTyConAppLastBin t1+  , Just (con', lastTwo -> [c, d]) <- splitTyConAppLastBin t2+  , con `elem` natCompare given, con' `elem` natCompare given+  = (<=>) <$> ((:<) <$> toPresburgerExp a <*> toPresburgerExp b)+          <*> ((:<) <$> toPresburgerExp c <*> toPresburgerExp d)+toPresburgerPredTree (EqPred NomEq t1 t2) -- CmpNat a b ~ x+  | Just (con, lastTwo -> [a, b]) <- splitTyConAppLastBin t1+  , con `elem` natCompare given+  , Just cmp <- tyConAppTyCon_maybe t2 =+    MaybeT (return $ lookup cmp orderingDic)+       <*> toPresburgerExp a+       <*> toPresburgerExp b+toPresburgerPredTree (EqPred NomEq t1 t2) -- x ~ CmpNat a b+  | Just (con, lastTwo -> [a, b]) <- splitTyConAppLastBin t2+  , con `elem` natCompare given+  , Just cmp <- tyConAppTyCon_maybe t1 =+    MaybeT (return $ lookup cmp orderingDic)+       <*> toPresburgerExp a+       <*> toPresburgerExp b+toPresburgerPredTree (ClassPred con ts)+  -- (n :: Nat) (<=| < | > | >= | == | /=) (m :: Nat)+  | let n = length ts, n >= 2+  , [t1, t2] <- drop (n - 2) ts+  , typeKind t1 `eqType` typeNatKind+  , typeKind t2 `eqType` typeNatKind =+    let p = lookup (classTyCon con) binPropDic+    in MaybeT (return p) <*> toPresburgerExp t1 <*> toPresburgerExp t2+toPresburgerPredTree _ = mzero++binPropDic :: Given Translation => [(TyCon, Expr -> Expr -> Prop)]+binPropDic =+  [ (n, (:<)) | n <- natLt given ++ natLtBool given ] +++  [ (n, (:>)) | n <- natGt given ++ natGtBool given ] +++  [ (n, (:<=)) | n <- natLeq given ++ natLeqBool given ] +++  [ (n, (:>=)) | n <- natGeq given ++ natGeqBool given ] +++  [ (n, (:==)) | n <- tyEq given ++ tyEqBool given ] +++  [ (n, (:/=)) | n <- tyNeqBool given ]++toPresburgerExp :: Given Translation => Type -> Machine Expr+toPresburgerExp ty = case ty of+  TyVarTy t          -> return $ Var $ toName $ getKey $ getUnique t+  t@(TyConApp tc ts) -> body tc ts <|> Var . toName . getKey . getUnique <$> toVar t+  LitTy (NumTyLit n) -> return (K n)+  LitTy _            -> mzero+  t                  ->+        parseExpr given ty+    <|> Var . toName . getKey .getUnique <$> toVar t+  where+    body tc ts =+      let step con op+            | tc == con, [tl, tr] <- lastTwo ts =+              op <$> toPresburgerExp tl <*> toPresburgerExp tr+            | otherwise = mzero+      in case ts of+        [tl, tr] | tc `elem` natTimes given ->+          case (simpleExp tl, simpleExp tr) of+            (LitTy (NumTyLit n), LitTy (NumTyLit m)) -> return $ K $ n * m+            (LitTy (NumTyLit n), x) -> (:*) <$> pure n <*> toPresburgerExp x+            (x, LitTy (NumTyLit n)) -> (:*) <$> pure n <*> toPresburgerExp x+            _ -> mzero+        _ ->  asum+           $  [ step con (:+)+              | con <- natPlus given+              ] +++              [ step con (:-)+              | con <- natMinus given+              ]+++-- simplTypeCmp :: Type -> Type++lastTwo :: [a] -> [a]+lastTwo = drop <$> subtract 2 . length <*> id++simpleExp :: Given Translation => Type -> Type+simpleExp (AppTy t1 t2) = AppTy (simpleExp t1) (simpleExp t2)+simpleExp (FunTy t1 t2) = FunTy (simpleExp t1) (simpleExp t2)+simpleExp (ForAllTy t1 t2) = ForAllTy t1 (simpleExp t2)+simpleExp (TyConApp tc (lastTwo -> ts)) = fromMaybe (TyConApp tc (map simpleExp ts)) $+  asum (map simpler+        $ [(c, (+)) | c <- natPlus given] +++          [(c, (-)) | c <- natMinus given] +++          [(c, (*)) | c <- natTimes given] +++          [(c, (^)) | c <- natExp given]+      )+  where+    simpler (con, op)+      | con == tc, [tl, tr] <- map simpleExp ts =+        Just $+        case (tl, tr) of+          (LitTy (NumTyLit n), LitTy (NumTyLit m)) -> LitTy (NumTyLit (op n m))+          _ -> TyConApp con [tl, tr]+      | otherwise = Nothing+simpleExp t = t++type ParseEnv = M.Map TypeEq TyVar++type Machine = MaybeT (StateT ParseEnv TcPluginM)++runMachine :: Machine a -> TcPluginM (Maybe a)+runMachine act = do+  (ma, dic) <- runStateT (runMaybeT act) M.empty+  forM_ (M.toList dic) $ \(TypeEq ty, var) ->+    newWanted undefined $ mkPrimEqPredRole Nominal (mkTyVarTy var) ty+  return ma++toVar :: Type -> Machine TyVar+toVar ty = gets (M.lookup (TypeEq ty)) >>= \case+  Just v -> return v+  Nothing -> do+    v <- lift $ lift $ newFlexiTyVar $ typeKind ty+    modify $ M.insert (TypeEq ty) v+    return v