diff --git a/.gitignore b/.gitignore
index 6b1d5a0..13c6fe9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 /.vscode/
 /Manifest.toml
+.DS_Store
diff --git a/project/createmap.jl b/project/createmap.jl
index 27fbc86..8f76727 100644
--- a/project/createmap.jl
+++ b/project/createmap.jl
@@ -1,4 +1,4 @@
-using UnitDiskMapping, GraphTensorNetworks
+using UnitDiskMapping, GraphTensorNetworks, Graphs
 
 function mapped_entry_to_compact(s::Pattern)
     locs, g, pins = mapped_graph(s)
@@ -40,8 +40,8 @@ function compute_mis_overhead(s)
     locs2, g2, pins2 = mapped_graph(s)
     m1 = mis_compactify!(solve(Independence(g1, openvertices=pins1), "size max"))
     m2 = mis_compactify!(solve(Independence(g2, openvertices=pins2), "size max"))
-    @test nv(g1) == length(locs1) && nv(g2) == length(locs2)
-    sig, diff = UnitDiskMapping.is_diff_by_const(content.(m1), content.(m2))
+    @assert nv(g1) == length(locs1) && nv(g2) == length(locs2)
+    sig, diff = UnitDiskMapping.is_diff_by_const(GraphTensorNetworks.content.(m1), GraphTensorNetworks.content.(m2))
     @assert sig
     return diff
 end
@@ -71,7 +71,9 @@ function dump_mapping_to_julia(filename, patterns)
     end
 end
 
+
 dump_mapping_to_julia(joinpath(@__DIR__, "..", "src", "extracting_results.jl"),
     (Cross{false}(), Cross{true}(),
     Turn(), WTurn(), Branch(), BranchFix(), TrivialTurn(), TCon(), BranchFixB(),
-    UnitDiskMapping.simplifier_ruleset...))
\ No newline at end of file
+    EndTurn(),
+    UnitDiskMapping.simplifier_ruleset...))
diff --git a/src/UnitDiskMapping.jl b/src/UnitDiskMapping.jl
index d3efda6..95a6b35 100644
--- a/src/UnitDiskMapping.jl
+++ b/src/UnitDiskMapping.jl
@@ -6,8 +6,10 @@ using Graphs
 
 export UGrid, apply_crossing_gadgets!, apply_simplifier_gadgets!, apply_gadget!, embed_graph
 export unapply_gadgets!, unmatch
-export Pattern, Corner, Turn, Cross, source_graph, mapped_graph, TruncatedTurn
+export Pattern, Corner, Turn, Cross, source_graph, mapped_graph, TruncatedTurn, EndTurn
 export mapped_entry_to_compact, source_entry_to_configs, map_config_back, mis_overhead
+export UNode, contract_graph, compress_graph_ug, compress_graph_loc
+export unitdisk_graph
 
 include("utils.jl")
 include("gadgets.jl")
@@ -15,5 +17,6 @@ include("simplifiers.jl")
 include("mapping.jl")
 include("extracting_results.jl")
 include("pathdecomposition/pathdecomposition.jl")
+include("shrinking/compressUDG.jl")
 
 end
diff --git a/src/extracting_results.jl b/src/extracting_results.jl
index 0ce8d8b..19bad27 100644
--- a/src/extracting_results.jl
+++ b/src/extracting_results.jl
@@ -5,7 +5,7 @@ function mapped_entry_to_compact(::Cross{false})
 end
 
 function source_entry_to_configs(::Cross{false})
-    return Dict(Pair{Int64, Vector{BitVector}}[5 => [[1, 0, 0, 1, 0, 0, 1, 0, 1], [1, 0, 1, 0, 0, 0, 1, 0, 1]], 12 => [[0, 1, 0, 0, 1, 0, 1, 0, 1], [0, 0, 1, 0, 1, 0, 1, 0, 1]], 8 => [[0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 1, 0, 1, 0, 0]], 1 => [[1, 0, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 1, 0, 0]], 0 => [[0, 1, 0, 1, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 1, 0, 0]], 6 => [[0, 1, 0, 1, 0, 1, 0, 0, 1]], 11 => [[1, 0, 1, 0, 1, 1, 0, 1, 0]], 9 => [[1, 0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0]], 14 => [[0, 1, 0, 0, 1, 1, 0, 0, 1], [0, 0, 1, 0, 1, 1, 0, 0, 1]], 3 => [[1, 0, 0, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 0, 1, 0, 1, 0]], 7 => [[1, 0, 0, 1, 0, 1, 0, 0, 1], [1, 0, 1, 0, 0, 1, 0, 0, 1]], 4 => [[0, 1, 0, 1, 0, 0, 1, 0, 1]], 13 => [[1, 0, 1, 0, 1, 0, 1, 0, 1]], 15 => [[1, 0, 1, 0, 1, 1, 0, 0, 1]], 2 => [[0, 1, 0, 1, 0, 1, 0, 1, 0]], 10 => [[0, 1, 0, 0, 1, 1, 0, 1, 0], [0, 0, 1, 0, 1, 1, 0, 1, 0]]])
+    return Dict(Pair{Int64, Vector{BitVector}}[5 => [[1, 0, 1, 0, 0, 0, 1, 0, 1], [1, 0, 0, 1, 0, 0, 1, 0, 1]], 12 => [[0, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 0, 1, 0, 1, 0, 1]], 8 => [[0, 0, 1, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0]], 1 => [[1, 0, 1, 0, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0, 0]], 0 => [[0, 1, 0, 1, 0, 0, 0, 1, 0], [0, 1, 0, 1, 0, 0, 1, 0, 0]], 6 => [[0, 1, 0, 1, 0, 1, 0, 0, 1]], 11 => [[1, 0, 1, 0, 1, 1, 0, 1, 0]], 9 => [[1, 0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0]], 14 => [[0, 0, 1, 0, 1, 1, 0, 0, 1], [0, 1, 0, 0, 1, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1, 0, 1, 0], [1, 0, 0, 1, 0, 1, 0, 1, 0]], 7 => [[1, 0, 1, 0, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1, 0, 0, 1]], 4 => [[0, 1, 0, 1, 0, 0, 1, 0, 1]], 13 => [[1, 0, 1, 0, 1, 0, 1, 0, 1]], 15 => [[1, 0, 1, 0, 1, 1, 0, 0, 1]], 2 => [[0, 1, 0, 1, 0, 1, 0, 1, 0]], 10 => [[0, 0, 1, 0, 1, 1, 0, 1, 0], [0, 1, 0, 0, 1, 1, 0, 1, 0]]])
 end
 
 mis_overhead(::Cross{false}) = -1.0
