UIMA-5306 -  trying to provide alternative impl

git-svn-id: https://svn.apache.org/repos/asf/uima/ruta/branches/RutaBasicMemory@1783905 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/action/GetListAction.java b/ruta-core/src/main/java/org/apache/uima/ruta/action/GetListAction.java
index cf1a3bd..95c24c0 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/action/GetListAction.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/action/GetListAction.java
@@ -23,6 +23,7 @@
 import java.util.Collection;

 import java.util.HashSet;

 import java.util.List;

+import java.util.Map;

 import java.util.Set;

 

 import org.apache.uima.cas.Type;

@@ -71,30 +72,30 @@
     for (AnnotationFS matched : matchedAnnotations) {

 

       if (TYPES_AT_BEGIN.equals(op)) {

-        RutaBasic beginAnchor = stream.getBeginAnchor(matched.getBegin());

-        Collection<?>[] beginMap = beginAnchor.getBeginMap();

-        Set<AnnotationFS> aset = new HashSet<AnnotationFS>();

-        for (Collection<?> set : beginMap) {

-          if (set != null) {

-            aset.addAll((Collection<? extends AnnotationFS>) set);

-          }

-        }

-        for (AnnotationFS annotationFS : aset) {

-          list.add(annotationFS.getType());

-        }

+//        RutaBasic beginAnchor = stream.getBeginAnchor(matched.getBegin());

+//        Map<Integer, Collection<?>> beginMap = beginAnchor.getBeginMap();

+//        Set<AnnotationFS> aset = new HashSet<AnnotationFS>();

+//        for (Collection<?> set : beginMap.values()) {

+//          if (set != null) {

+//            aset.addAll((Collection<? extends AnnotationFS>) set);

+//          }

+//        }

+//        for (AnnotationFS annotationFS : aset) {

+//          list.add(annotationFS.getType());

+//        }

       } else if (TYPES_AT_END.equals(op)) {

-        RutaBasic endAnchor = stream.getEndAnchor(matched.getEnd());

-        // Collection<Set<AnnotationFS>> values = endAnchor.getEndMap().values();

-        Collection<?>[] endMap = endAnchor.getEndMap();

-        Set<AnnotationFS> aset = new HashSet<AnnotationFS>();

-        for (Collection<?> set : endMap) {

-          if (set != null) {

-            aset.addAll((Collection<? extends AnnotationFS>) set);

-          }

-        }

-        for (AnnotationFS annotationFS : aset) {

-          list.add(annotationFS.getType());

-        }

+//        RutaBasic endAnchor = stream.getEndAnchor(matched.getEnd());

+//        // Collection<Set<AnnotationFS>> values = endAnchor.getEndMap().values();

+//        Map<Integer, Collection<?>> endMap = endAnchor.getEndMap();

+//        Set<AnnotationFS> aset = new HashSet<AnnotationFS>();

+//        for (Collection<?> set : endMap.values()) {

+//          if (set != null) {

+//            aset.addAll((Collection<? extends AnnotationFS>) set);

+//          }

+//        }

+//        for (AnnotationFS annotationFS : aset) {

+//          list.add(annotationFS.getType());

+//        }

       } else if (TYPES.equals(op)) {

         Type annotationType = stream.getCas().getAnnotationType();

         List<AnnotationFS> inWindow = stream.getAnnotationsInWindow(matched, annotationType);

diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/engine/MemoryFootprintTest.java b/ruta-core/src/test/java/org/apache/uima/ruta/engine/MemoryFootprintTest.java
new file mode 100644
index 0000000..b17c503
--- /dev/null
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/engine/MemoryFootprintTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.ruta.engine;
+
+import java.util.Collection;
+
+import org.apache.uima.analysis_engine.AnalysisEngine;
+import org.apache.uima.fit.factory.AnalysisEngineFactory;
+import org.apache.uima.fit.factory.JCasFactory;
+import org.apache.uima.fit.util.JCasUtil;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.ruta.type.TruePositive;
+import org.junit.Test;
+
+public class MemoryFootprintTest {
+
+  public static void main(String[] args) throws Exception {
+//     Thread.sleep(20000);
+
+    System.out.println("Start");
+    new MemoryFootprintTest().test();
+    new MemoryFootprintTest().test();
+//    new MemoryFootprintTest().test();
+//    new MemoryFootprintTest().test();
+  }
+
+  @Test
+  public void test() throws Exception {
+
+    int lines = 25000;
+    String line = "This is a simple line with a number like 24 and some special characters like %&$.\n";
+    String rules = "CW SW{-> TruePositive};CW SW{-> TruePositive};CW SW{-> TruePositive};CW SW{-> TruePositive};CW SW{-> TruePositive};";
+
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0; i < lines; i++) {
+      sb.append(line);
+    }
+
+    JCas jcas = JCasFactory.createJCas();
+    jcas.setDocumentText(sb.toString());
+
+    AnalysisEngine ae = AnalysisEngineFactory.createEngine(RutaEngine.class, RutaEngine.PARAM_RULES,
+            rules);
+
+    long start = System.currentTimeMillis();
+    ae.process(jcas);
+    long end = System.currentTimeMillis();
+    System.out.println("took " + (end - start) / 1000);
+    System.out.println("freeMemory " + Runtime.getRuntime().freeMemory() / 1000000);
+    System.out.println("maxMemory " + Runtime.getRuntime().maxMemory() / 1000000);
+    System.out.println("totalMemory " + Runtime.getRuntime().totalMemory() / 1000000);
+
+    Collection<TruePositive> select = JCasUtil.select(jcas, TruePositive.class);
+    System.out.println("TruePositive: " + select.size());
+    jcas.release();
+  }
+
+}
diff --git a/ruta-typesystem/pom.xml b/ruta-typesystem/pom.xml
index 9347fd1..34f05bc 100644
--- a/ruta-typesystem/pom.xml
+++ b/ruta-typesystem/pom.xml
@@ -30,6 +30,11 @@
   <name>Apache UIMA Ruta: ${project.artifactId}</name>
   <dependencies>
     <dependency>
+        <groupId>it.unimi.dsi</groupId>
+        <artifactId>fastutil</artifactId>
+        <version>7.1.0</version>
+    </dependency>
+    <dependency>
       <groupId>org.apache.uima</groupId>
       <artifactId>uimaj-core</artifactId>
       <version>${uimaVersion}</version>
diff --git a/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic.java b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic.java
index a2b80f6..6cd6f45 100644
--- a/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic.java
+++ b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic.java
@@ -23,20 +23,25 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.FeatureStructureImpl;
+import org.apache.uima.cas.impl.LowLevelCAS;
 import org.apache.uima.cas.impl.TypeImpl;
-import org.apache.uima.cas.impl.TypeSystemImpl;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.JCas;
 import org.apache.uima.jcas.JCasRegistry;
 import org.apache.uima.jcas.cas.TOP_Type;
 import org.apache.uima.jcas.tcas.Annotation;
 
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+
 /**
- * Updated by JCasGen Thu Jul 12 10:42:33 CEST 2012 XML source:
- * D:/work/workspace-uima6/uimaj-ruta/src
- * /main/java/org/apache/uima/ruta/engine/InternalTypeSystem.xml
  * 
  * @generated
  */
@@ -44,19 +49,17 @@
 
   private static final int INITIAL_CAPACITY = 2;
 
-  private static final String ROOT_TYPE1 = "uima.tcas.Annotation";
+  private static final String ROOT_TYPE1 = CAS.TYPE_NAME_ANNOTATION;
 
-  private static final String ROOT_TYPE2 = "uima.cas.AnnotationBase";
+  private static final String ROOT_TYPE2 = CAS.TYPE_NAME_ANNOTATION_BASE;
 
   private boolean lowMemoryProfile = false;
 
-  private int[] partOf = new int[((TypeSystemImpl) getCAS().getTypeSystem()).getLargestTypeCode()];
+  private Int2IntOpenHashMap partOf;
 
-  private Collection<?>[] beginMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem())
-          .getLargestTypeCode()];
+  private Int2ObjectOpenHashMap<IntArrayList> beginMap;
 
