diff --git a/AERN-Real.cabal b/AERN-Real.cabal
--- a/AERN-Real.cabal
+++ b/AERN-Real.cabal
@@ -1,5 +1,5 @@
 Name:           AERN-Real
-Version:        0.9.4
+Version:        0.9.5
 Cabal-Version:  >= 1.2
 Build-Type:     Simple
 License:        BSD3
@@ -9,7 +9,7 @@
 Maintainer:     mik@konecny.aow.cz
 Stability:      experimental
 Category:       Data, Math
-Synopsis:       datatypes and abstractions for approximating exact real numbers
+Synopsis:       arbitrary precision interval arithmetic for approximating exact real numbers
 Tested-with:    GHC ==6.8.2
 Description:
     Datatypes and abstractions for approximating exact real numbers
@@ -56,10 +56,10 @@
   hs-source-dirs:  src
   if flag(containers-in-base)
     Build-Depends:
-      base < 3, binary >= 0.4, haskell98
+      base < 3, binary >= 0.4
   else
     Build-Depends:
-      base >= 3, containers, binary >= 0.4, haskell98
+      base >= 3, containers, binary >= 0.4
   Exposed-modules:
     Data.Number.ER,
     Data.Number.ER.Real,
@@ -78,9 +78,11 @@
     Data.Number.ER.Real.Approx.Elementary,
     Data.Number.ER.Real.Approx.Interval,
     Data.Number.ER.Real.Approx,
+    Data.Number.ER.Real.DomainBox,
+    Data.Number.ER.Real.DomainBox.IntMap,
     Data.Number.ER.PlusMinus,
     Data.Number.ER.BasicTypes,
     Data.Number.ER.Misc,
     Data.Number.ER.ExtendedInteger
-  Extensions: DeriveDataTypeable, ForeignFunctionInterface, ScopedTypeVariables
+  Extensions: DeriveDataTypeable, ForeignFunctionInterface, ScopedTypeVariables, MultiParamTypeClasses, FunctionalDependencies, TypeSynonymInstances, FlexibleInstances
   
diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,11 @@
-0.9.4:
+0.9.5: 24 July 2008
+    * new operation for testing disjoing interiors
+    * real approximations not automatically instances of Ord
+      because comparison is not decidable in general;
+      one should use the four-valued compareReals instead of <, =<, ==
+    * removed rependency on haskell98
+
+0.9.4: 15 July 2008
     * fixed buggy formatting of floating point numbers
     * added a simple although inefficient linear solver
 
diff --git a/src/Data/Number/ER/BasicTypes.hs b/src/Data/Number/ER/BasicTypes.hs
--- a/src/Data/Number/ER/BasicTypes.hs
+++ b/src/Data/Number/ER/BasicTypes.hs
@@ -15,8 +15,6 @@
 
 import qualified Data.Number.ER.ExtendedInteger as EI
 
-import qualified Data.Map as Map
-
 {-|
     Precision represents an upper bound on the measure of 
     an approximation viewed as a set;
@@ -70,16 +68,4 @@
 
 gran2effIx :: Granularity -> EffortIndex
 gran2effIx = fromInteger . toInteger
-
-{-| 
-    A variable identifier for axes in function domains, polynomials etc.
--}
-type VarID = Int
-defaultVar :: VarID
-defaultVar = 0
-
-{-|
-    A many-dimensional point or interval.
--}
-type Box ira = Map.Map VarID ira
  
diff --git a/src/Data/Number/ER/Misc.hs b/src/Data/Number/ER/Misc.hs
--- a/src/Data/Number/ER/Misc.hs
+++ b/src/Data/Number/ER/Misc.hs
@@ -12,7 +12,7 @@
 -}
 module Data.Number.ER.Misc where
 
-import List
+import Data.List
 import System.IO.Unsafe
 
 unsafePrint msg val =
diff --git a/src/Data/Number/ER/Real/Approx.hs b/src/Data/Number/ER/Real/Approx.hs
--- a/src/Data/Number/ER/Real/Approx.hs
+++ b/src/Data/Number/ER/Real/Approx.hs
@@ -33,7 +33,10 @@
     effIx2ra,
     splitIRA,
 --    checkShrinking,