@@ -27,7 +27,7 @@ function mapped_entry_to_compact(::Turn)
 end
 
 function source_entry_to_configs(::Turn)
-    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 0, 1, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]])
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 0, 1, 0, 1], [0, 1, 0, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 0], [1, 0, 0, 1, 0]]])
 end
 
 mis_overhead(::Turn) = -1.0
@@ -49,7 +49,7 @@ function mapped_entry_to_compact(::Branch)
 end
 
 function source_entry_to_configs(::Branch)
-    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0, 1, 0]], 4 => [[0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 1, 0, 0, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 1]], 5 => [[1, 0, 1, 0, 0, 1, 0, 1]], 6 => [[0, 1, 0, 0, 1, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0, 1]], 2 => [[0, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0], [0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0]], 7 => [[1, 0, 1, 0, 1, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1, 0, 1, 0], [1, 0, 1, 0, 1, 1, 0, 0]], 1 => [[1, 0, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0]]])
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0, 1, 0]], 4 => [[0, 1, 0, 0, 0, 1, 0, 1], [0, 0, 1, 0, 0, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 1]], 5 => [[1, 0, 1, 0, 0, 1, 0, 1]], 6 => [[0, 1, 0, 0, 1, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0, 1]], 2 => [[0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0], [0, 1, 0, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 0, 1, 0]], 7 => [[1, 0, 1, 0, 1, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1, 1, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0]], 1 => [[1, 0, 1, 0, 0, 1, 0, 0], [1, 0, 1, 0, 0, 0, 1, 0], [1, 0, 0, 1, 0, 0, 1, 0]]])
 end
 
 mis_overhead(::Branch) = -1.0
@@ -60,7 +60,7 @@ function mapped_entry_to_compact(::BranchFix)
 end
 
 function source_entry_to_configs(::BranchFix)
-    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0], [0, 1, 0, 1, 0, 0]], 2 => [[0, 1, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 1, 0]]])
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0, 0], [0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 0, 1], [1, 0, 0, 1, 0, 1]], 1 => [[1, 0, 1, 0, 1, 0]]])
 end
 
 mis_overhead(::BranchFix) = -1.0
@@ -99,6 +99,17 @@ end
 mis_overhead(::BranchFixB) = -1.0
 
 
+function mapped_entry_to_compact(::EndTurn)
+    return Dict([0 => 0, 1 => 1])
+end
+
+function source_entry_to_configs(::EndTurn)
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1], [0, 1, 0]], 1 => [[1, 0, 1]]])
+end
+
+mis_overhead(::EndTurn) = -1.0
+
+
 function mapped_entry_to_compact(::UnitDiskMapping.DanglingLeg)
     return Dict([0 => 0, 1 => 1])
 end
@@ -108,3 +119,36 @@ function source_entry_to_configs(::UnitDiskMapping.DanglingLeg)
 end
 
 mis_overhead(::UnitDiskMapping.DanglingLeg) = -1.0
