diff --git a/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs b/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs
index aea2a14208699d88dedcd816e2de115039b98e6a..82f5b199b0fb84008330a25b81c7d9a7b696d63f 100644
--- a/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs
+++ b/btypes_primitives/src/main/rust_embedded/btypes/src/brelation.rs
@@ -1,6 +1,7 @@
 #![ allow( non_snake_case) ]
 
 use core::marker::PhantomData;
+use crate::bboolean::BBoolean;
 use crate::binteger::BInteger;
 use crate::bset::{BSet, PowSetItem, Set, SetItem};
 
@@ -24,9 +25,9 @@ pub trait RelLeftItem<const LEFT_SIZE: usize, RightItem: SetItem<RIGHT_SIZE>, co
 
     fn rel_to_idx(rel_arr: [[bool; RIGHT_SIZE]; LEFT_SIZE]) -> usize {
         let mut flat_arr = [false; REL_SIZE];
-        for left_idx in 0..6 {
-            for right_idx in 0..6 {
-                flat_arr[left_idx * 6 + right_idx] = rel_arr[left_idx][right_idx];
+        for left_idx in 0..LEFT_SIZE {
+            for right_idx in 0..RIGHT_SIZE {
+                flat_arr[left_idx * RIGHT_SIZE + right_idx] = rel_arr[left_idx][right_idx];
             }
         }
         return Self::RelEnum::arr_to_idx(flat_arr);
@@ -37,7 +38,7 @@ pub trait RelLeftItem<const LEFT_SIZE: usize, RightItem: SetItem<RIGHT_SIZE>, co
         let mut result = [[false; RIGHT_SIZE]; LEFT_SIZE];
         for left_idx in 0..LEFT_SIZE {
             for right_idx in 0..RIGHT_SIZE {
-                result[left_idx][right_idx] = flat_arr[left_idx * 6 + right_idx];
+                result[left_idx][right_idx] = flat_arr[left_idx * RIGHT_SIZE + right_idx];
             }
         }
         return result;
@@ -56,6 +57,10 @@ where L: SetItem<LS> + RelLeftItem<LS, R, RS, SIZE, REL_SIZE>,
     }
 }
 
+//impl<I> PowAble<> for I
+//where I: SetItem<>
+//TODO: pow/fin/pow1/fin1, maybe
+
 impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L, LS, R, RS, REL_SIZE>
     where L: SetItem<LS>,
           R: SetItem<RS>{
@@ -95,16 +100,6 @@ impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L,
         BSet::const_from_arr(self.rel[key.as_idx()])
     }
 
-    pub fn _union(&self, other: &Self) -> Self {
-        let mut result = self.copy();
-        for left_idx in 0..LS {
-            for right_idx in 0..RS {
-                if other.rel[left_idx][right_idx] { result.rel[left_idx][right_idx] = true; }
-            }
-        }
-        return result;
-    }
-
     pub fn card(&self) -> BInteger {
         let mut result: BInteger = 0;
         for left_idx in 0..LS {
@@ -182,6 +177,17 @@ impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L,
         return BSet::const_from_arr(result);
     }
 
+    pub fn range(&self) -> BSet<R, RS> {
+        let mut result = [false; RS];
+        for left_idx in 0..LS {
+            let current_arr = self.rel[left_idx];
+            for right_idx in 0..RS {
+                result[right_idx] |= current_arr[right_idx];
+            }
+        }
+        return BSet::const_from_arr(result);
+    }
+
     pub fn cartesian_product<TL, TR>(left_set: &TL, right_set: &TR) -> Self
         where TL: Set<LS, ItemType = L>,
               TR: Set<RS, ItemType = R> {
@@ -193,6 +199,153 @@ impl<L, const LS: usize, R, const RS: usize, const REL_SIZE: usize> BRelation<L,
         }
         return result;
     }
+
+    pub fn inverse(&self) -> BRelation<R, RS, L, LS, REL_SIZE> {
+        let mut result = BRelation::<R, RS, L, LS, REL_SIZE>::empty();
+        for left_idx in 0..LS {
+            for right_idx in 0..RS {
+                result.rel[right_idx][left_idx] = self.rel[left_idx][right_idx];
+            }
+        }
+        return result;
+    }
+
+    pub fn domainRestriction(&self, domain_set: &BSet<L, LS>) -> Self {
+        let mut result = self.copy();
+        for left_idx in 0..LS {
+            if !domain_set.contains_idx(left_idx) { result.rel[left_idx] = [false; RS]; }
+        }
+        return result;
+    }
+
+    pub fn domainSubstraction(&self, domain_set: &BSet<L, LS>) -> Self {
+        let mut result = self.copy();
+        for left_idx in 0..LS {
+            if domain_set.contains_idx(left_idx) { result.rel[left_idx] = [false; RS]; }
+        }
+        return result;
+    }
+
+    pub fn rangeRestriction(&self, range_set: &BSet<R, RS>) -> Self {
+        let mut result = self.copy();
+        let range_arr = range_set.as_arr();
+        for left_idx in 0..LS {
+            for right_idx in 0..RS {
+                //retain only elements that are in self *and* in range_set
+                result.rel[left_idx][right_idx] &= range_arr[right_idx];
+            }
+        }
+        return result;
+    }
+
+    pub fn rangeSubstraction(&self, range_set: &BSet<R, RS>) -> Self {
+        let mut result = self.copy();
+        let range_arr = range_set.as_arr();
+        for left_idx in 0..LS {
+            for right_idx in 0..RS {
+                //retain only elements that are in self *but not* in range_set
+                result.rel[left_idx][right_idx] &= !range_arr[right_idx];
+            }
+        }
+        return result;
+    }
+
+    pub fn relationImage(&self, result_domain: &BSet<L, LS>) -> BSet<R, RS> {
+        let mut result_arr = [false; RS];
+        for left_idx in 0..LS {
+            if result_domain.contains_idx(left_idx) {
+                for right_idx in 0..RS {
+                    result_arr[right_idx] |= self.rel[left_idx][right_idx];
+                }
+            }
+        }
+        return BSet::<R, RS>::const_from_arr(result_arr);
+    }
+
+    pub fn intersect(&self, other: &Self) -> Self {
+        return self.relation_combine(other, |s, o| s && o);
+    }
+
+    pub fn difference(&self, other: &Self) -> Self {
+        return self.relation_combine(other, |s, o| s && !o);
+    }
+
+    pub fn _union(&self, other: &Self) -> Self {
+        return self.relation_combine(other, |s, o| s | o);
+    }
+
+    fn relation_combine(&self, other: &Self, combine_fn: fn(bool, bool) -> bool) -> Self {
+        let mut result = self.copy();
+        for left_idx in 0..LS {
+            for right_idx in 0..RS {
+                result.rel[left_idx][right_idx] = combine_fn(result.rel[left_idx][right_idx], other.rel[left_idx][right_idx]);
+            }
+        }
+        return result;
+    }
+
+    pub fn equal(&self, other: &Self) -> BBoolean {
+        return self.rel.eq(&other.rel);
+    }
+
+    pub fn unequal(&self, other: &Self) -> BBoolean {
+        return !self.rel.eq(&other.rel);
+    }
+
+    pub fn elementOf(&self, (k, v): (L, R)) -> BBoolean {
+        return self.rel[k.as_idx()][v.as_idx()];
+    }
+
+    pub fn noElementOf(&self, (k, v): (L, R)) -> BBoolean {
+        return !self.rel[k.as_idx()][v.as_idx()];
+    }
+
+    pub fn subset(&self, other: &Self) -> BBoolean {
+        for left_idx in 0..LS {
+            for right_idx in 0..RS {
+                if other.rel[left_idx][right_idx] && !self.rel[left_idx][right_idx] { return false; }
+            }
+        }
+        return true;
+    }
+
+    pub fn notSubset(&self, other: &Self) -> BBoolean {
+        return !self.subset(other);
+    }
+
+    pub fn _override(&self, other: &Self) -> Self {
+        let mut result = self.copy();
+        for left_idx in 0..LS {
+            if other.rel[left_idx].contains(&true) { result.rel[left_idx] = other.rel[left_idx]; }
+        }
+        return result;
+    }
+
+    //TODO: directProduct/ParallelProduct maybe?
+
+    //TODO: support const-params in template? maybe compiler can figure them out itself?
+    pub fn composition<NewR, const NewRS: usize, const ParamTotal: usize, const NewTotal: usize>(&self, arg: &BRelation<R, RS, NewR, NewRS, ParamTotal>) -> BRelation<L, LS, NewR, NewRS, NewTotal>
+    where NewR: SetItem<NewRS>{
+        let mut result = BRelation::<L, LS, NewR, NewRS, NewTotal>::empty();
+        for left_idx in 0..LS {
+            result.rel[left_idx] = arg.relationImage(&BSet::const_from_arr(self.rel[left_idx])).as_arr()
+        }
+        return result;
+    }
+
+    //TODO: projection1/2 maybe? would need to impl SetItem for (L,R) and (R,L), might need adjustment in codegenerator?
+    //      or we use the relation-item enums for the tuples as well...
+
+    //TODO: support const-params in template? maybe compiler can figure them out itself?
+    pub fn fnc<NewR, const NewRS: usize, const newRelTotal: usize>(&self) -> BRelation<L, LS, NewR, NewRS, newRelTotal>
+    where NewR: Set<RS> + SetItem<NewRS>{                                  //BRelation<L, LS, BSet<R, RS>, NewRS, newRelTotal
+        //NewR::ItemType = R; not yet supported in rust, NewR: Set<RS, I = R> might be, but I'd need to rewrite the trait for that and the related code. For now, we assume the code-generator creates correct code (if it wouldn't the code probably wouldn't run anyway...)
+        let mut result = BRelation::<L, LS, NewR, NewRS, newRelTotal>::empty();
+        for left_idx in 0..LS {
+            result.rel[left_idx][NewR::from_arr(self.rel[left_idx]).as_idx()] = true;
+        }
+        return result;
+    }
 }
 
 #[macro_export]