---    eqSingletons,
+    eqSingletons,
+    leqSingletons,
+    ltSingletons,
+    equalIntervals,
     exactMiddle,
     maxExtensionR2R
 )
@@ -48,7 +51,7 @@
    A type whose elements represent sets that can be used
    to approximate a single extended real number with arbitrary precision.
 -}
-class (Fractional ra, Ord ra) => ERApprox ra where
+class (Fractional ra) => ERApprox ra where
     getPrecision :: ra -> Precision 
     {-^ 
             Precision is a measure of the set size.
@@ -72,6 +75,11 @@
     -- ^ true if this is a singleton
     isDisjoint :: ra -> ra -> Bool
     isDisjoint a b = isEmpty $ a /\ b
+    isInteriorDisjoint :: ra -> ra -> Bool
+    isInteriorDisjoint a b = 
+        isEmpty isect || isExact isect 
+        where
+        isect = a /\ b
     isBounded :: ra -> Bool 
     -- ^ true if the approximation excludes infinity
     bottomApprox :: ra 
@@ -110,34 +118,6 @@
         String
     
 {-|
-    Assuming the arguments are singletons, equality is decidable.
--}
-eqSingletons :: (ERApprox ra) => ra -> ra -> Bool
-eqSingletons s1 s2 =  
-    case equalReals s1 s2 of 
-        Just b -> b
-        _ -> False 
-
-{-|
-    Assuming the arguments are singletons, @<=@ is decidable.
--}
-leqSingletons :: (ERApprox ra) => ra -> ra -> Bool
-leqSingletons s1 s2 =  
-    case compareReals s1 s2 of 
-        Just EQ -> True
-        Just LT -> True
-        _ -> False 
-        
-{-|
-    Assuming the arguments are singletons, @<@ is decidable.
--}
-ltSingletons :: (ERApprox ra) => ra -> ra -> Bool
-ltSingletons s1 s2 =  
-    case compareReals s1 s2 of 
-        Just LT -> True
-        _ -> False 
-        
-{-|
     For a finite sequence of real approximations, determine
     whether it is a shrinking sequence.
 -}    
@@ -189,40 +169,62 @@
     -}
     (\/) :: ira -> ira -> ira
     
+{-| 
+    Inverse of 'bounds'.
+-}
 bounds2ira ::
     (ERIntApprox ira) =>
-    ira -> ira -> ira
-bounds2ira = (\/)
-    
-{- old stuff that will probably never be resurrected:
-
---   It is intended that ra and ira are the same type.
---   We distinguish them so that we can conveniently
---   switch between two levels of abstraction when
---   working with values of this one type. 
---
---   Given some ra or ira, the other type is determined uniquely.       
+    (ira, ira) -> ira
+bounds2ira (a,b) = a \/ b
     
---    -- | coercion to more concrete view (allows a more intentional computation)
---    ra2ira :: ra -> ira
---    -- | coercion to more abstract view (guarantees certain extensionality and convergence properties)
---    ira2ra :: ira -> ra
+{-|
+    Assuming the arguments are singletons, equality is decidable.
+-}
+eqSingletons :: (ERApprox ra) => ra -> ra -> Bool
+eqSingletons s1 s2 =  
+    case equalReals s1 s2 of 
+        Just b -> b
+        _ -> False 
 
---    -- | coercion
---    ira2sra :: ira -> sra    
---    sraCover :: sra -> ira
---    sraAllIntervals :: sra -> [ira] -- ^ disjoint, in natural order
+{-|
+    Assuming the arguments are singletons, @<=@ is decidable.
 -}
+leqSingletons :: (ERApprox ra) => ra -> ra -> Bool
+leqSingletons s1 s2 =  
+    case compareReals s1 s2 of 
+        Just EQ -> True
+        Just LT -> True
+        _ -> False 
+        
+{-|
+    Assuming the arguments are singletons, @<@ is decidable.
+-}
+ltSingletons :: (ERApprox ra) => ra -> ra -> Bool
+ltSingletons s1 s2 =  
+    case compareReals s1 s2 of 
+        Just LT -> True
+        _ -> False 
+        
+{-|
+    Return true if and only if the two intervals have equal endpoints.
+-}
+equalIntervals ::
+    (ERIntApprox ira) => ira -> ira -> Bool
+equalIntervals d1 d2 =
+    d1L == d2L && d1U == d2U
+    where
+    (==) = eqSingletons
+    (d1L, d1U) = bounds d1
+    (d2L, d2U) = bounds d2
 
---
---bounds2ira :: 
---    (ERIntApprox ira) => 
---    ra -> 
---    ra -> 
---    ira
---bounds2ira leftRA rightRA =
---    (ra2ira leftRA) \/ (ra2ira rightRA)
 
+{-|    
+    This function converts
+    an effort index to a real number approximation.
+    
+    Useful when an effort index is used in a formula
+    mixed with real approximations.  
+-}
 effIx2ra :: 
     (ERApprox ra) =>
     EffortIndex -> ra
diff --git a/src/Data/Number/ER/Real/Approx/Elementary.hs b/src/Data/Number/ER/Real/Approx/Elementary.hs
--- a/src/Data/Number/ER/Real/Approx/Elementary.hs
+++ b/src/Data/Number/ER/Real/Approx/Elementary.hs
@@ -30,7 +30,7 @@
     All operations here have default implementations based on
     "Data.Number.ER.Real.Arithmetic.Elementary".
 -}