+
+
+function mapped_entry_to_compact(::UnitDiskMapping.Square)
+    return Dict([0 => 0, 2 => 2, 3 => 3, 1 => 1])
+end
+
+function source_entry_to_configs(::UnitDiskMapping.Square)
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 0, 1, 0], [0, 0, 0, 1]], 2 => [[0, 1, 1, 0]], 3 => [], 1 => [[1, 0, 0, 1]]])
+end
+
+mis_overhead(::UnitDiskMapping.Square) = -1.0
+
+
+function mapped_entry_to_compact(::UnitDiskMapping.Cane)
+    return Dict([0 => 0, 2 => 0, 3 => 3, 1 => 0])
+end
+
+function source_entry_to_configs(::UnitDiskMapping.Cane)
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 0, 1, 0]], 2 => [[0, 1, 0, 0, 1], [0, 0, 1, 0, 1]], 3 => [[1, 0, 1, 0, 1]], 1 => [[1, 0, 0, 1, 0], [1, 0, 1, 0, 0]]])
+end
+
+mis_overhead(::UnitDiskMapping.Cane) = -1.0
+
+
+function mapped_entry_to_compact(::UnitDiskMapping.CLoop)
+    return Dict([0 => 0, 2 => 0, 3 => 3, 1 => 0])
+end
+
+function source_entry_to_configs(::UnitDiskMapping.CLoop)
+    return Dict(Pair{Int64, Vector{BitVector}}[0 => [[0, 1, 1, 0, 0]], 2 => [[0, 1, 0, 0, 1], [1, 0, 0, 0, 1]], 3 => [[1, 0, 0, 1, 1]], 1 => [[0, 0, 1, 1, 0], [1, 0, 0, 1, 0]]])
+end
+
+mis_overhead(::UnitDiskMapping.CLoop) = -1.0
diff --git a/src/gadgets.jl b/src/gadgets.jl
index 5d9a480..d246f08 100644
--- a/src/gadgets.jl
+++ b/src/gadgets.jl
@@ -108,18 +108,18 @@ end
 
 struct Cross{CON} <: CrossPattern end
 iscon(::Cross{CON}) where {CON} = CON
-# ⋅ ● ⋅ 
-# ◆ ◉ ● 
-# ⋅ ◆ ⋅ 
+# ⋅ ● ⋅
+# ◆ ◉ ●
+# ⋅ ◆ ⋅
 function source_graph(::Cross{true})
     locs = [(2,1), (2,2), (2,3), (1,2), (2,2), (3,2)]
     g = simplegraph([(1,2), (2,3), (4,5), (5,6), (1,6)])
     return locs, g, [1,4,6,3]
 end
 
-# ⋅ ● ⋅ 
-# ● ● ● 
-# ⋅ ● ⋅ 
+# ⋅ ● ⋅
+# ● ● ●
+# ⋅ ● ⋅
 function mapped_graph(::Cross{true})
     locs = [(2,1), (2,2), (2,3), (1,2), (3,2)]
     locs, unitdisk_graph(locs, 1.5), [1,4,5,3]
@@ -128,20 +128,20 @@ Base.size(::Cross{true}) = (3, 3)
 cross_location(::Cross{true}) = (2,2)
 connect_locations(::Cross{true}) = [(2, 1), (3,2)]
 
-# ⋅ ⋅ ● ⋅ ⋅ 
-# ● ● ◉ ● ● 
-# ⋅ ⋅ ● ⋅ ⋅ 
-# ⋅ ⋅ ● ⋅ ⋅ 
+# ⋅ ⋅ ● ⋅ ⋅
+# ● ● ◉ ● ●
+# ⋅ ⋅ ● ⋅ ⋅
+# ⋅ ⋅ ● ⋅ ⋅
 function source_graph(::Cross{false})
     locs = [(2,1), (2,2), (2,3), (2,4), (2,5), (1,3), (2,3), (3,3), (4,3)]
     g = simplegraph([(1,2), (2,3), (3,4), (4,5), (6,7), (7,8), (8,9)])
     return locs, g, [1,6,9,5]
 end
 
-# ⋅ ⋅ ● ⋅ ⋅ 
-# ● ● ● ● ● 
-# ⋅ ● ● ● ⋅ 
-# ⋅ ⋅ ● ⋅ ⋅ 
+# ⋅ ⋅ ● ⋅ ⋅
+# ● ● ● ● ●
+# ⋅ ● ● ● ⋅
+# ⋅ ⋅ ● ⋅ ⋅
 function mapped_graph(::Cross{false})
     locs = [(2,1), (2,2), (2,3), (2,4), (2,5), (1,3), (3,3), (4,3), (3, 2), (3,4)]
     locs, unitdisk_graph(locs, 1.5), [1,6,8,5]
@@ -151,9 +151,9 @@ cross_location(::Cross{false}) = (2,3)
 
 struct Turn <: CrossPattern end
 iscon(::Turn) = false
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ● ● ● 
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ● ●
 # ⋅ ⋅ ⋅ ⋅
 function source_graph(::Turn)
     locs = [(1,2), (2,2), (3,2), (3,3), (3,4)]
@@ -161,9 +161,9 @@ function source_graph(::Turn)
     return locs, g, [1,5]
 end
 
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ⋅ ● ⋅ 
-# ⋅ ⋅ ⋅ ● 
+# ⋅ ● ⋅ ⋅
+# ⋅ ⋅ ● ⋅
+# ⋅ ⋅ ⋅ ●
 # ⋅ ⋅ ⋅ ⋅
 function mapped_graph(::Turn)
     locs = [(1,2), (2,3), (3,4)]