-  private Collection<?>[] endMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem())
-          .getLargestTypeCode()];
+  private Int2ObjectOpenHashMap<IntArrayList> endMap;
 
   private boolean empty = true;
 
@@ -78,7 +81,10 @@
   }
 
   private void addPartOf(int code) {
-    partOf[code] = partOf[code] + 1;
+    if (partOf == null) {
+      partOf = new Int2IntOpenHashMap();
+    }
+    partOf.addTo(code, 1);
     if (!lowMemoryProfile) {
       int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
       if (parentCode > 0) {
@@ -93,8 +99,8 @@
   }
 
   private void removePartOf(int code) {
-    if (partOf[code] != 0) {
-      partOf[code] = partOf[code] - 1;
+    if (partOf != null && partOf.get(code) != 0) {
+      partOf.addTo(code, -1);
       if (!lowMemoryProfile) {
         int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
         if (parentCode > 0) {
@@ -105,8 +111,11 @@
   }
 
   public boolean isPartOf(Type type) {
+    if (partOf == null) {
+      return false;
+    }
     int code = ((TypeImpl) type).getCode();
-    int count = partOf[code];
+    int count = partOf.get(code);
     if (count > 0) {
       return true;
     }
@@ -114,7 +123,7 @@
       List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
       for (Type each : subsumedTypes) {
         int code2 = ((TypeImpl) each).getCode();
-        int count2 = partOf[code2];
+        int count2 = partOf.get(code2);
         if (count2 > 0) {
           return true;
         }
@@ -125,71 +134,78 @@
 
   }
 
-  public void setPartOf(int[] partOf) {
+  public void setPartOf(Int2IntOpenHashMap partOf) {
     this.partOf = partOf;
   }
-  
-  public int[] getPartOf() {
+
+  public Int2IntOpenHashMap getPartOf() {
     return partOf;
   }
-  
-  @SuppressWarnings("unchecked")
+
   public Collection<AnnotationFS> getBeginAnchors(Type type) {
+    if (beginMap == null) {
+      return Collections.emptyList();
+    }
     int code = ((TypeImpl) type).getCode();
-    Collection<AnnotationFS> set = (Collection<AnnotationFS>) beginMap[code];
+    IntArrayList list = beginMap.get(code);
     if (lowMemoryProfile) {
-      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
-      if (set != null) {
-        result.addAll(set);
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>(list.size());
+      if (list != null) {
+        result.addAll(adressToAnnotationList(list));
       }
       List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
       for (Type each : subsumedTypes) {
         int parentCode = ((TypeImpl) each).getCode();
-        Collection<?> c = beginMap[parentCode];
+        IntArrayList c = beginMap.get(parentCode);
         if (c != null) {
-          result.addAll((Collection<? extends AnnotationFS>) c);
+          result.addAll(adressToAnnotationList(c));
         }
       }
       return result;
     } else {
-      if (set == null) {
+      if (list == null) {
         return Collections.emptySet();
       } else {
-        return set;
+        return adressToAnnotationList(list);
       }
     }
   }
 
-  @SuppressWarnings("unchecked")
   public Collection<AnnotationFS> getEndAnchors(Type type) {
+    if (endMap == null) {
+      return Collections.emptyList();
+    }
     int code = ((TypeImpl) type).getCode();
-    Collection<AnnotationFS> set = (Collection<AnnotationFS>) endMap[code];
+    IntArrayList list = endMap.get(code);
     if (lowMemoryProfile) {
-      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
-      if (set != null) {
-        result.addAll(set);
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>(list.size());
+      if (list != null) {
+        result.addAll(adressToAnnotationList(list));
       }
       List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
       for (Type each : subsumedTypes) {
         int parentCode = ((TypeImpl) each).getCode();
-        Collection<?> c = endMap[parentCode];
+        IntArrayList c = endMap.get(parentCode);
         if (c != null) {
-          result.addAll((Collection<? extends AnnotationFS>) c);
+          result.addAll(adressToAnnotationList(c));
         }
       }
       return result;
     } else {
-      if (set == null) {
+      if (list == null) {
         return Collections.emptySet();
       } else {
-        return set;
+        return adressToAnnotationList(list);
       }
     }
   }
 
   public boolean beginsWith(Type type) {
+    if (beginMap == null) {
+      return false;
+    }
     int code = ((TypeImpl) type).getCode();
-    Collection<?> set = beginMap[code];
+    Collection<?> set = beginMap.get(code);
     boolean beginsWith = set != null && !set.isEmpty();
     if (beginsWith) {
       return true;
@@ -206,8 +222,11 @@
   }
 
   public boolean endsWith(Type type) {
+    if (endMap == null) {
+      return false;
+    }
     int code = ((TypeImpl) type).getCode();
-    Collection<?> set = endMap[code];
+    Collection<?> set = endMap.get(code);
     boolean endswith = set != null && !set.isEmpty();
     if (endswith) {
       return true;
@@ -223,16 +242,18 @@
     return false;
   }
 
-  @SuppressWarnings("unchecked")
   public void addBegin(AnnotationFS annotation, Type type) {
+    if (beginMap == null) {
+      beginMap = new Int2ObjectOpenHashMap<>();
+    }
     empty = false;
     int code = ((TypeImpl) type).getCode();
-    Collection<Object> set = (Collection<Object>) beginMap[code];
-    if (set == null) {
-      set = new ArrayList<Object>(INITIAL_CAPACITY);
-      beginMap[code] = set;
+    IntArrayList list = beginMap.get(code);
+    if (list == null) {
+      list = new IntArrayList(INITIAL_CAPACITY);
+      beginMap.put(code, list);
     }
-    set.add(annotation);
+    list.add(annotationToAddress(annotation));
     if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
             && !type.getName().equals(ROOT_TYPE2)) {
       TypeSystem typeSystem = getCAS().getTypeSystem();
@@ -243,16 +264,18 @@
     }
   }
 
-  @SuppressWarnings("unchecked")
   public void addEnd(AnnotationFS annotation, Type type) {
+    if (endMap == null) {
+      endMap = new Int2ObjectOpenHashMap<>();
+    }
     empty = false;
     int code = ((TypeImpl) type).getCode();
-    Collection<Object> set = (Collection<Object>) endMap[code];
-    if (set == null) {
-      set = new ArrayList<Object>(INITIAL_CAPACITY);
-      endMap[code] = set;
+    IntArrayList list = endMap.get(code);
+    if (list == null) {
+      list = new IntArrayList(INITIAL_CAPACITY);
+      endMap.put(code, list);
     }
-    set.add(annotation);
+    list.add(annotationToAddress(annotation));
     if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
             && !type.getName().equals(ROOT_TYPE2)) {
       TypeSystem typeSystem = getCAS().getTypeSystem();
@@ -263,14 +286,16 @@
     }
   }
 
-  @SuppressWarnings("unchecked")
   public void removeBegin(AnnotationFS annotation, Type type) {
+    if (beginMap == null) {
+      return;
+    }
     int code = ((TypeImpl) type).getCode();
-    Collection<Object> set = (Collection<Object>) beginMap[code];
-    if (set != null) {
-      set.remove(annotation);
-      if (set.isEmpty()) {
-        beginMap[code] = null;
+    IntArrayList list = beginMap.get(code);
+    if (list != null) {
+      list.removeInt(annotationToAddress(annotation));
+      if (list.isEmpty()) {
+        beginMap.remove(code);
       }
     }
     if (!lowMemoryProfile) {
@@ -282,14 +307,16 @@
     }
   }
 
-  @SuppressWarnings("unchecked")
   public void removeEnd(AnnotationFS annotation, Type type) {
+    if (endMap == null) {
+      return;
+    }
     int code = ((TypeImpl) type).getCode();
-    Collection<Object> set = (Collection<Object>) endMap[code];
-    if (set != null) {
-      set.remove(annotation);
-      if (set.isEmpty()) {
-        endMap[code] = null;
+    IntArrayList list = endMap.get(code);
+    if (list != null) {
+      list.removeInt(annotationToAddress(annotation));
+      if (list.isEmpty()) {
+        endMap.remove(code);
       }
     }
     if (!lowMemoryProfile) {
@@ -301,28 +328,30 @@
     }
   }
 
-  public Collection<?>[] getBeginMap() {
+  public Int2ObjectOpenHashMap<IntArrayList> getBeginMap() {
     return beginMap;
   }
 
-  public Collection<?>[] getEndMap() {
+  public Int2ObjectOpenHashMap<IntArrayList> getEndMap() {
     return endMap;
   }
 
-  public void setBeginMap(Collection<?>[] beginMap) {
+  public void setBeginMap(Int2ObjectOpenHashMap<IntArrayList> beginMap) {
     this.beginMap = beginMap;
-    for (Collection<?> each : beginMap) {
-      if (each != null && !each.isEmpty()) {
+    for (Entry<IntArrayList> entry : beginMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
         this.empty = false;
         break;
       }
     }
   }
 
-  public void setEndMap(Collection<?>[] endMap) {
+  public void setEndMap(Int2ObjectOpenHashMap<IntArrayList> endMap) {
     this.endMap = endMap;
-    for (Collection<?> each : endMap) {
-      if (each != null && !each.isEmpty()) {
+    for (Entry<IntArrayList> entry : endMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
         this.empty = false;
         break;
       }
@@ -330,20 +359,40 @@
   }
 
   public void clearBeginMap() {
-    this.beginMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem())
-            .getLargestTypeCode()];
+    this.beginMap.clear();
   }
 
   public void clearEndMap() {
-    this.endMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem()).getLargestTypeCode()];
-    for (Collection<?> each : beginMap) {
-      if (each != null && !each.isEmpty()) {
-        return;
+    this.endMap.clear();
+    if (beginMap != null) {
+      for (Entry<IntArrayList> entry : beginMap.int2ObjectEntrySet()) {
+        Collection<?> value = entry.getValue();
+        if (value != null && !value.isEmpty()) {
+          return;
+        }
       }
     }
     this.empty = true;
   }
 
+  private Collection<AnnotationFS> adressToAnnotationList(IntArrayList addressList) {
+    List<AnnotationFS> result = new ArrayList<>(addressList.size());
+    for (int value : addressList) {
+      result.add(addressToAnnotation(value));
+    }
+    return result;
+  }
+
+  private int annotationToAddress(AnnotationFS annotation) {
+    return ((FeatureStructureImpl) annotation).getAddress();
+  }
+
+  private AnnotationFS addressToAnnotation(int address) {
+    LowLevelCAS lowLevelCAS = getCASImpl().getLowLevelCAS();
+    FeatureStructure fs = lowLevelCAS.ll_getFSForRef(address);
+    return (AnnotationFS) fs;
+  }
+
   /**
    * @generated
    * @ordered
diff --git a/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic1.java b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic1.java
new file mode 100644
index 0000000..6df0050
--- /dev/null
+++ b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic1.java
@@ -0,0 +1,428 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.ruta.type;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+/**
+ * 
+ * @generated
+ */
+public class RutaBasic1 extends Annotation {
+
+  private static final int INITIAL_CAPACITY = 2;
+
+  private static final String ROOT_TYPE1 = "uima.tcas.Annotation";
+
+  private static final String ROOT_TYPE2 = "uima.cas.AnnotationBase";
+
+  private boolean lowMemoryProfile = false;
+
+  private int[] partOf = new int[((TypeSystemImpl) getCAS().getTypeSystem()).getLargestTypeCode()];
+
+  private Collection<?>[] beginMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem())
+          .getLargestTypeCode()];
+
+  private Collection<?>[] endMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem())
+          .getLargestTypeCode()];
+
+  private boolean empty = true;
+
+  public boolean isEmpty() {
+    return empty;
+  }
+
+  public boolean isLowMemoryProfile() {
+    return lowMemoryProfile;
+  }
+
+  public void setLowMemoryProfile(boolean lowMemoryProfile) {
+    this.lowMemoryProfile = lowMemoryProfile;
+  }
+
+  public void addPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    addPartOf(code);
+  }
+
+  private void addPartOf(int code) {
+    partOf[code] = partOf[code] + 1;
+    if (!lowMemoryProfile) {
+      int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+      if (parentCode > 0) {
+        addPartOf(parentCode);
+      }
+    }
+  }
+
+  public void removePartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    removePartOf(code);
+  }
+
+  private void removePartOf(int code) {
+    if (partOf[code] != 0) {
+      partOf[code] = partOf[code] - 1;
+      if (!lowMemoryProfile) {
+        int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+        if (parentCode > 0) {
+          removePartOf(parentCode);
+        }
+      }
+    }
+  }
+
+  public boolean isPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    int count = partOf[code];
+    if (count > 0) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int code2 = ((TypeImpl) each).getCode();
+        int count2 = partOf[code2];
+        if (count2 > 0) {
+          return true;
+        }
+      }
+
+    }
+    return false;
+
+  }
+
+  public void setPartOf(int[] partOf) {
+    this.partOf = partOf;
+  }
+  
+  public int[] getPartOf() {
+    return partOf;
+  }
+  
+  @SuppressWarnings("unchecked")
+  public Collection<AnnotationFS> getBeginAnchors(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<AnnotationFS> set = (Collection<AnnotationFS>) beginMap[code];
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
+      if (set != null) {
+        result.addAll(set);
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        Collection<?> c = beginMap[parentCode];
+        if (c != null) {
+          result.addAll((Collection<? extends AnnotationFS>) c);
+        }
+      }
+      return result;
+    } else {
+      if (set == null) {
+        return Collections.emptySet();
+      } else {
+        return set;
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public Collection<AnnotationFS> getEndAnchors(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<AnnotationFS> set = (Collection<AnnotationFS>) endMap[code];
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
+      if (set != null) {
+        result.addAll(set);
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        Collection<?> c = endMap[parentCode];
+        if (c != null) {
+          result.addAll((Collection<? extends AnnotationFS>) c);
+        }
+      }
+      return result;
+    } else {
+      if (set == null) {
+        return Collections.emptySet();
+      } else {
+        return set;
+      }
+    }
+  }
+
+  public boolean beginsWith(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = beginMap[code];
+    boolean beginsWith = set != null && !set.isEmpty();
+    if (beginsWith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (beginsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public boolean endsWith(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = endMap[code];
+    boolean endswith = set != null && !set.isEmpty();
+    if (endswith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (endsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  @SuppressWarnings("unchecked")
+  public void addBegin(AnnotationFS annotation, Type type) {
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) beginMap[code];
+    if (set == null) {
+      set = new ArrayList<Object>(INITIAL_CAPACITY);
+      beginMap[code] = set;
+    }
+    set.add(annotation);
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addBegin(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void addEnd(AnnotationFS annotation, Type type) {
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) endMap[code];
+    if (set == null) {
+      set = new ArrayList<Object>(INITIAL_CAPACITY);
+      endMap[code] = set;
+    }
+    set.add(annotation);
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addEnd(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void removeBegin(AnnotationFS annotation, Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) beginMap[code];
+    if (set != null) {
+      set.remove(annotation);
+      if (set.isEmpty()) {
+        beginMap[code] = null;
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeBegin(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void removeEnd(AnnotationFS annotation, Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) endMap[code];
+    if (set != null) {
+      set.remove(annotation);
+      if (set.isEmpty()) {
+        endMap[code] = null;
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeEnd(annotation, parent);
+      }
+    }
+  }
+
+  public Collection<?>[] getBeginMap() {
+    return beginMap;
+  }
+
+  public Collection<?>[] getEndMap() {
+    return endMap;
+  }
+
+  public void setBeginMap(Collection<?>[] beginMap) {
+    this.beginMap = beginMap;
+    for (Collection<?> each : beginMap) {
+      if (each != null && !each.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void setEndMap(Collection<?>[] endMap) {
+    this.endMap = endMap;
+    for (Collection<?> each : endMap) {
+      if (each != null && !each.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void clearBeginMap() {
+    this.beginMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem())
+            .getLargestTypeCode()];
+  }
+
+  public void clearEndMap() {
+    this.endMap = new ArrayList<?>[((TypeSystemImpl) getCAS().getTypeSystem()).getLargestTypeCode()];
+    for (Collection<?> each : beginMap) {
+      if (each != null && !each.isEmpty()) {
+        return;
+      }
+    }
+    this.empty = true;
+  }
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(RutaBasic1.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  @Override
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected RutaBasic1() {/* intentionally empty block */
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public RutaBasic1(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic1(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic1(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: Replacement
+
+  /**
+   * getter for Replacement - gets
+   * 
+   * @generated
+   */
+  public String getReplacement() {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((RutaBasic_Type) jcasType).casFeatCode_replacement);
+  }
+
+  /**
+   * setter for Replacement - sets
+   * 
+   * @generated
+   */
+  public void setReplacement(String v) {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    jcasType.ll_cas.ll_setStringValue(addr, ((RutaBasic_Type) jcasType).casFeatCode_replacement, v);
+  }
+
+}
diff --git a/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic2.java b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic2.java
new file mode 100644
index 0000000..5f153db
--- /dev/null
+++ b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic2.java
@@ -0,0 +1,431 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.ruta.type;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.impl.TypeSystemImpl;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+
+/**
+ * 
+ * @generated
+ */
+public class RutaBasic2 extends Annotation {
+
+  private static final int INITIAL_CAPACITY = 2;
+
+  private static final String ROOT_TYPE1 = CAS.TYPE_NAME_ANNOTATION;
+
+  private static final String ROOT_TYPE2 = CAS.TYPE_NAME_ANNOTATION_BASE;
+
+  private boolean lowMemoryProfile = false;
+
+  private int[] partOf = new int[((TypeSystemImpl) getCAS().getTypeSystem()).getLargestTypeCode()];
+
+  private Int2ObjectOpenHashMap<Collection<?>> beginMap = new Int2ObjectOpenHashMap<>();
+  private Int2ObjectOpenHashMap<Collection<?>> endMap = new Int2ObjectOpenHashMap<>();
+  
+  private boolean empty = true;
+
+  public boolean isEmpty() {
+    return empty;
+  }
+
+  public boolean isLowMemoryProfile() {
+    return lowMemoryProfile;
+  }
+
+  public void setLowMemoryProfile(boolean lowMemoryProfile) {
+    this.lowMemoryProfile = lowMemoryProfile;
+  }
+
+  public void addPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    addPartOf(code);
+  }
+
+  private void addPartOf(int code) {
+    partOf[code] = partOf[code] + 1;
+    if (!lowMemoryProfile) {
+      int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+      if (parentCode > 0) {
+        addPartOf(parentCode);
+      }
+    }
+  }
+
+  public void removePartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    removePartOf(code);
+  }
+
+  private void removePartOf(int code) {
+    if (partOf[code] != 0) {
+      partOf[code] = partOf[code] - 1;
+      if (!lowMemoryProfile) {
+        int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+        if (parentCode > 0) {
+          removePartOf(parentCode);
+        }
+      }
+    }
+  }
+
+  public boolean isPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    int count = partOf[code];
+    if (count > 0) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int code2 = ((TypeImpl) each).getCode();
+        int count2 = partOf[code2];
+        if (count2 > 0) {
+          return true;
+        }
+      }
+
+    }
+    return false;
+
+  }
+
+  public void setPartOf(int[] partOf) {
+    this.partOf = partOf;
+  }
+  
+  public int[] getPartOf() {
+    return partOf;
+  }
+  
+  @SuppressWarnings("unchecked")
+  public Collection<AnnotationFS> getBeginAnchors(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<AnnotationFS> set = (Collection<AnnotationFS>) beginMap.get(code);
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
+      if (set != null) {
+        result.addAll(set);
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        Collection<?> c =  beginMap.get(parentCode);
+        if (c != null) {
+          result.addAll((Collection<? extends AnnotationFS>) c);
+        }
+      }
+      return result;
+    } else {
+      if (set == null) {
+        return Collections.emptySet();
+      } else {
+        return set;
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public Collection<AnnotationFS> getEndAnchors(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<AnnotationFS> set = (Collection<AnnotationFS>) endMap.get(code);
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
+      if (set != null) {
+        result.addAll(set);
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        Collection<?> c = endMap.get(parentCode);
+        if (c != null) {
+          result.addAll((Collection<? extends AnnotationFS>) c);
+        }
+      }
+      return result;
+    } else {
+      if (set == null) {
+        return Collections.emptySet();
+      } else {
+        return set;
+      }
+    }
+  }
+
+  public boolean beginsWith(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = beginMap.get(code);
+    boolean beginsWith = set != null && !set.isEmpty();
+    if (beginsWith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (beginsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public boolean endsWith(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = endMap.get(code);
+    boolean endswith = set != null && !set.isEmpty();
+    if (endswith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (endsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  @SuppressWarnings("unchecked")
+  public void addBegin(AnnotationFS annotation, Type type) {
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) beginMap.get(code);
+    if (set == null) {
+      set = new ArrayList<Object>(INITIAL_CAPACITY);
+      beginMap.put(code, set);
+    }
+    set.add(annotation);
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addBegin(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void addEnd(AnnotationFS annotation, Type type) {
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) endMap.get(code);
+    if (set == null) {
+      set = new ArrayList<Object>(INITIAL_CAPACITY);
+      endMap.put(code, set);
+    }
+    set.add(annotation);
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addEnd(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void removeBegin(AnnotationFS annotation, Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) beginMap.get(code);
+    if (set != null) {
+      set.remove(annotation);
+      if (set.isEmpty()) {
+        beginMap.remove(code);
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeBegin(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void removeEnd(AnnotationFS annotation, Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) endMap.get(code);
+    if (set != null) {
+      set.remove(annotation);
+      if (set.isEmpty()) {
+        endMap.remove(code);
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeEnd(annotation, parent);
+      }
+    }
+  }
+
+  public Int2ObjectOpenHashMap<Collection<?>> getBeginMap() {
+    return beginMap;
+  }
+
+  public Int2ObjectOpenHashMap<Collection<?>> getEndMap() {
+    return endMap;
+  }
+
+  public void setBeginMap(Int2ObjectOpenHashMap<Collection<?>> beginMap) {
+    this.beginMap = beginMap;
+    for (Entry<Collection<?>> entry : beginMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void setEndMap(Int2ObjectOpenHashMap<Collection<?>> endMap) {
+    this.endMap = endMap;
+    for (Entry<Collection<?>> entry : endMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void clearBeginMap() {
+    this.beginMap.clear();;
+  }
+
+  public void clearEndMap() {
+    this.endMap.clear();
+    for (Entry<Collection<?>> entry : beginMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        return;
+      }
+    }
+    this.empty = true;
+  }
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(RutaBasic2.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  @Override
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected RutaBasic2() {/* intentionally empty block */
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public RutaBasic2(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic2(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic2(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: Replacement
+
+  /**
+   * getter for Replacement - gets
+   * 
+   * @generated
+   */
+  public String getReplacement() {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((RutaBasic_Type) jcasType).casFeatCode_replacement);
+  }
+
+  /**
+   * setter for Replacement - sets
+   * 
+   * @generated
+   */
+  public void setReplacement(String v) {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    jcasType.ll_cas.ll_setStringValue(addr, ((RutaBasic_Type) jcasType).casFeatCode_replacement, v);
+  }
+
+}
diff --git a/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic3.java b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic3.java
new file mode 100644
index 0000000..d07be47
--- /dev/null
+++ b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic3.java
@@ -0,0 +1,431 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.ruta.type;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+
+/**
+ * 
+ * @generated
+ */
+public class RutaBasic3 extends Annotation {
+
+  private static final int INITIAL_CAPACITY = 2;
+
+  private static final String ROOT_TYPE1 = CAS.TYPE_NAME_ANNOTATION;
+
+  private static final String ROOT_TYPE2 = CAS.TYPE_NAME_ANNOTATION_BASE;
+
+  private boolean lowMemoryProfile = false;
+
+  private Int2IntOpenHashMap partOf = new Int2IntOpenHashMap();
+
+  private Int2ObjectOpenHashMap<Collection<?>> beginMap = new Int2ObjectOpenHashMap<>();
+  private Int2ObjectOpenHashMap<Collection<?>> endMap = new Int2ObjectOpenHashMap<>();
+  
+  private boolean empty = true;
+
+  public boolean isEmpty() {
+    return empty;
+  }
+
+  public boolean isLowMemoryProfile() {
+    return lowMemoryProfile;
+  }
+
+  public void setLowMemoryProfile(boolean lowMemoryProfile) {
+    this.lowMemoryProfile = lowMemoryProfile;
+  }
+
+  public void addPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    addPartOf(code);
+  }
+
+  private void addPartOf(int code) {
+    partOf.addTo(code, 1);
+    if (!lowMemoryProfile) {
+      int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+      if (parentCode > 0) {
+        addPartOf(parentCode);
+      }
+    }
+  }
+
+  public void removePartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    removePartOf(code);
+  }
+
+  private void removePartOf(int code) {
+    if (partOf.get(code) != 0) {
+      partOf.addTo(code, -1);
+      if (!lowMemoryProfile) {
+        int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+        if (parentCode > 0) {
+          removePartOf(parentCode);
+        }
+      }
+    }
+  }
+
+  public boolean isPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    int count = partOf.get(code);
+    if (count > 0) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int code2 = ((TypeImpl) each).getCode();
+        int count2 = partOf.get(code2);
+        if (count2 > 0) {
+          return true;
+        }
+      }
+
+    }
+    return false;
+
+  }
+
+  public void setPartOf(Int2IntOpenHashMap partOf) {
+    this.partOf = partOf;
+  }
+
+  public Int2IntOpenHashMap getPartOf() {
+    return partOf;
+  }
+  
+  @SuppressWarnings("unchecked")
+  public Collection<AnnotationFS> getBeginAnchors(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<AnnotationFS> set = (Collection<AnnotationFS>) beginMap.get(code);
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
+      if (set != null) {
+        result.addAll(set);
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        Collection<?> c =  beginMap.get(parentCode);
+        if (c != null) {
+          result.addAll((Collection<? extends AnnotationFS>) c);
+        }
+      }
+      return result;
+    } else {
+      if (set == null) {
+        return Collections.emptySet();
+      } else {
+        return set;
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public Collection<AnnotationFS> getEndAnchors(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<AnnotationFS> set = (Collection<AnnotationFS>) endMap.get(code);
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>();
+      if (set != null) {
+        result.addAll(set);
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        Collection<?> c = endMap.get(parentCode);
+        if (c != null) {
+          result.addAll((Collection<? extends AnnotationFS>) c);
+        }
+      }
+      return result;
+    } else {
+      if (set == null) {
+        return Collections.emptySet();
+      } else {
+        return set;
+      }
+    }
+  }
+
+  public boolean beginsWith(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = beginMap.get(code);
+    boolean beginsWith = set != null && !set.isEmpty();
+    if (beginsWith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (beginsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public boolean endsWith(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = endMap.get(code);
+    boolean endswith = set != null && !set.isEmpty();
+    if (endswith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (endsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  @SuppressWarnings("unchecked")
+  public void addBegin(AnnotationFS annotation, Type type) {
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) beginMap.get(code);
+    if (set == null) {
+      set = new ArrayList<Object>(INITIAL_CAPACITY);
+      beginMap.put(code, set);
+    }
+    set.add(annotation);
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addBegin(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void addEnd(AnnotationFS annotation, Type type) {
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) endMap.get(code);
+    if (set == null) {
+      set = new ArrayList<Object>(INITIAL_CAPACITY);
+      endMap.put(code, set);
+    }
+    set.add(annotation);
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addEnd(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void removeBegin(AnnotationFS annotation, Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) beginMap.get(code);
+    if (set != null) {
+      set.remove(annotation);
+      if (set.isEmpty()) {
+        beginMap.remove(code);
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeBegin(annotation, parent);
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void removeEnd(AnnotationFS annotation, Type type) {
+    int code = ((TypeImpl) type).getCode();
+    Collection<Object> set = (Collection<Object>) endMap.get(code);
+    if (set != null) {
+      set.remove(annotation);
+      if (set.isEmpty()) {
+        endMap.remove(code);
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeEnd(annotation, parent);
+      }
+    }
+  }
+
+  public Int2ObjectOpenHashMap<Collection<?>> getBeginMap() {
+    return beginMap;
+  }
+
+  public Int2ObjectOpenHashMap<Collection<?>> getEndMap() {
+    return endMap;
+  }
+
+  public void setBeginMap(Int2ObjectOpenHashMap<Collection<?>> beginMap) {
+    this.beginMap = beginMap;
+    for (Entry<Collection<?>> entry : beginMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void setEndMap(Int2ObjectOpenHashMap<Collection<?>> endMap) {
+    this.endMap = endMap;
+    for (Entry<Collection<?>> entry : endMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void clearBeginMap() {
+    this.beginMap.clear();;
+  }
+
+  public void clearEndMap() {
+    this.endMap.clear();
+    for (Entry<Collection<?>> entry : beginMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        return;
+      }
+    }
+    this.empty = true;
+  }
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(RutaBasic3.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  @Override
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected RutaBasic3() {/* intentionally empty block */
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public RutaBasic3(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic3(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic3(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: Replacement
+
+  /**
+   * getter for Replacement - gets
+   * 
+   * @generated
+   */
+  public String getReplacement() {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((RutaBasic_Type) jcasType).casFeatCode_replacement);
+  }
+
+  /**
+   * setter for Replacement - sets
+   * 
+   * @generated
+   */
+  public void setReplacement(String v) {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    jcasType.ll_cas.ll_setStringValue(addr, ((RutaBasic_Type) jcasType).casFeatCode_replacement, v);
+  }
+
+}
diff --git a/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic4.java b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic4.java
new file mode 100644
index 0000000..aefd282
--- /dev/null
+++ b/ruta-typesystem/src/main/java/org/apache/uima/ruta/type/RutaBasic4.java
@@ -0,0 +1,480 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.ruta.type;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
+import org.apache.uima.cas.impl.FeatureStructureImpl;
+import org.apache.uima.cas.impl.LowLevelCAS;
+import org.apache.uima.cas.impl.TypeImpl;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.JCas;
+import org.apache.uima.jcas.JCasRegistry;
+import org.apache.uima.jcas.cas.TOP_Type;
+import org.apache.uima.jcas.tcas.Annotation;
+
+import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+
+/**
+ * 
+ * @generated
+ */
+public class RutaBasic4 extends Annotation {
+
+  private static final int INITIAL_CAPACITY = 2;
+
+  private static final String ROOT_TYPE1 = CAS.TYPE_NAME_ANNOTATION;
+
+  private static final String ROOT_TYPE2 = CAS.TYPE_NAME_ANNOTATION_BASE;
+
+  private boolean lowMemoryProfile = false;
+
+  private Int2IntOpenHashMap partOf;
+
+  private Int2ObjectOpenHashMap<IntArrayList> beginMap;
+
+  private Int2ObjectOpenHashMap<IntArrayList> endMap;
+
+  private boolean empty = true;
+
+  public boolean isEmpty() {
+    return empty;
+  }
+
+  public boolean isLowMemoryProfile() {
+    return lowMemoryProfile;
+  }
+
+  public void setLowMemoryProfile(boolean lowMemoryProfile) {
+    this.lowMemoryProfile = lowMemoryProfile;
+  }
+
+  public void addPartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    addPartOf(code);
+  }
+
+  private void addPartOf(int code) {
+    if (partOf == null) {
+      partOf = new Int2IntOpenHashMap();
+    }
+    partOf.addTo(code, 1);
+    if (!lowMemoryProfile) {
+      int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+      if (parentCode > 0) {
+        addPartOf(parentCode);
+      }
+    }
+  }
+
+  public void removePartOf(Type type) {
+    int code = ((TypeImpl) type).getCode();
+    removePartOf(code);
+  }
+
+  private void removePartOf(int code) {
+    if (partOf != null && partOf.get(code) != 0) {
+      partOf.addTo(code, -1);
+      if (!lowMemoryProfile) {
+        int parentCode = getCAS().getTypeSystem().getLowLevelTypeSystem().ll_getParentType(code);
+        if (parentCode > 0) {
+          removePartOf(parentCode);
+        }
+      }
+    }
+  }
+
+  public boolean isPartOf(Type type) {
+    if (partOf == null) {
+      return false;
+    }
+    int code = ((TypeImpl) type).getCode();
+    int count = partOf.get(code);
+    if (count > 0) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int code2 = ((TypeImpl) each).getCode();
+        int count2 = partOf.get(code2);
+        if (count2 > 0) {
+          return true;
+        }
+      }
+
+    }
+    return false;
+
+  }
+
+  public void setPartOf(Int2IntOpenHashMap partOf) {
+    this.partOf = partOf;
+  }
+
+  public Int2IntOpenHashMap getPartOf() {
+    return partOf;
+  }
+
+  public Collection<AnnotationFS> getBeginAnchors(Type type) {
+    if (beginMap == null) {
+      return Collections.emptyList();
+    }
+    int code = ((TypeImpl) type).getCode();
+    IntArrayList list = beginMap.get(code);
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>(list.size());
+      if (list != null) {
+        result.addAll(adressToAnnotationList(list));
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        IntArrayList c = beginMap.get(parentCode);
+        if (c != null) {
+          result.addAll(adressToAnnotationList(c));
+        }
+      }
+      return result;
+    } else {
+      if (list == null) {
+        return Collections.emptySet();
+      } else {
+        return adressToAnnotationList(list);
+      }
+    }
+  }
+
+  public Collection<AnnotationFS> getEndAnchors(Type type) {
+    if (endMap == null) {
+      return Collections.emptyList();
+    }
+    int code = ((TypeImpl) type).getCode();
+    IntArrayList list = endMap.get(code);
+    if (lowMemoryProfile) {
+      Collection<AnnotationFS> result = new ArrayList<AnnotationFS>(list.size());
+      if (list != null) {
+        result.addAll(adressToAnnotationList(list));
+      }
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        int parentCode = ((TypeImpl) each).getCode();
+        IntArrayList c = endMap.get(parentCode);
+        if (c != null) {
+          result.addAll(adressToAnnotationList(c));
+        }
+      }
+      return result;
+    } else {
+      if (list == null) {
+        return Collections.emptySet();
+      } else {
+        return adressToAnnotationList(list);
+      }
+    }
+  }
+
+  public boolean beginsWith(Type type) {
+    if (beginMap == null) {
+      return false;
+    }
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = beginMap.get(code);
+    boolean beginsWith = set != null && !set.isEmpty();
+    if (beginsWith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (beginsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public boolean endsWith(Type type) {
+    if (endMap == null) {
+      return false;
+    }
+    int code = ((TypeImpl) type).getCode();
+    Collection<?> set = endMap.get(code);
+    boolean endswith = set != null && !set.isEmpty();
+    if (endswith) {
+      return true;
+    }
+    if (lowMemoryProfile) {
+      List<Type> subsumedTypes = getCAS().getTypeSystem().getProperlySubsumedTypes(type);
+      for (Type each : subsumedTypes) {
+        if (endsWith(each)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  public void addBegin(AnnotationFS annotation, Type type) {
+    if (beginMap == null) {
+      beginMap = new Int2ObjectOpenHashMap<>();
+    }
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    IntArrayList list = beginMap.get(code);
+    if (list == null) {
+      list = new IntArrayList(INITIAL_CAPACITY);
+      beginMap.put(code, list);
+    }
+    list.add(annotationToAddress(annotation));
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addBegin(annotation, parent);
+      }
+    }
+  }
+
+  public void addEnd(AnnotationFS annotation, Type type) {
+    if (endMap == null) {
+      endMap = new Int2ObjectOpenHashMap<>();
+    }
+    empty = false;
+    int code = ((TypeImpl) type).getCode();
+    IntArrayList list = endMap.get(code);
+    if (list == null) {
+      list = new IntArrayList(INITIAL_CAPACITY);
+      endMap.put(code, list);
+    }
+    list.add(annotationToAddress(annotation));
+    if (!lowMemoryProfile && !type.getName().equals(ROOT_TYPE1)
+            && !type.getName().equals(ROOT_TYPE2)) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        addEnd(annotation, parent);
+      }
+    }
+  }
+
+  public void removeBegin(AnnotationFS annotation, Type type) {
+    if (beginMap == null) {
+      return;
+    }
+    int code = ((TypeImpl) type).getCode();
+    IntArrayList list = beginMap.get(code);
+    if (list != null) {
+      list.removeInt(annotationToAddress(annotation));
+      if (list.isEmpty()) {
+        beginMap.remove(code);
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeBegin(annotation, parent);
+      }
+    }
+  }
+
+  public void removeEnd(AnnotationFS annotation, Type type) {
+    if (endMap == null) {
+      return;
+    }
+    int code = ((TypeImpl) type).getCode();
+    IntArrayList list = endMap.get(code);
+    if (list != null) {
+      list.removeInt(annotationToAddress(annotation));
+      if (list.isEmpty()) {
+        endMap.remove(code);
+      }
+    }
+    if (!lowMemoryProfile) {
+      TypeSystem typeSystem = getCAS().getTypeSystem();
+      Type parent = typeSystem.getParent(type);
+      if (parent != null) {
+        removeEnd(annotation, parent);
+      }
+    }
+  }
+
+  public Int2ObjectOpenHashMap<IntArrayList> getBeginMap() {
+    return beginMap;
+  }
+
+  public Int2ObjectOpenHashMap<IntArrayList> getEndMap() {
+    return endMap;
+  }
+
+  public void setBeginMap(Int2ObjectOpenHashMap<IntArrayList> beginMap) {
+    this.beginMap = beginMap;
+    for (Entry<IntArrayList> entry : beginMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void setEndMap(Int2ObjectOpenHashMap<IntArrayList> endMap) {
+    this.endMap = endMap;
+    for (Entry<IntArrayList> entry : endMap.int2ObjectEntrySet()) {
+      Collection<?> value = entry.getValue();
+      if (value != null && !value.isEmpty()) {
+        this.empty = false;
+        break;
+      }
+    }
+  }
+
+  public void clearBeginMap() {
+    this.beginMap.clear();
+  }
+
+  public void clearEndMap() {
+    this.endMap.clear();
+    if (beginMap != null) {
+      for (Entry<IntArrayList> entry : beginMap.int2ObjectEntrySet()) {
+        Collection<?> value = entry.getValue();
+        if (value != null && !value.isEmpty()) {
+          return;
+        }
+      }
+    }
+    this.empty = true;
+  }
+
+  private Collection<AnnotationFS> adressToAnnotationList(IntArrayList addressList) {
+    List<AnnotationFS> result = new ArrayList<>(addressList.size());
+    for (int value : addressList) {
+      result.add(addressToAnnotation(value));
+    }
+    return result;
+  }
+
+  private int annotationToAddress(AnnotationFS annotation) {
+    return ((FeatureStructureImpl) annotation).getAddress();
+  }
+
+  private AnnotationFS addressToAnnotation(int address) {
+    LowLevelCAS lowLevelCAS = getCASImpl().getLowLevelCAS();
+    FeatureStructure fs = lowLevelCAS.ll_getFSForRef(address);
+    return (AnnotationFS) fs;
+  }
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int typeIndexID = JCasRegistry.register(RutaBasic4.class);
+
+  /**
+   * @generated
+   * @ordered
+   */
+  public final static int type = typeIndexID;
+
+  /** @generated */
+  @Override
+  public int getTypeIndexID() {
+    return typeIndexID;
+  }
+
+  /**
+   * Never called. Disable default constructor
+   * 
+   * @generated
+   */
+  protected RutaBasic4() {/* intentionally empty block */
+  }
+
+  /**
+   * Internal - constructor used by generator
+   * 
+   * @generated
+   */
+  public RutaBasic4(int addr, TOP_Type type) {
+    super(addr, type);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic4(JCas jcas) {
+    super(jcas);
+    readObject();
+  }
+
+  /** @generated */
+  public RutaBasic4(JCas jcas, int begin, int end) {
+    super(jcas);
+    setBegin(begin);
+    setEnd(end);
+    readObject();
+  }
+
+  /**
+   * <!-- begin-user-doc --> Write your own initialization here <!-- end-user-doc -->
+   * 
+   * @generated modifiable
+   */
+  private void readObject() {
+  }
+
+  // *--------------*
+  // * Feature: Replacement
+
+  /**
+   * getter for Replacement - gets
+   * 
+   * @generated
+   */
+  public String getReplacement() {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    return jcasType.ll_cas.ll_getStringValue(addr,
+            ((RutaBasic_Type) jcasType).casFeatCode_replacement);
+  }
+
+  /**
+   * setter for Replacement - sets
+   * 
+   * @generated
+   */
+  public void setReplacement(String v) {
+    if (RutaBasic_Type.featOkTst && ((RutaBasic_Type) jcasType).casFeat_replacement == null)
+      jcasType.jcas.throwFeatMissing("replacement", "org.apache.uima.ruta.type.RutaBasic");
+    jcasType.ll_cas.ll_setStringValue(addr, ((RutaBasic_Type) jcasType).casFeatCode_replacement, v);
+  }
+
+}