-class (RA.ERIntApprox ra) => (ERApproxElementary ra) 
+class (RA.ERIntApprox ra, Ord ra) => (ERApproxElementary ra) 
     where
     abs :: EffortIndex -> ra -> ra
     abs ix = Prelude.abs
diff --git a/src/Data/Number/ER/Real/Approx/Interval.hs b/src/Data/Number/ER/Real/Approx/Interval.hs
--- a/src/Data/Number/ER/Real/Approx/Interval.hs
+++ b/src/Data/Number/ER/Real/Approx/Interval.hs
@@ -410,8 +410,6 @@
         normaliseERInterval $
         (ERInterval (- (B.setGranularity gr (-l))) (B.setGranularity gr r))
     setGranularity _ i = i
-    {- isDisjoint -}
-    isDisjoint i1 i2 = RA.isEmpty $ i1 RA./\ i2
     {- bottomApprox -}  
     bottomApprox = ERIntervalAny
     {- emptyApprox -}  
@@ -486,21 +484,21 @@
         where
         infinity = 1/0
     doubleBounds ERIntervalEmpty = 
-        error "SuiteERInterval: iraDoubleBounds: empty interval"
+        error "ERInterval: doubleBounds: empty interval"
     doubleBounds (ERInterval l r) =
         (B.toDouble l, B.toDouble r) 
     floatBounds ERIntervalAny = (- infinity, infinity)
         where
         infinity = 1/0
     floatBounds ERIntervalEmpty = 
-        error "SuiteERInterval: iraFloatBounds: empty interval"
+        error "ERInterval: floatBounds: empty interval"
     floatBounds (ERInterval l r) =
         (B.toFloat l, B.toFloat r) 
     integerBounds ERIntervalAny = (- infinity, infinity)
         where
         infinity = EI.PlusInfinity
     integerBounds ERIntervalEmpty = 
-        error "SuiteERInterval: iraIntegerBounds: empty interval"
+        error "ERInterval: integerBounds: empty interval"
     integerBounds (ERInterval l r) = 
         (- (mkEI (- l)), mkEI r)
         where
diff --git a/src/Data/Number/ER/Real/Arithmetic/Elementary.hs b/src/Data/Number/ER/Real/Arithmetic/Elementary.hs
--- a/src/Data/Number/ER/Real/Arithmetic/Elementary.hs
+++ b/src/Data/Number/ER/Real/Arithmetic/Elementary.hs
@@ -51,13 +51,13 @@
 -}
 
 erSqr_IR ::
-    (RA.ERIntApprox ira) =>
+    (RA.ERIntApprox ira, Ord ira) =>
     EffortIndex -> 
     ira -> ira
 erSqr_IR = erSqr_R
 
 erSqr_R ::
-    (RA.ERIntApprox ira) =>
+    (RA.ERIntApprox ira, Ord ira) =>
     EffortIndex -> 
     ira -> ira
 erSqr_R ix a
@@ -74,14 +74,14 @@
 -}
 
 erPow_IR ::
-    (RA.ERIntApprox ira) =>
+    (RA.ERIntApprox ira, Ord ira) =>
     EffortIndex -> 
     Integer ->
     ira -> ira
 erPow_IR = erPow_R
 
 erPow_R ::