@@ -175,20 +175,20 @@ cross_location(::Turn) = (3,2)
 
 export Branch, TrivialTurn, BranchFix, WTurn, TCon, BranchFixB
 struct Branch <: CrossPattern end
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ● ● ● 
-# ⋅ ● ● ⋅ 
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ● ●
+# ⋅ ● ● ⋅
 # ⋅ ● ⋅ ⋅
 function source_graph(::Branch)
     locs = [(1,2), (2,2), (3,2),(3,3),(3,4),(4,3),(4,2),(5,2)]
     g = simplegraph([(1,2), (2,3), (3, 4), (4,5), (4,6), (6,7), (7,8)])
     return locs, g, [1, 5, 8]
 end
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ⋅ ● ⋅ 
-# ⋅ ● ⋅ ● 
-# ⋅ ⋅ ● ⋅ 
+# ⋅ ● ⋅ ⋅
+# ⋅ ⋅ ● ⋅
+# ⋅ ● ⋅ ●
+# ⋅ ⋅ ● ⋅
 # ⋅ ● ⋅ ⋅
 function mapped_graph(::Branch)
     locs = [(1,2), (2,3), (3,2),(3,4),(4,3),(5,2)]
@@ -199,19 +199,19 @@ cross_location(::Branch) = (3,2)
 iscon(::Branch) = false
 
 struct BranchFix <: CrossPattern end
-# ⋅ ● ⋅ ⋅ 
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ● ⋅
 # ⋅ ● ● ⋅
-# ⋅ ● ● ⋅ 
 # ⋅ ● ⋅ ⋅
 function source_graph(::BranchFix)
     locs = [(1,2), (2,2), (2,3),(3,3),(3,2),(4,2)]
     g = simplegraph([(1,2), (2,3), (3,4),(4,5), (5,6)])
     return locs, g, [1, 6]
 end
-# ⋅ ● ⋅ ⋅ 
-# ⋅ ● ⋅ ⋅ 
 # ⋅ ● ⋅ ⋅
-# ⋅ ● ⋅ ⋅ 
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ⋅ ⋅
 function mapped_graph(::BranchFix)
     locs = [(1,2),(2,2),(3,2),(4,2)]
     return locs, unitdisk_graph(locs, 1.5), [1, 4]
@@ -221,18 +221,18 @@ cross_location(::BranchFix) = (2,2)
 iscon(::BranchFix) = false
 
 struct WTurn <: CrossPattern end
-# ⋅ ⋅ ⋅ ⋅ 
-# ⋅ ⋅ ● ● 
-# ⋅ ● ● ⋅ 
+# ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ● ●
+# ⋅ ● ● ⋅
 # ⋅ ● ⋅ ⋅
 function source_graph(::WTurn)
     locs = [(2,3), (2,4), (3,2),(3,3),(4,2)]
     g = simplegraph([(1,2), (1,4), (3,4),(3,5)])
     return locs, g, [2, 5]
 end
-# ⋅ ⋅ ⋅ ⋅ 
-# ⋅ ⋅ ⋅ ● 
-# ⋅ ⋅ ● ⋅ 
+# ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ●
+# ⋅ ⋅ ● ⋅
 # ⋅ ● ⋅ ⋅
 function mapped_graph(::WTurn)
     locs = [(2,4),(3,3),(4,2)]
@@ -243,19 +243,19 @@ cross_location(::WTurn) = (2,2)
 iscon(::WTurn) = false
 
 struct BranchFixB <: CrossPattern end
-# ⋅ ⋅ ⋅ ⋅ 
+# ⋅ ⋅ ⋅ ⋅
 # ⋅ ⋅ ● ⋅
-# ⋅ ● ● ⋅ 
+# ⋅ ● ● ⋅
 # ⋅ ● ⋅ ⋅
 function source_graph(::BranchFixB)
     locs = [(2,3),(3,3),(3,2),(4,2)]
     g = simplegraph([(1,3), (2,3), (2,4)])
     return locs, g, [1, 4]
 end
-# ⋅ ⋅ ⋅ ⋅ 
-# ⋅ ⋅ ⋅ ⋅ 
+# ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅
+# ⋅ ● ⋅ ⋅
 # ⋅ ● ⋅ ⋅
-# ⋅ ● ⋅ ⋅ 
 function mapped_graph(::BranchFixB)
     locs = [(3,2),(4,2)]
     return locs, unitdisk_graph(locs, 1.5), [1, 2]
@@ -267,7 +267,7 @@ iscon(::BranchFixB) = false
 
 struct TCon <: CrossPattern end
 # ⋅ ◆ ⋅ ⋅
-# ◆ ● ⋅ ⋅ 
+# ◆ ● ⋅ ⋅
 # ⋅ ● ⋅ ⋅
 function source_graph(::TCon)
     locs = [(1,2), (2,1), (2,2),(3,2)]
@@ -306,6 +306,26 @@ cross_location(::TrivialTurn) = (2,2)
 iscon(::TrivialTurn) = true
 connect_locations(::TrivialTurn) = [(1,2), (2,1)]
 
+struct EndTurn <: CrossPattern end
+# ⋅ ● ⋅ ⋅
+# ⋅ ● ● ⋅
+# ⋅ ⋅ ⋅ ⋅
+function source_graph(::EndTurn)
+    locs = [(1,2), (2,2), (2,3)]
+    g = simplegraph([(1,2), (2,3)])
+    return locs, g, [1]
+end
+# ⋅ ● ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅
+function mapped_graph(::EndTurn)
+    locs = [(1,2)]
+    return locs, unitdisk_graph(locs, 1.5), [1]
+end
+Base.size(::EndTurn) = (3,4)
+cross_location(::EndTurn) = (2,2)
+iscon(::EndTurn) = false
+
 ############## Rotation and Flip ###############
 export RotatedGadget, ReflectedGadget
 struct RotatedGadget{GT} <: Pattern
@@ -402,4 +422,4 @@ function _boundary_config(pins, config)
         res += Int(config[p]) << (i-1)
     end
     return res
-end
\ No newline at end of file
+end
diff --git a/src/mapping.jl b/src/mapping.jl
index 13b3543..d70a2d7 100644
--- a/src/mapping.jl
+++ b/src/mapping.jl
@@ -72,7 +72,7 @@ end
 const crossing_ruleset = (Cross{false}(),
                     Turn(), WTurn(), Branch(), BranchFix(), TCon(), TrivialTurn(),
                     RotatedGadget(TCon(), 1), ReflectedGadget(Cross{true}(), "y"),
-                    ReflectedGadget(TrivialTurn(), "y"), BranchFixB(),
+                    ReflectedGadget(TrivialTurn(), "y"), BranchFixB(), EndTurn(),
                     ReflectedGadget(RotatedGadget(TCon(), 1), "y"))
 function apply_crossing_gadgets!(ug::UGrid, ruleset=crossing_ruleset)
     tape = Tuple{Pattern,Int,Int}[]
@@ -92,7 +92,29 @@ function apply_crossing_gadgets!(ug::UGrid, ruleset=crossing_ruleset)
     return ug, tape
 end
 
-function apply_simplifier_gadgets!(ug::UGrid; ruleset, nrepeat::Int=10)
+function apply_simplifier_gadgets!(ug::UGrid; ruleset=[RotatedGadget(DanglingLeg(), 0),
+    RotatedGadget(DanglingLeg(), 1), RotatedGadget(DanglingLeg(), 2),
+    RotatedGadget(DanglingLeg(), 3), RotatedGadget(Square(), 0),
+    RotatedGadget(Square(), 1), RotatedGadget(Square(), 2),
+    RotatedGadget(Square(), 3), RotatedGadget(Cane(), 0),
+    RotatedGadget(Cane(), 1), RotatedGadget(Cane(), 2),
+    RotatedGadget(Cane(), 3), RotatedGadget(ReflectedGadget(Cane(), "y"),0),
+    RotatedGadget(ReflectedGadget(Cane(), "y"),1),
+    RotatedGadget(ReflectedGadget(Cane(), "y"),2),
+    RotatedGadget(ReflectedGadget(Cane(), "y"),3),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),0),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),1),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),2),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),3), RotatedGadget(CLoop(), 0),
+    RotatedGadget(CLoop(), 1), RotatedGadget(CLoop(), 2),
+    RotatedGadget(CLoop(), 3), RotatedGadget(ReflectedGadget(CLoop(), "y"),0),
+    RotatedGadget(ReflectedGadget(CLoop(), "y"),1),
+    RotatedGadget(ReflectedGadget(CLoop(), "y"),2),
+    RotatedGadget(ReflectedGadget(CLoop(), "y"),3),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),0),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),1),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),2),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),3)], nrepeat::Int=10)
     tape = Tuple{Pattern,Int,Int}[]
     for _ in 1:nrepeat, pattern in ruleset
         for j=0:size(ug.content, 2)  # start from 0 because there can be one empty padding column/row.