-    (RA.ERIntApprox ira) =>
+    (RA.ERIntApprox ira, Ord ira) =>
     EffortIndex ->
     Integer ->
     ira -> ira
@@ -105,12 +105,12 @@
 -}
 
 erSqrt_R ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> ira -> ira
 erSqrt_R = erSqrtNewton_R  
     
 erSqrt_IR ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> ira -> ira
 erSqrt_IR =
     RA.maxExtensionR2R 
@@ -124,12 +124,12 @@
 
 
 erSqrtContFr_R ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> ira -> ira
 erSqrtContFr_R ix a
     | aR == 0 = 0
     | aL == 1/0 = 1/0
-    | aR < 0 = RA.emptyApprox
+    | aR `RA.ltSingletons` 0 = RA.emptyApprox
     | otherwise =
         contFrIter (ix + 3) $
             RA.setMinGranularity gran $ max 0 (0 RA.\/ a) 
@@ -147,7 +147,7 @@
         x_iPlus1 = contFrIter (i - 1) x_i
             
 erSqrtNewton_R ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> ira -> ira
 erSqrtNewton_R ix a
     | RA.isEmpty a = RA.emptyApprox
@@ -177,12 +177,12 @@
 -}
 
 erRoot_R ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> Integer -> ira -> ira
 erRoot_R = erRootNewton_R    
     
 erRoot_IR ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> Integer -> ira -> ira
 erRoot_IR ix p =
     RA.maxExtensionR2R 
@@ -195,7 +195,7 @@
     | otherwise = []
 
 erRootNewton_R ::
-    (RA.ERIntApprox ira) => 
+    (RA.ERIntApprox ira, Ord ira) => 
     EffortIndex -> Integer -> ira -> ira
 erRootNewton_R ix p a
     | RA.isEmpty a = RA.emptyApprox
diff --git a/src/Data/Number/ER/Real/Arithmetic/LinearSolver.hs b/src/Data/Number/ER/Real/Arithmetic/LinearSolver.hs
--- a/src/Data/Number/ER/Real/Arithmetic/LinearSolver.hs
+++ b/src/Data/Number/ER/Real/Arithmetic/LinearSolver.hs
@@ -19,13 +19,17 @@
 where
 
 import qualified Data.Number.ER.Real.Approx as RA 
+import qualified Data.Number.ER.Real.DomainBox as DBox
+import Data.Number.ER.Real.DomainBox (VariableID(..), DomainBox, DomainIntBox)
 import Data.Number.ER.BasicTypes
 
 import Data.List
 import Data.Maybe
-import qualified Data.Map as Map
+--import qualified Data.Map as Map
 
+-- the following is code for unit testing 
 {-
+
 import Data.Number.ER.Real.DefaultRepr 
 
 eq1 :: (Box IRA, IRA)
@@ -44,14 +48,14 @@
 -}
 
 linearSolver ::
-    (RA.ERIntApprox ira) =>
-    [(Map.Map VarID ira, ira)] 
+    (RA.ERIntApprox ira, DomainIntBox box varid ira) =>
+    [(box, ira)] 
         {-^ the equations; 
             each equation has coefficients of linear terms 
               + constant term -} ->
-    Box ira {-^ the domain of the variables -} ->
+    box {-^ the domain of the variables -} ->
     ira {-^ an upper bound on the size of an acceptable solution box -} ->