@@ -327,7 +349,29 @@ a maximum independent set of the original graph in polynomial time.
 
 Returns a `MappingResult` instance.
 """
-function map_graph(g::SimpleGraph; ruleset=[RotatedGadget(DanglingLeg(), n) for n=0:3])
+function map_graph(g::SimpleGraph; ruleset=[RotatedGadget(DanglingLeg(), 0),
+    RotatedGadget(DanglingLeg(), 1), RotatedGadget(DanglingLeg(), 2),
+    RotatedGadget(DanglingLeg(), 3), RotatedGadget(Square(), 0),
+    RotatedGadget(Square(), 1), RotatedGadget(Square(), 2),
+    RotatedGadget(Square(), 3), RotatedGadget(Cane(), 0),
+    RotatedGadget(Cane(), 1), RotatedGadget(Cane(), 2),
+    RotatedGadget(Cane(), 3), RotatedGadget(ReflectedGadget(Cane(), "y"),0),
+    RotatedGadget(ReflectedGadget(Cane(), "y"),1),
+    RotatedGadget(ReflectedGadget(Cane(), "y"),2),
+    RotatedGadget(ReflectedGadget(Cane(), "y"),3),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),0),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),1),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),2),
+    RotatedGadget(ReflectedGadget(Cane(), "x"),3), RotatedGadget(CLoop(), 0),
+    RotatedGadget(CLoop(), 1), RotatedGadget(CLoop(), 2),
+    RotatedGadget(CLoop(), 3), RotatedGadget(ReflectedGadget(CLoop(), "y"),0),
+    RotatedGadget(ReflectedGadget(CLoop(), "y"),1),
+    RotatedGadget(ReflectedGadget(CLoop(), "y"),2),
+    RotatedGadget(ReflectedGadget(CLoop(), "y"),3),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),0),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),1),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),2),
+    RotatedGadget(ReflectedGadget(CLoop(), "x"),3)])
     ug = embed_graph(g)
     mis_overhead0 = mis_overhead_copylines(ug)
     ug, tape = apply_crossing_gadgets!(ug)
@@ -337,4 +381,49 @@ function map_graph(g::SimpleGraph; ruleset=[RotatedGadget(DanglingLeg(), n) for
     return MappingResult(ug, vcat(tape, tape2) , mis_overhead0 + mis_overhead1 + mis_overhead2)
 end
 
+
 map_configs_back(r::MappingResult, configs::AbstractVector) = unapply_gadgets!(copy(r.grid_graph), r.mapping_history, copy.(configs))[2]
+
+function compress_graph_ug(ug::UGrid)
+    # get locations
+    M = ug.content
+
+    locs = Vector{Tuple{Int, Int}}()
+
+    for i=1:size(ug.content)[1]
+        for j = 1:size(ug.content)[2]
+            if M[i, j] > 0
+                push!(locs, (i, j))
+            end
+        end
+    end
+
+    new_locs = contract_graph(locs)
+
+    count = 0
+
+    while (new_locs != locs) || (count < 10)
+        locs = new_locs
+        new_locs = contract_graph(locs)
+        print(count)
+        count += 1
+    end
+
+    return new_locs
+end
+
+
+function compress_graph_loc(locs::Vector{Tuple{Int, Int}})
+    new_locs = contract_graph(locs)
+
+    count = 0
+
+    while (new_locs != locs) || (count < 10)
+        locs = new_locs
+        new_locs = contract_graph(locs)
+        print(count)
+        count += 1
+    end
+
+    return new_locs
+end
diff --git a/src/shrinking/compressUDG.jl b/src/shrinking/compressUDG.jl
new file mode 100644
index 0000000..0fbd6d0
--- /dev/null
+++ b/src/shrinking/compressUDG.jl
@@ -0,0 +1,309 @@
+module CompressUDG
+using Graphs
+
+export UNode, contract_graph, CompressUDGMethod
+
+struct UNode
+    vertex::Int # vertex index in original graph
+    pos::Tuple{Int,Int}
+    neighbors::Vector{Int} # neighbors of node
+end
+Base.hash(unode::UNode) = hash(unode.vertex)
+function Base.:(==)(x::UNode, y::UNode)
+    x.vertex == y.vertex && x.neighbors == y.neighbors
+end
+
+# get surrounding neighbor points on UDG
+function get_udg_neighbors(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+
+    pos_udg_neighbors = Vector{Tuple{Int, Int}}()
+    for i=-1:1
+        for j=-1:1
+            if !(i == 0 && j == 0)
+                push!(pos_udg_neighbors, (p_x + i, p_y + j))
+            end
+        end
+    end
+    return pos_udg_neighbors
+end
+
+# find the UDNode given a position
+# return nothing if no node at that position
+function get_UNode_from_pos(pos::Tuple{Int, Int}, node_list::Vector{UNode})
+    for u in node_list
+        if u.pos == pos
+            return u
+        end
+    end
+    return nothing
+end
+
+# find the boundaries of a grid graph given list of UNodes
+function find_boundaries(node_list::Vector{UNode})
+    min_x = typemax(Int)
+    min_y = typemax(Int)
+    max_x = 0
+    max_y = 0
+
+    for u in node_list
+        p_x, p_y = u.pos
+
+        if p_x > max_x
+            max_x = p_x
+        end
+        if p_x < min_x
+            min_x = p_x
+        end
+        if p_y > max_y
+            max_y = p_y
+        end
+        if p_y < min_y
+            min_y = p_y
+        end
+    end
+    return min_x, min_y, max_x, max_y
+end
+
+# find points on the boundary in which we would like to move
+# divide region into 4 and move nodes greedily closer to center
+function find_boundary_points(node_list::Vector{UNode}, x_min, x_max, y_min,
+    y_max)
+    half_x = (x_max - x_min)/2
+    half_y = (y_max - y_min)/2
+
+    pts_xmin_upper = UNode[]
+    pts_xmax_upper = Vector{UNode}()
+    pts_xmin_lower = Vector{UNode}()
+    pts_xmax_lower = Vector{UNode}()
+
+    pts_ymin_left = Vector{UNode}()
+    pts_ymax_left = Vector{UNode}()
+    pts_ymin_right = Vector{UNode}()
+    pts_ymax_right = Vector{UNode}()
+
+    for u in node_list
+        p_x, p_y = u.pos
+
+        if p_x == x_min && p_y >= half_y
+            push!(pts_xmin_upper, u)
+        end
+        if p_x == x_min && p_y < half_y
+            push!(pts_xmin_lower, u)
+        end
+        if p_x == x_max && p_y >= half_y
+            push!(pts_xmax_upper, u)
+        end
+        if p_x == x_max && p_y < half_y
+            push!(pts_xmax_lower, u)
+        end
+        if p_x >= half_x && p_y == y_min
+            push!(pts_ymin_right, u)
+        end
+        if p_x < half_x && p_y == y_min
+            push!(pts_ymin_left, u)
+        end
+        if p_x >= half_x && p_y == y_max
+            push!(pts_ymax_right, u)
+        end
+        if p_x < half_x && p_y == y_max
+            push!(pts_ymax_left, u)
+        end
+    end
+
+    return pts_xmin_upper, pts_xmin_lower, pts_xmax_upper, pts_xmax_lower,
+    pts_ymin_right, pts_ymin_left, pts_ymax_right, pts_ymax_left
+end
+
+# check that the new position of node n satisfies UDG requirements
+function check_UDG_criteria(n::UNode, new_pos::Tuple{Int, Int}, node_list::Vector{UNode})
+    # check if new_pos is already occupied
+    if get_UNode_from_pos(new_pos, node_list) != Nothing()
+        return false
+    end
+
+    p_x, p_y = new_pos
+    p_neighbors = n.neighbors
+
+    new_neighbors = Vector{Int}()
+    UDG_neighbor_pos = get_udg_neighbors(new_pos)
+
+    for p in UDG_neighbor_pos
+        unode = get_UNode_from_pos(p, node_list)
+
+        if unode !== nothing
+            if unode.vertex != n.vertex
+                push!(new_neighbors, unode.vertex)
+            end
+        end
+    end
+
+
+    if issetequal(new_neighbors, p_neighbors) == true
+        return true
+    end
+    return false
+end
+
+# move node n to a new position new_pos
+function move_node(n::UNode, node_list::Vector{UNode}, candidates::Vector{Tuple{Int, Int}})
+
+    for p in candidates
+        if check_UDG_criteria(n, p, node_list) == true
+            new_n = UNode(n.vertex, p, n.neighbors)
+            #n.pos = p
+            node_list[n.vertex] = new_n
+            return node_list
+        end
+    end
+    return node_list
+end
+
+# determine candidates
+function candidates_xmin_upper(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x + 1, p_y), (p_x + 1, p_y - 1), (p_x, p_y - 1)]
+end
+
+function candidates_xmin_lower(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x + 1, p_y), (p_x + 1, p_y + 1), (p_x, p_y + 1)]
+end
+
+
+function candidates_xmax_upper(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x - 1, p_y), (p_x - 1, p_y - 1), (p_x, p_y - 1)]
+end
+
+
+function candidates_xmax_lower(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x - 1, p_y), (p_x - 1, p_y + 1), (p_x, p_y + 1)]
+end
+
+
+function candidates_ymin_left(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x, p_y + 1), (p_x + 1, p_y + 1), (p_x + 1, p_y)]
+end
+
+function candidates_ymin_right(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x, p_y + 1), (p_x - 1, p_y + 1), (p_x - 1, p_y)]
+end
+
+function candidates_ymax_left(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x, p_y - 1), (p_x + 1, p_y - 1), (p_x + 1, p_y)]
+end
+
+function candidates_ymax_right(pos::Tuple{Int, Int})
+    p_x, p_y = pos
+    return [(p_x, p_y - 1), (p_x - 1, p_y - 1), (p_x - 1, p_y)]
+end
+
+function greedy_step(node_list::Vector{UNode}, min_x::Int, max_x::Int,
+    min_y::Int, max_y::Int)
+
+    xmin_upper, xmin_lower, xmax_upper, xmax_lower, ymin_right, ymin_left,
+    ymax_right, ymax_left = find_boundary_points(node_list, min_x, max_x,
+    min_y, max_y)
+
+    for p in xmin_upper
+        candidates = candidates_xmin_upper(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+    for p in xmin_lower
+        candidates = candidates_xmin_lower(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+    for p in xmax_upper
+        candidates = candidates_xmax_upper(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+    for p in xmax_lower
+        candidates = candidates_xmax_lower(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+
+    for p in ymin_left
+        candidates = candidates_ymin_left(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+    for p in ymin_right
+        candidates = candidates_ymin_right(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+    for p in ymax_left
+        candidates = candidates_ymax_left(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+    for p in ymax_right
+        candidates = candidates_ymax_right(p.pos)
+        node_list = move_node(p, node_list, candidates)
+    end
+
+    return node_list
+end
+
+# interfaces
+abstract type CompressUDGMethod end
+
+"""
+    contract_graph(locs::Vector{Tuple{Int, Int}})
+
+Compute a contracted version of input graph node positions and returns a
+corresponding layout of new condensed graph
+"""
+# execute
+function udg(locs::Vector{Tuple{Int, Int}}, unit::Real)
+    n = length(locs)
+    g = SimpleGraph(n)
+    for i=1:n, j=i+1:n
+        if sum(abs2, locs[i] .- locs[j]) < unit ^ 2
+            add_edge!(g, i, j)
+        end
+    end
+    return g
+end
+function contract_graph(node_positions::Vector{Tuple{Int, Int}})
+    # initiate UNodes
+
+    n_list = Vector{UNode}(undef, size(node_positions)[1])
+    g = udg(node_positions, 1.5)
+
+    for (ind, n_pos) in enumerate(node_positions)
+        uneighbors = neighbors(g, ind)
+        unode = UNode(ind, n_pos, uneighbors)
+        n_list[ind] = unode
+    end
+
+    xmin, ymin, xmax, ymax = find_boundaries(n_list)
+
+    while (xmax - xmin > 1) && (ymax - ymin > 1)
+        n_list = greedy_step(n_list, xmin, xmax, ymin, ymax)
+
+        if xmin < xmax
+            xmin += 1
+            xmax -= 1
+        end
+
+        if ymin < ymax
+            ymin += 1
+            ymax -= 1
+        end
+    end
+
+    locs_new = Vector{Tuple{Int, Int}}(undef, size(node_positions)[1])
+    for (ind, un) in enumerate(n_list)
+        locs_new[ind] = un.pos
+    end
+
+    return locs_new
+end
+end
+
+
+using .CompressUDG
+export UNode, contract_graph_ug, compress_graph_loc, CompressUDGMethod
diff --git a/src/simplifiers.jl b/src/simplifiers.jl
index e271dfb..d58e7e7 100644
--- a/src/simplifiers.jl
+++ b/src/simplifiers.jl
@@ -70,18 +70,67 @@ end
 # # How to add a new simplification rule
 # 1. specify a gadget like the following. Use either `o` and `●` to specify a vertex,
 # either `.` or `⋅` to specify a placeholder.
+# ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
+# ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅
 @gg DanglingLeg =
-    """ 
-    ⋅ ⋅ ⋅ 
-    ⋅ ● ⋅ 
-    ⋅ ● ⋅ 
-    ⋅ ● ⋅ 
+    """
+    ⋅ ⋅ ⋅
+    ⋅ ● ⋅
+    ⋅ ● ⋅
+    ⋅ ● ⋅
     """=>"""
-    ⋅ ⋅ ⋅ 
-    ⋅ ⋅ ⋅ 
-    ⋅ ⋅ ⋅ 
+    ⋅ ⋅ ⋅
+    ⋅ ⋅ ⋅
+    ⋅ ⋅ ⋅
     ⋅ ● ⋅
     """
 
+@gg Square =
+    """
+    ⋅ ● ⋅ ⋅
+    ● ⋅ ● ⋅
+    ⋅ ● ⋅ ⋅
+    ⋅ ⋅ ⋅ ⋅
+    """=>"""
+    ⋅ ● ⋅ ⋅
+    ● ⋅ ⋅ ⋅
+    ⋅ ⋅ ⋅ ⋅
+    ⋅ ⋅ ⋅ ⋅
+    """
+
+@gg Cane =
+    """
+    ⋅ ⋅ ⋅ ⋅
+    ⋅ ● ⋅ ⋅
+    ● ⋅ ● ⋅
+    ⋅ ⋅ ● ⋅
+    ⋅ ⋅ ● ⋅
+    """=>"""
+    ⋅ ⋅ ⋅ ⋅
+    ⋅ ⋅ ⋅ ⋅
+    ● ⋅ ⋅ ⋅
+    ⋅ ● ⋅ ⋅
+    ⋅ ⋅ ● ⋅
+    """
+
+@gg CLoop = 
+"""
+⋅ ⋅ ⋅ ⋅
+⋅ ⋅ ● ⋅
+⋅ ● ⋅ ●
+⋅ ● ⋅ ⋅
+⋅ ⋅ ● ⋅
+"""=>"""
+⋅ ⋅ ⋅ ⋅
+⋅ ⋅ ⋅ ⋅
+⋅ ⋅ ⋅ ●
+⋅ ⋅ ● ⋅
+⋅ ⋅ ● ⋅
+"""
+
+
 # 2. run the script `project/createmap` to generate `mis_overhead` and other informations required