-    Maybe (Box ira) 
+    Maybe box 
         {-^ 
             A box containing at least one solution within the domain; 
             Nothing if there is no solution. 
@@ -64,10 +68,13 @@
 linearSolver' eqns (b:bs) tolerance
     | not $ evalEqns b eqns = -- no solutions in the box
         linearSolver' eqns bs tolerance
-    | width (b Map.! (widestVar b)) < tolerance = 
+    | belowTolerance = 
         Just b
     | otherwise = 
-        linearSolver' eqns (splitBox b ++ bs) tolerance               
+        linearSolver' eqns (splitBox b ++ bs) tolerance
+    where
+    belowTolerance =
+        and $ map (\d -> width d `RA.ltSingletons` tolerance) $ DBox.elems b
 
 evalEqns box eqns =
     and $ map (evalEqn box) eqns
@@ -78,38 +85,27 @@
 evalEqn box (expr,cons) = 
     cons `RA.refines` (evalExpr expr box)
     where
-    evalExpr expr box = Map.fold (+) 0 $ Map.unionWith (*) expr box
+    evalExpr expr box = sum $ DBox.elems $ DBox.intersectionWith (*) expr box
 
 {-|
     returns the list of (two) boxes resulting from splitting the widest edge 
     of the box in half
 -}
 splitBox box =
-    [Map.insert k (iLg RA.\/ iMg) box, Map.insert k (iMg RA.\/ iRg) box]
+    [DBox.insert k (iLg RA.\/ iMg) box, 
+     DBox.insert k (iMg RA.\/ iRg) box]
     where
     iMg = (iLg+iRg)/2
     iLg = incrementGranularity iL
     iRg = incrementGranularity iR
     (iL,iR) = RA.bounds i
-    i = box Map.! k
+    i = DBox.lookup "ER: LinearSolver: splitBox: " k box
     k = widestVar box
     incrementGranularity x =
         RA.setMinGranularity (RA.getGranularity x + 1) x
 
 widestVar box =
-    fst $ maxm (head widthMap) $ tail widthMap
-    where
-    widthMap = 
-        Map.assocs $ Map.map width box
-    maxm m [] = m
-    maxm m (x:xs) = 
-        if mW < xW then 
-            maxm x xs 
-        else 
-            maxm m xs
-        where
-        mW = snd m
-        xW = snd x
+    fst $ DBox.bestSplit box    
 
 width i =
     snd $ RA.bounds (iR-iL)
diff --git a/src/Data/Number/ER/Real/Base/Float.hs b/src/Data/Number/ER/Real/Base/Float.hs
--- a/src/Data/Number/ER/Real/Base/Float.hs
+++ b/src/Data/Number/ER/Real/Base/Float.hs
@@ -282,10 +282,12 @@
 
 instance Ord ERFloat where
     {- compare NaN -}
-    compare _ (ERFloatNaN _) = 
-        error "ERFloat: comparing NaN - aborting"
-    compare (ERFloatNaN _) _ = 
-        error "ERFloat: comparing NaN - aborting"
+    compare a b@(ERFloatNaN _) =
+        unsafePrint ("ERFloat: comparing NaN: " ++ show a ++ " vs. " ++ show b) EQ 
+--        error $ "ERFloat: comparing NaN: " ++ show a ++ " vs. " ++ show b 
+    compare a@(ERFloatNaN _) b = 
+        unsafePrint ("ERFloat: comparing NaN: " ++ show a ++ " vs. " ++ show b) EQ 
+--        error $ "ERFloat: comparing NaN: " ++ show a ++ " vs. " ++ show b 
     {- compare infty -}
     compare (ERFloatInfty gr1 pm1) (ERFloatInfty gr2 pm2) =
         compare pm1 pm2
diff --git a/src/Data/Number/ER/Real/DomainBox.hs b/src/Data/Number/ER/Real/DomainBox.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Number/ER/Real/DomainBox.hs
@@ -0,0 +1,142 @@
+{-# LANGUAGE MultiParamTypeClasses  #-}
+{-# LANGUAGE FunctionalDependencies  #-}
+{-|
+    Module      :  Data.Number.ER.Real.DomainBox
+    Description :  portions of many-dimensional domains   
+    Copyright   :  (c) Michal Konecny
+    License     :  BSD3
+
+    Maintainer  :  mik@konecny.aow.cz
+    Stability   :  experimental
+    Portability :  portable
+
+    Abstractions of the 'Box' datatype, often used to represent
+    sections of multi-dimensional function domains.
+    
+    To be imported qualified, usually with prefix DBox.
+    
+    VariableID(..) and DomainBox 
+    are usually imported separately and not qualified.
+-}
+module Data.Number.ER.Real.DomainBox 
+(
+    VariableID(..),
+    DomainBox(..),
+    DomainIntBox(..)
+)
+where
+
+import qualified Data.Number.ER.Real.Approx as RA
+
+import Data.Number.ER.BasicTypes
+
+import qualified Data.Set as Set
+import qualified Data.Map as Map
+
+import Prelude hiding (lookup)
+
+
+{-| 
+    A class abstracting a type of variable identifiers 
+    for axes in function domains, polynomials etc.
+-}
+class (Ord varid) => VariableID varid
+    where
+    newVarID :: Set.Set varid -> varid
+    defaultVar :: varid
+    defaultVar = newVarID Set.empty
+    showVar :: varid -> String
+
+{-|
+    A class abstracting a type of many-dimensional points or intervals.
+-}
+class (VariableID varid) => DomainBox box varid ira
+    | box -> varid ira, varid ira -> box
+    where
+    noinfo :: box
+    isNoinfo :: box -> Bool
+    {-| constructor using 'defaultVar' -}
+    unary :: ira -> box
+    singleton :: varid -> ira -> box
+    toList :: box -> [(varid, ira)]
+    fromList :: [(varid, ira)] -> box
+    toAscList :: box -> [(varid, ira)]
+    fromAscList :: [(varid, ira)] -> box
+    toMap :: box -> Map.Map varid ira
+    fromMap :: Map.Map varid ira -> box
+    insert :: varid -> ira -> box -> box
+    insertWith :: (ira -> ira -> ira) -> varid -> ira -> box -> box
+    delete :: varid -> box -> box
+    member :: varid -> box -> Bool
+    notMember :: varid -> box -> Bool
+    union :: box -> box -> box
+    unionWith :: (ira -> ira -> ira) -> box -> box -> box
+    keys :: box -> [varid]
+    elems :: box -> [ira]
+    map :: (ira -> ira) -> box -> box
+    fold :: (ira -> a -> a) -> a -> box -> a
+    foldWithKey :: (varid -> ira -> a -> a) -> a -> box -> a
+    zipWith :: (ira -> ira -> a) -> box -> box -> [(varid, a)] 
+    intersectionWith :: (ira -> ira -> ira) -> box -> box -> box 
+    findWithDefault :: ira -> varid -> box -> ira
+    {-|
+        Pick the extents of a single variable in a domain box.
+        If there is no information for this variable, assume the
+        variable ranges over the whole real line.
+    -}
+    lookup ::     
+        String {-^ identification of caller location to use in error messages -} ->
+        varid ->
+        box ->
+        ira
+        
+        
+{-|
+    A class abstracting a type of many-dimensional intervals.
+-}
+class (DomainBox box varid ira) => DomainIntBox box varid ira
+    | box -> varid ira, varid ira -> box
+    where
+    {-|
+        Check whether the two domains specify the same
+        interval for each variable that they share.
+    -}
+    compatible ::
+        box ->
+        box ->
+        Bool
+    {-|
+        Assuming that two domains are compatible, take the
+        most information from both of the domains about the
+        ranges of variables.
+    -}
+    unify ::
+        String {-^ identification of caller location to use in error messages -} ->
+        box ->
+        box ->
+        box
+    {-|
+        Find the variable with the largest interval
+        and return it together with the default splitting point
+        in its domain.
+    -}
+    bestSplit ::
+        box ->
+        (varid, ira)
+    classifyPosition ::
+        box {-^ domain @d1@ -} ->
+        box {-^ domain @d2@ -} ->
+        (Bool, Bool, Bool, Bool) 
+            {-^ 
+                Answers to these (mutually exclusive) questions:
+                
+                * is @d1@ outside and /not/ touching @d2@?
+            
+                * is @d1@ outside and touching @d2@?
+            
+                * is @d1@ intersecting and not inside @d2@?
+            
+                * is @d1@ inside @d2@?
+            -}
+
+            
diff --git a/src/Data/Number/ER/Real/DomainBox/IntMap.hs b/src/Data/Number/ER/Real/DomainBox/IntMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Number/ER/Real/DomainBox/IntMap.hs
@@ -0,0 +1,128 @@
+{-# LANGUAGE MultiParamTypeClasses  #-}
+{-# LANGUAGE FlexibleInstances   #-}
+{-# LANGUAGE TypeSynonymInstances   #-}
+{-|
+    Module      :  Data.Number.ER.Real.DomainBox.IntMap
+    Description :  implementation of DomainBox based on Data.Map   
+    Copyright   :  (c) Michal Konecny
+    License     :  BSD3
+
+    Maintainer  :  mik@konecny.aow.cz
+    Stability   :  experimental
+    Portability :  portable
+
+    A simple implementation of the 'VariableID' and 'DomainBox' classes.
+-}
+module Data.Number.ER.Real.DomainBox.IntMap 
+(
+    VarID, Box
+)
+where
+
+import qualified Data.Number.ER.Real.Approx as RA
+import Data.Number.ER.Real.DomainBox
+
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+
+type VarID = Int
+type Box ira = Map.Map VarID ira
+
+instance VariableID VarID
+    where
+    newVarID prevVars 
+        | Set.null prevVars = 0
+        | otherwise =
+            1 + (Set.findMax prevVars)
+    showVar v = "x" ++ show v
+
+instance (Show ira) => (DomainBox (Box ira) VarID ira)
+    where
+    noinfo = Map.empty
+    isNoinfo = Map.null
+    unary r = Map.singleton defaultVar r
+    singleton = Map.singleton
+    toList = Map.toList
+    fromList = Map.fromList
+    toAscList = Map.toAscList
+    fromAscList = Map.fromAscList
+    toMap = id
+    fromMap = id
+    insert = Map.insert
+    insertWith = Map.insertWith
+    delete = Map.delete
+    member = Map.member 
+    notMember = Map.notMember
+    union = Map.union 
+    unionWith = Map.unionWith 
+    elems = Map.elems
+    keys = Map.keys
+    map = Map.map
+    fold = Map.fold
+    foldWithKey = Map.foldWithKey
+    zipWith f b1 b2 = Map.toList $ Map.intersectionWith f b1 b2
+    intersectionWith = Map.intersectionWith
+    findWithDefault = Map.findWithDefault
+    lookup locspec var dom =
+        Map.findWithDefault err var dom
+        where
+        err =
+            error $
+                locspec ++ "DomainBox.IntMap lookup: domain box " ++ show dom 
+                ++ " ignores variable " ++ show var
+
+instance (RA.ERIntApprox ira) => DomainIntBox (Box ira) VarID ira
+    where
+    compatible dom1 dom2 =
+        Map.fold (&&) True $
+            Map.intersectionWith RA.equalIntervals dom1 dom2
+    unify locspec dom1 dom2
+        | compatible dom1 dom2 =
+            Map.union dom1 dom2
+        | otherwise =
+            error $
+                locspec ++ "incompatible domains " ++ show dom1 ++ " and " ++ show dom2
+    bestSplit dom =
+        (var, pt)
+        where
+        pt = 
+            RA.defaultBisectPt varDom
+        (_, (varDom, var)) = 
+            foldl findWidestVar (0, err) $ Map.toList dom
+        err =
+            error $ "DomainBox: bestSplit: failed to find a split for " ++ show dom 
+        findWidestVar (prevWidth, prevRes) (v, d)
+            | currWidth `RA.leqSingletons` prevWidth = (prevWidth, prevRes)
+            | otherwise = (currWidth, (d, v))
+            where
+            currWidth = snd $ RA.bounds $ domHI - domLO
+            (domLO, domHI) = RA.bounds d
+    classifyPosition dom sdom =    
+        (away, touch, intersect, inside)
+            where
+            (away, touch, inside, intersect) =
+                Map.fold addDimension (True, True, True, False) awayTouchInsides
+            addDimension 
+                    (prevAway, prevTouch, prevInside, prevIntersect) 
+                    (thisAway, thisTouch, thisInside, thisIntersect) =
+                (prevAway && thisAway, 
+                 (prevTouch || prevAway) && (thisTouch || thisAway) && (prevTouch || thisTouch),
+                 prevInside && thisInside,
+                 prevIntersect || thisIntersect)
+            awayTouchInsides =
+                Map.intersectionWith classifyRA dom sdom
+            classifyRA d sd =
+                (outsideNoTouch, outsideTouch, inside,
+                 not (outsideNoTouch || outsideTouch || inside))
+                 where
+                 outsideNoTouch = sdR < dL || dR < sdL
+                 outsideTouch = sdR == dL || dR == sdL
+                 inside = sdL =< dL && dR =< sdR
+                 (==) = RA.eqSingletons
+                 (<) = RA.ltSingletons
+                 (=<) = RA.leqSingletons
+                 (dL, dR) = RA.bounds d 
+                 (sdL, sdR) = RA.bounds sd 
+        
+
+    