-# for mapping back. (Note: will overwrite the source file `src/extracting_results.jl`)
\ No newline at end of file
+# for mapping back. (Note: will overwrite the source file `src/extracting_results.jl`)
diff --git a/test/gadgets.jl b/test/gadgets.jl
index db965f0..1c06ebe 100644
--- a/test/gadgets.jl
+++ b/test/gadgets.jl
@@ -16,4 +16,4 @@ using Graphs
         @test diff == -mis_overhead(s)
         @test sig
     end
-end
\ No newline at end of file
+end
diff --git a/test/mapping.jl b/test/mapping.jl
index f2a0f9c..9ac4569 100644
--- a/test/mapping.jl
+++ b/test/mapping.jl
@@ -60,6 +60,37 @@ end
     end
 end
 
+
+@testset "interface_K23" begin
+    g = SimpleGraph(5)
+
+    add_edge!(g, 1, 5)
+    add_edge!(g, 4, 5)
+    add_edge!(g, 4, 3)
+    add_edge!(g, 3, 2)
+    add_edge!(g, 5, 2)
+    add_edge!(g, 1, 3)
+
+    res = map_graph(g)
+
+    # checking size
+    gp = Independence(SimpleGraph(res.grid_graph); optimizer=TreeSA(ntrials=1, niters=10), simplifier=MergeGreedy())
+    missize_map = solve(gp, "size max")[].n
+    missize = solve(Independence(g), "size max")[].n
+    @test res.mis_overhead + missize == missize_map
+
+    # checking mapping back
+    misconfig = solve(gp, "config max")[].c
+    c = zeros(Int, size(res.grid_graph.content))
+    for (i, loc) in enumerate(findall(!iszero, res.grid_graph.content))
+        c[loc] = misconfig.data[i]
+    end
+    original_configs = map_configs_back(res, [c])
+    @test count(isone, original_configs[1]) == missize
+    @test is_independent_set(g, original_configs[1])
+end
+
+
 @testset "interface" begin
     g = smallgraph(:petersen)
     res = map_graph(g)
@@ -79,4 +110,4 @@ end
     original_configs = map_configs_back(res, [c])
     @test count(isone, original_configs[1]) == missize
     @test is_independent_set(g, original_configs[1])
-end
\ No newline at end of file
+end