You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@systemds.apache.org by ma...@apache.org on 2020/10/30 16:15:34 UTC

[systemds] branch master updated: [SYSTEMDS-2678] Fine-Grained Propagation of RBind and CBind

This is an automated email from the ASF dual-hosted git repository.

markd pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/systemds.git


The following commit(s) were added to refs/heads/master by this push:
     new d601858  [SYSTEMDS-2678] Fine-Grained Propagation of RBind and CBind
d601858 is described below

commit d601858c74de08d0f3d644227e1a9c10223ee737
Author: sebwrede <sw...@know-center.at>
AuthorDate: Fri Oct 30 17:11:55 2020 +0100

    [SYSTEMDS-2678] Fine-Grained Propagation of RBind and CBind
    
    Closes #1066
---
 .../instructions/cp/AppendCPInstruction.java       |    4 +
 .../cp/ListAppendRemoveCPInstruction.java          |    4 +
 .../sysds/runtime/instructions/cp/ListObject.java  |    8 +-
 .../sysds/runtime/privacy/PrivacyConstraint.java   |   15 +
 .../apache/sysds/runtime/privacy/PrivacyUtils.java |   58 +-
 .../finegrained/FineGrainedPrivacyList.java        |   21 +-
 .../privacy/propagation/AppendPropagator.java      |   87 ++
 .../privacy/propagation/CBindPropagator.java       |   49 +
 .../privacy/propagation/ListAppendPropagator.java  |   73 ++
 .../privacy/propagation/ListRemovePropagator.java  |  108 +++
 .../privacy/propagation/PrivacyPropagator.java     |  103 +-
 .../runtime/privacy/propagation/Propagator.java    |    2 +-
 ...{Propagator.java => PropagatorMultiReturn.java} |   10 +-
 .../privacy/propagation/RBindPropagator.java       |   49 +
 .../org/apache/sysds/test/AutomatedTestBase.java   |   33 +
 .../test/functions/privacy/ReadWriteTest.java      |   46 +-
 .../privacy/{ => algorithms}/BuiltinGLMTest.java   |    2 +-
 .../{ => algorithms}/FederatedL2SVMTest.java       |    2 +-
 .../privacy/{ => algorithms}/GLMTest.java          |    2 +-
 .../privacy/propagation/AppendPropagatorTest.java  | 1002 ++++++++++++++++++++
 .../{ => propagation}/CorePropagatorTest.java      |    2 +-
 .../MatrixMultiplicationPropagatorTest.java}       |   90 +-
 src/test/scripts/functions/privacy/CBindTest.dml   |   25 +
 .../scripts/functions/privacy/ListAppendTest.dml   |   25 +
 src/test/scripts/functions/privacy/RBindTest.dml   |   25 +
 .../scripts/functions/privacy/StringAppendTest.dml |   25 +
 26 files changed, 1766 insertions(+), 104 deletions(-)

diff --git a/src/main/java/org/apache/sysds/runtime/instructions/cp/AppendCPInstruction.java b/src/main/java/org/apache/sysds/runtime/instructions/cp/AppendCPInstruction.java
index 34d735b..1216f8e 100644
--- a/src/main/java/org/apache/sysds/runtime/instructions/cp/AppendCPInstruction.java
+++ b/src/main/java/org/apache/sysds/runtime/instructions/cp/AppendCPInstruction.java
@@ -72,4 +72,8 @@ public abstract class AppendCPInstruction extends BinaryCPInstruction
 		else //DataType.FRAME
 			return new FrameAppendCPInstruction(op, in1, in2, out, type, opcode, str);
 	}
+
+	public AppendType getAppendType() {
+		return _type;
+	}
 }
diff --git a/src/main/java/org/apache/sysds/runtime/instructions/cp/ListAppendRemoveCPInstruction.java b/src/main/java/org/apache/sysds/runtime/instructions/cp/ListAppendRemoveCPInstruction.java
index 1721c4a..1bd582f 100644
--- a/src/main/java/org/apache/sysds/runtime/instructions/cp/ListAppendRemoveCPInstruction.java
+++ b/src/main/java/org/apache/sysds/runtime/instructions/cp/ListAppendRemoveCPInstruction.java
@@ -74,4 +74,8 @@ public final class ListAppendRemoveCPInstruction extends AppendCPInstruction {
 			throw new DMLRuntimeException("Unsupported list operation: "+getOpcode());
 		}
 	}
+
+	public CPOperand getOutput2(){
+		return output2;
+	}
 }
diff --git a/src/main/java/org/apache/sysds/runtime/instructions/cp/ListObject.java b/src/main/java/org/apache/sysds/runtime/instructions/cp/ListObject.java
index 8798799..4f726ee 100644
--- a/src/main/java/org/apache/sysds/runtime/instructions/cp/ListObject.java
+++ b/src/main/java/org/apache/sysds/runtime/instructions/cp/ListObject.java
@@ -236,7 +236,13 @@ public class ListObject extends Data {
 			_lineage.add(li);
 		return this;
 	}
-	
+
+	/**
+	 * Removes the element at the specified position from the list
+	 * and returns that element as the only element in a new ListObject.
+	 * @param pos position of element in the list
+	 * @return new ListObject with the specified element
+	 */
 	public ListObject remove(int pos) {
 		ListObject ret = new ListObject(Arrays.asList(_data.get(pos)),
 				null, _lineage != null?Arrays.asList(_lineage.get(pos)):null);
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/PrivacyConstraint.java b/src/main/java/org/apache/sysds/runtime/privacy/PrivacyConstraint.java
index b19d981..e950c22 100644
--- a/src/main/java/org/apache/sysds/runtime/privacy/PrivacyConstraint.java
+++ b/src/main/java/org/apache/sysds/runtime/privacy/PrivacyConstraint.java
@@ -253,4 +253,19 @@ public class PrivacyConstraint implements Externalizable
 		}
 	}
 
+	@Override
+	public boolean equals(Object other){
+		if ( other instanceof PrivacyConstraint ){
+			PrivacyConstraint otherPrivacyConstraint = (PrivacyConstraint) other;
+			return otherPrivacyConstraint.privacyLevel == privacyLevel
+				&& otherPrivacyConstraint.getFineGrainedPrivacy().equals(fineGrainedPrivacy);
+		} else return false;
+	}
+
+	@Override
+	public String toString(){
+		return "General privacy level: " + privacyLevel + System.getProperty("line.separator")
+			+ "Fine-grained privacy level: " + fineGrainedPrivacy.toString();
+	}
+
 }
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/PrivacyUtils.java b/src/main/java/org/apache/sysds/runtime/privacy/PrivacyUtils.java
index 15fff32..206f59d 100644
--- a/src/main/java/org/apache/sysds/runtime/privacy/PrivacyUtils.java
+++ b/src/main/java/org/apache/sysds/runtime/privacy/PrivacyUtils.java
@@ -33,6 +33,62 @@ import org.apache.wink.json4j.JSONObject;
 
 public class PrivacyUtils {
 
+	/**
+	 * Returns true if the privacy constraint is not null and the privacy level is set to Private or PrivateAggregation.
+	 * This only works for the general privacy levels, the fine-grained constraints are not checked!
+	 * @param constraint to check
+	 * @return true if the privacy constraint is not null and activated
+	 */
+	public static boolean privacyConstraintActivated(PrivacyConstraint constraint){
+		return constraint != null &&
+			(constraint.getPrivacyLevel() == PrivacyLevel.Private
+				|| constraint.getPrivacyLevel() == PrivacyLevel.PrivateAggregation);
+	}
+
+	/**
+	 * Returns true if the privacy constraint is not null and it has fine-grained constraints.
+	 * @param constraint to check
+	 * @return true if the privacy constraint is not null and has fine-grained constraints
+	 */
+	public static boolean privacyConstraintFineGrainedActivated(PrivacyConstraint constraint){
+		return constraint != null && constraint.getFineGrainedPrivacy().hasConstraints();
+	}
+
+	/**
+	 * Returns true if some constraints are set for either of two input privacy constraints.
+	 * This only checks first two elements in privacy constraint array.
+	 * @param privacyConstraints input privacy constraints
+	 * @return true if one of the two constraints are activated
+	 */
+	public static boolean someConstraintSetBinary(PrivacyConstraint... privacyConstraints){
+		return privacyConstraints != null &&
+			((privacyConstraints[0] != null && privacyConstraints[0].hasConstraints())
+				|| (privacyConstraints[1] != null && privacyConstraints[1].hasConstraints()));
+	}
+
+	/**
+	 * Returns true if the constraint is set for the input privacy constraint.
+	 * @param privacyConstraint input to check
+	 * @return true if any constraint is activated
+	 */
+	public static boolean someConstraintSetUnary(PrivacyConstraint privacyConstraint){
+		return privacyConstraint != null && privacyConstraint.hasConstraints();
+	}
+
+	public static PrivacyLevel getGeneralPrivacyLevel(PrivacyConstraint privacyConstraint){
+		if ( privacyConstraint != null ){
+			return privacyConstraint.getPrivacyLevel();
+		}
+		else return PrivacyLevel.None;
+	}
+
+	public static PrivacyLevel[] getGeneralPrivacyLevels(PrivacyConstraint[] privacyConstraints){
+		PrivacyLevel[] privacyLevels = new PrivacyLevel[privacyConstraints.length];
+		for ( int i = 0; i < privacyConstraints.length; i++)
+			privacyLevels[i] = getGeneralPrivacyLevel(privacyConstraints[i]);
+		return privacyLevels;
+	}
+
 	public static void setFineGrainedPrivacy(PrivacyConstraint privacyConstraint, Expression eFineGrainedPrivacy){
 		FineGrainedPrivacy fineGrainedPrivacy = privacyConstraint.getFineGrainedPrivacy();
 		StringIdentifier fgPrivacyIdentifier = (StringIdentifier) eFineGrainedPrivacy;
@@ -45,7 +101,7 @@ public class PrivacyUtils {
 		privacyConstraint.setFineGrainedPrivacyConstraints(fineGrainedPrivacy);
 	}
 
-	private static void putFineGrainedConstraintsFromString(FineGrainedPrivacy fineGrainedPrivacy, String fgPrivacyValue)
+	public static void putFineGrainedConstraintsFromString(FineGrainedPrivacy fineGrainedPrivacy, String fgPrivacyValue)
 		throws JSONException {
 		JSONArtifact fgPrivacyJson = JSON.parse(fgPrivacyValue);
 		JSONObject fgPrivacyObject = (JSONObject)fgPrivacyJson;
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/finegrained/FineGrainedPrivacyList.java b/src/main/java/org/apache/sysds/runtime/privacy/finegrained/FineGrainedPrivacyList.java
index 2992606..54cb639 100644
--- a/src/main/java/org/apache/sysds/runtime/privacy/finegrained/FineGrainedPrivacyList.java
+++ b/src/main/java/org/apache/sysds/runtime/privacy/finegrained/FineGrainedPrivacyList.java
@@ -159,8 +159,25 @@ public class FineGrainedPrivacyList implements FineGrainedPrivacy {
 				return true;
 			if ( !otherFGP.hasConstraints() || !hasConstraints() )
 				return false;
-			return otherFGP.getAllConstraintsList().equals(constraintCollection);
-			
+			return listEquals(otherFGP.getAllConstraintsList());
+		}
+		return false;
+	}
+
+	private boolean listEquals(ArrayList<Map.Entry<DataRange,PrivacyLevel>> otherFGP){
+		if ( otherFGP.size() == constraintCollection.size() ){
+			for ( Map.Entry<DataRange, PrivacyLevel> constraint : constraintCollection){
+				if ( !innerEquals(constraint, otherFGP) )
+					return false;
+			}
+			return true;
+		} else return false;
+	}
+
+	private boolean innerEquals(Map.Entry<DataRange, PrivacyLevel> constraint, ArrayList<Map.Entry<DataRange,PrivacyLevel>> otherFGP){
+		for (Map.Entry<DataRange, PrivacyLevel> otherConstraint : otherFGP){
+			if ( constraint.equals(otherConstraint) )
+				return true;
 		}
 		return false;
 	}
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/AppendPropagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/AppendPropagator.java
new file mode 100644
index 0000000..58d1220
--- /dev/null
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/AppendPropagator.java
@@ -0,0 +1,87 @@
+/*
+ * 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.sysds.runtime.privacy.propagation;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint.PrivacyLevel;
+import org.apache.sysds.runtime.privacy.PrivacyUtils;
+import org.apache.sysds.runtime.privacy.finegrained.DataRange;
+import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacy;
+
+public abstract class AppendPropagator implements Propagator {
+
+	protected MatrixBlock input1, input2;
+	protected PrivacyConstraint privacyConstraint1, privacyConstraint2;
+
+	public AppendPropagator(MatrixBlock input1, PrivacyConstraint privacyConstraint1,
+		MatrixBlock input2, PrivacyConstraint privacyConstraint2){
+		setFields(input1, privacyConstraint1, input2, privacyConstraint2);
+	}
+
+	public void setFields(MatrixBlock input1, PrivacyConstraint privacyConstraint1,
+		MatrixBlock input2, PrivacyConstraint privacyConstraint2){
+		this.input1 = input1;
+		this.input2 = input2;
+		this.privacyConstraint1 = privacyConstraint1;
+		this.privacyConstraint2 = privacyConstraint2;
+	}
+
+	@Override
+	public PrivacyConstraint propagate() {
+		PrivacyConstraint mergedPrivacyConstraint = new PrivacyConstraint();
+		propagateInput1Constraint(mergedPrivacyConstraint);
+		propagateInput2Constraint(mergedPrivacyConstraint);
+		return mergedPrivacyConstraint;
+	}
+
+	private void propagateInput1Constraint(PrivacyConstraint mergedPrivacyConstraint){
+		if ( PrivacyUtils.privacyConstraintActivated(privacyConstraint1) ){
+			//Get dimensions of input1 and make a fine-grained constraint of that size with privacy level
+			long[] endDims = new long[]{input1.getNumRows()-1, input1.getNumColumns()-1};
+			mergedPrivacyConstraint.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0}, endDims), privacyConstraint1.getPrivacyLevel());
+		}
+		if ( PrivacyUtils.privacyConstraintFineGrainedActivated(privacyConstraint1) ){
+			privacyConstraint1.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+				constraint -> mergedPrivacyConstraint.getFineGrainedPrivacy().put(constraint.getKey(), constraint.getValue())
+			);
+		}
+	}
+
+	private void propagateInput2Constraint(PrivacyConstraint mergedPrivacyConstraint){
+		if ( PrivacyUtils.privacyConstraintActivated(privacyConstraint2) ){
+			//Get dimensions of input2 and ...
+			long[] endDims = new long[]{input2.getNumRows()-1, input2.getNumColumns()-1};
+			appendInput2(mergedPrivacyConstraint.getFineGrainedPrivacy(),
+				new DataRange(new long[]{0,0}, endDims), privacyConstraint2.getPrivacyLevel());
+		}
+		if ( PrivacyUtils.privacyConstraintFineGrainedActivated(privacyConstraint2) ){
+			// propagate fine-grained constraints
+			privacyConstraint2.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+				constraint -> appendInput2(
+					mergedPrivacyConstraint.getFineGrainedPrivacy(),
+					constraint.getKey(), constraint.getValue()
+				)
+			);
+		}
+	}
+
+	protected abstract void appendInput2(FineGrainedPrivacy mergedConstraint, DataRange range, PrivacyLevel privacyLevel);
+}
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/CBindPropagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/CBindPropagator.java
new file mode 100644
index 0000000..1c0af3e
--- /dev/null
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/CBindPropagator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sysds.runtime.privacy.propagation;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint;
+import org.apache.sysds.runtime.privacy.finegrained.DataRange;
+import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacy;
+
+public class CBindPropagator extends AppendPropagator {
+
+	public CBindPropagator(MatrixBlock input1, PrivacyConstraint privacyConstraint1, MatrixBlock input2,
+		PrivacyConstraint privacyConstraint2) {
+		super(input1, privacyConstraint1, input2, privacyConstraint2);
+	}
+
+	@Override
+	protected void appendInput2(FineGrainedPrivacy mergedConstraint, DataRange range,
+		PrivacyConstraint.PrivacyLevel privacyLevel) {
+		long rowBegin = range.getBeginDims()[0]; //same as before
+		long colBegin = range.getBeginDims()[1] + input1.getNumColumns();
+		long[] beginDims = new long[]{rowBegin, colBegin};
+
+		long rowEnd = range.getEndDims()[0]; //same as before
+		long colEnd = range.getEndDims()[1] + input1.getNumColumns();
+		long[] endDims = new long[]{rowEnd, colEnd};
+
+		DataRange outputRange = new DataRange(beginDims, endDims);
+
+		mergedConstraint.put(outputRange, privacyLevel);
+	}
+}
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/ListAppendPropagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/ListAppendPropagator.java
new file mode 100644
index 0000000..3c88ea3
--- /dev/null
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/ListAppendPropagator.java
@@ -0,0 +1,73 @@
+/*
+ * 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.sysds.runtime.privacy.propagation;
+
+import org.apache.sysds.runtime.instructions.cp.ListObject;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint;
+import org.apache.sysds.runtime.privacy.PrivacyUtils;
+import org.apache.sysds.runtime.privacy.finegrained.DataRange;
+
+import java.util.Map;
+
+public class ListAppendPropagator implements Propagator {
+
+	private final ListObject input1, input2;
+	private final PrivacyConstraint privacyConstraint1, privacyConstraint2;
+
+	public ListAppendPropagator(ListObject input1, PrivacyConstraint privacyConstraint1, ListObject input2, PrivacyConstraint privacyConstraint2){
+		this.input1 = input1;
+		this.input2 = input2;
+		this.privacyConstraint1 = privacyConstraint1;
+		this.privacyConstraint2 = privacyConstraint2;
+	}
+
+	@Override public PrivacyConstraint propagate() {
+		PrivacyConstraint mergedPrivacyConstraint = new PrivacyConstraint();
+		propagateInput1Constraint(mergedPrivacyConstraint);
+		propagateInput2Constraint(mergedPrivacyConstraint);
+		return mergedPrivacyConstraint;
+	}
+
+	private void propagateInput1Constraint(PrivacyConstraint mergedPrivacyConstraint){
+		if(PrivacyUtils.privacyConstraintActivated(privacyConstraint1)) {
+			mergedPrivacyConstraint.getFineGrainedPrivacy()
+				.put(new DataRange(new long[] {0}, new long[] {input1.getLength()-1}), privacyConstraint1.getPrivacyLevel());
+		}
+		if ( PrivacyUtils.privacyConstraintFineGrainedActivated(privacyConstraint1) ){
+			privacyConstraint1.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+				constraint -> mergedPrivacyConstraint.getFineGrainedPrivacy().put(constraint.getKey(), constraint.getValue()));
+		}
+	}
+
+	private void propagateInput2Constraint(PrivacyConstraint mergedPrivacyConstraint){
+		if ( PrivacyUtils.privacyConstraintActivated(privacyConstraint2) ){
+			mergedPrivacyConstraint.getFineGrainedPrivacy()
+				.put(new DataRange(new long[]{input1.getLength()}, new long[]{input1.getLength() + input2.getLength() - 1}), privacyConstraint2.getPrivacyLevel());
+		}
+		if ( PrivacyUtils.privacyConstraintFineGrainedActivated(privacyConstraint2) ){
+			for ( Map.Entry<DataRange, PrivacyConstraint.PrivacyLevel> constraint : privacyConstraint2.getFineGrainedPrivacy().getAllConstraintsList()){
+				long beginIndex = constraint.getKey().getBeginDims()[0] + input1.getLength();
+				long endIndex = constraint.getKey().getEndDims()[0] + input1.getLength();
+				mergedPrivacyConstraint.getFineGrainedPrivacy()
+					.put(new DataRange(new long[]{beginIndex}, new long[]{endIndex}), constraint.getValue());
+			}
+		}
+	}
+}
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/ListRemovePropagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/ListRemovePropagator.java
new file mode 100644
index 0000000..47d2e24
--- /dev/null
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/ListRemovePropagator.java
@@ -0,0 +1,108 @@
+/*
+ * 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.sysds.runtime.privacy.propagation;
+
+import org.apache.sysds.runtime.instructions.cp.ListObject;
+import org.apache.sysds.runtime.instructions.cp.ScalarObject;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint.PrivacyLevel;
+import org.apache.sysds.runtime.privacy.PrivacyUtils;
+import org.apache.sysds.runtime.privacy.finegrained.DataRange;
+
+import java.util.Map;
+
+public class ListRemovePropagator implements PropagatorMultiReturn {
+	private final ScalarObject removePosition;
+	private final PrivacyConstraint removePositionPrivacyConstraint;
+	private final ListObject list;
+	private final PrivacyConstraint listPrivacyConstraint;
+
+
+	public ListRemovePropagator(ListObject list, PrivacyConstraint listPrivacyConstraint, ScalarObject removePosition, PrivacyConstraint removePositionPrivacyConstraint){
+		this.list = list;
+		this.listPrivacyConstraint = listPrivacyConstraint;
+		this.removePosition = removePosition;
+		this.removePositionPrivacyConstraint = removePositionPrivacyConstraint;
+	}
+
+	@Override
+	public PrivacyConstraint[] propagate() {
+		PrivacyConstraint output1PrivacyConstraint = new PrivacyConstraint();
+		PrivacyConstraint output2PrivacyConstraint = new PrivacyConstraint();
+		propagateGeneralConstraints(output1PrivacyConstraint, output2PrivacyConstraint);
+		propagateFineGrainedConstraints(output1PrivacyConstraint, output2PrivacyConstraint);
+		return new PrivacyConstraint[]{output1PrivacyConstraint, output2PrivacyConstraint};
+	}
+
+	private void propagateFineGrainedConstraints(PrivacyConstraint output1PrivacyConstraint, PrivacyConstraint output2PrivacyConstraint){
+		if ( PrivacyUtils.privacyConstraintFineGrainedActivated(listPrivacyConstraint) ){
+			propagateFirstHalf(output1PrivacyConstraint);
+			propagateSecondHalf(output1PrivacyConstraint);
+			propagateRemovedElement(output2PrivacyConstraint);
+		}
+	}
+
+	private void propagateFirstHalf(PrivacyConstraint output1PrivacyConstraint){
+		// The newEndDimension is minus 2 since removePosition is given in 1-index terms whereas the data
+		// and privacy constraints are 0-index and the privacy constraints are given as closed intervals
+		long[] newEndDimension = new long[]{removePosition.getLongValue()-2};
+		Map<DataRange, PrivacyLevel> output1Ranges = listPrivacyConstraint.getFineGrainedPrivacy()
+			.getPrivacyLevel(new DataRange(new long[]{0}, newEndDimension));
+		output1Ranges.forEach(
+			(range, privacyLevel) -> {
+				long endDim = Long.min(range.getEndDims()[0], removePosition.getLongValue()-2);
+				DataRange cappedRange = new DataRange(range.getBeginDims(),new long[]{endDim});
+				output1PrivacyConstraint.getFineGrainedPrivacy().put(cappedRange, privacyLevel);
+			}
+		);
+	}
+
+	private void propagateSecondHalf(PrivacyConstraint output1PrivacyConstraint){
+		Map<DataRange, PrivacyLevel> output2Ranges = listPrivacyConstraint.getFineGrainedPrivacy()
+			.getPrivacyLevel(new DataRange(new long[]{removePosition.getLongValue()}, new long[]{list.getLength()}));
+		output2Ranges.forEach(
+			(range, privacyLevel) -> {
+				long[] beginDims = new long[]{range.getBeginDims()[0]-1};
+				long[] endDims = new long[]{range.getEndDims()[0]-1};
+				output1PrivacyConstraint.getFineGrainedPrivacy().put(new DataRange(beginDims, endDims), privacyLevel);
+			}
+		);
+	}
+
+	private void propagateRemovedElement(PrivacyConstraint output2PrivacyConstraint){
+		if ( output2PrivacyConstraint.getPrivacyLevel() != PrivacyLevel.Private ){
+			Map<DataRange, PrivacyLevel> elementPrivacy = listPrivacyConstraint.getFineGrainedPrivacy()
+				.getPrivacyLevelOfElement(new long[]{removePosition.getLongValue()-1});
+			if ( elementPrivacy.containsValue(PrivacyLevel.Private) )
+				output2PrivacyConstraint.setPrivacyLevel(PrivacyLevel.Private);
+			else if ( elementPrivacy.containsValue(PrivacyLevel.PrivateAggregation) )
+				output2PrivacyConstraint.setPrivacyLevel(PrivacyLevel.PrivateAggregation);
+		}
+	}
+
+	private void propagateGeneralConstraints(PrivacyConstraint output1PrivacyConstraint, PrivacyConstraint output2PrivacyConstraint){
+		PrivacyLevel[] inputPrivacyLevels = PrivacyUtils.getGeneralPrivacyLevels(new PrivacyConstraint[]{
+			listPrivacyConstraint, removePositionPrivacyConstraint
+		});
+		PrivacyLevel outputPrivacyLevel = PrivacyPropagator.corePropagation(inputPrivacyLevels, OperatorType.NonAggregate);
+		output1PrivacyConstraint.setPrivacyLevel(outputPrivacyLevel);
+		output2PrivacyConstraint.setPrivacyLevel(outputPrivacyLevel);
+	}
+}
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/PrivacyPropagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/PrivacyPropagator.java
index b6b845d..2776a49 100644
--- a/src/main/java/org/apache/sysds/runtime/privacy/propagation/PrivacyPropagator.java
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/PrivacyPropagator.java
@@ -22,29 +22,15 @@ package org.apache.sysds.runtime.privacy.propagation;
 import java.util.*;
 
 import org.apache.sysds.parser.DataExpression;
+import org.apache.sysds.runtime.DMLRuntimeException;
 import org.apache.sysds.runtime.controlprogram.context.ExecutionContext;
 import org.apache.sysds.runtime.instructions.Instruction;
-import org.apache.sysds.runtime.instructions.cp.AggregateBinaryCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.AggregateUnaryCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.BinaryCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.BuiltinNaryCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.CPInstruction;
-import org.apache.sysds.runtime.instructions.cp.CPOperand;
-import org.apache.sysds.runtime.instructions.cp.ComputationCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.CovarianceCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.Data;
-import org.apache.sysds.runtime.instructions.cp.FunctionCallCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.MultiReturnParameterizedBuiltinCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.ParameterizedBuiltinCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.MultiReturnBuiltinCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.QuaternaryCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.SqlCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.UnaryCPInstruction;
-import org.apache.sysds.runtime.instructions.cp.VariableCPInstruction;
+import org.apache.sysds.runtime.instructions.cp.*;
 import org.apache.sysds.runtime.matrix.data.MatrixBlock;
 import org.apache.sysds.runtime.privacy.DMLPrivacyException;
 import org.apache.sysds.runtime.privacy.PrivacyConstraint;
 import org.apache.sysds.runtime.privacy.PrivacyConstraint.PrivacyLevel;
+import org.apache.sysds.runtime.privacy.PrivacyUtils;
 import org.apache.wink.json4j.JSONException;
 import org.apache.wink.json4j.JSONObject;
 
@@ -188,6 +174,7 @@ public class PrivacyPropagator
 				// Assumption: aggregates in one or several dimensions, number of dimensions may change, only certain slices of the data may be aggregated upon, elements do not change position
 				return preprocessAggregateUnaryCPInstruction((AggregateUnaryCPInstruction)inst, ec);
 			case Append:
+				return preprocessAppendCPInstruction((AppendCPInstruction) inst, ec);
 			case Binary:
 				// TODO: Support propagation of fine-grained privacy constraints
 				return preprocessBinaryCPInstruction((BinaryCPInstruction) inst, ec);
@@ -281,24 +268,62 @@ public class PrivacyPropagator
 	}
 
 	private static Instruction preprocessAggregateBinaryCPInstruction(AggregateBinaryCPInstruction inst, ExecutionContext ec){
-		PrivacyConstraint privacyConstraint1 = getInputPrivacyConstraint(ec, inst.input1);
-		PrivacyConstraint privacyConstraint2 = getInputPrivacyConstraint(ec, inst.input2);
-		if ( (privacyConstraint1 != null && privacyConstraint1.hasConstraints()) 
-			|| (privacyConstraint2 != null && privacyConstraint2.hasConstraints()) ){
-				PrivacyConstraint mergedPrivacyConstraint;
-				if ( (privacyConstraint1 != null && privacyConstraint1.hasFineGrainedConstraints() ) || (privacyConstraint2 != null && privacyConstraint2.hasFineGrainedConstraints() )){
-					MatrixBlock input1 = ec.getMatrixInput(inst.input1.getName());
-					MatrixBlock input2 = ec.getMatrixInput(inst.input2.getName());
-					Propagator propagator = new MatrixMultiplicationPropagatorPrivateFirst(input1, privacyConstraint1, input2, privacyConstraint2);
-					mergedPrivacyConstraint = propagator.propagate();
-					ec.releaseMatrixInput(inst.input1.getName(), inst.input2.getName());
-				}
-				else {
-					mergedPrivacyConstraint = mergeNary(new PrivacyConstraint[]{privacyConstraint1,privacyConstraint2},
-						OperatorType.NonAggregate);
-					inst.setPrivacyConstraint(mergedPrivacyConstraint);
+		PrivacyConstraint[] privacyConstraints = getInputPrivacyConstraints(ec, inst.getInputs());
+		if ( PrivacyUtils.someConstraintSetBinary(privacyConstraints) ){
+			PrivacyConstraint mergedPrivacyConstraint;
+			if ( (privacyConstraints[0] != null && privacyConstraints[0].hasFineGrainedConstraints() ) ||
+				(privacyConstraints[1] != null && privacyConstraints[1].hasFineGrainedConstraints() )){
+				MatrixBlock input1 = ec.getMatrixInput(inst.input1.getName());
+				MatrixBlock input2 = ec.getMatrixInput(inst.input2.getName());
+				Propagator propagator = new MatrixMultiplicationPropagatorPrivateFirst(input1, privacyConstraints[0], input2, privacyConstraints[1]);
+				mergedPrivacyConstraint = propagator.propagate();
+				ec.releaseMatrixInput(inst.input1.getName(), inst.input2.getName());
+			}
+			else {
+				mergedPrivacyConstraint = mergeNary(privacyConstraints, OperatorType.NonAggregate);
+				inst.setPrivacyConstraint(mergedPrivacyConstraint);
+			}
+			inst.output.setPrivacyConstraint(mergedPrivacyConstraint);
+		}
+		return inst;
+	}
+
+	public static Instruction preprocessAppendCPInstruction(AppendCPInstruction inst, ExecutionContext ec){
+		PrivacyConstraint[] privacyConstraints = getInputPrivacyConstraints(ec, inst.getInputs());
+		if ( PrivacyUtils.someConstraintSetBinary(privacyConstraints) ){
+			if ( inst.getAppendType() == AppendCPInstruction.AppendType.STRING ){
+				PrivacyLevel[] privacyLevels = new PrivacyLevel[2];
+				privacyLevels[0] = PrivacyUtils.getGeneralPrivacyLevel(privacyConstraints[0]);
+				privacyLevels[1] =  PrivacyUtils.getGeneralPrivacyLevel(privacyConstraints[1]);
+				PrivacyConstraint outputConstraint = new PrivacyConstraint(corePropagation(privacyLevels, OperatorType.NonAggregate));
+				inst.output.setPrivacyConstraint(outputConstraint);
+			} else if ( inst.getAppendType() == AppendCPInstruction.AppendType.LIST ){
+				ListObject input1 = (ListObject) ec.getVariable(inst.input1);
+				if ( inst.getOpcode().equals("remove")){
+					ScalarObject removePosition = ec.getScalarInput(inst.input2);
+					PropagatorMultiReturn propagator = new ListRemovePropagator(input1, privacyConstraints[0], removePosition, removePosition.getPrivacyConstraint());
+					PrivacyConstraint[] outputConstraints = propagator.propagate();
+					inst.output.setPrivacyConstraint(outputConstraints[0]);
+					((ListAppendRemoveCPInstruction) inst).getOutput2().setPrivacyConstraint(outputConstraints[1]);
+				} else {
+					ListObject input2 = (ListObject) ec.getVariable(inst.input2);
+					Propagator propagator = new ListAppendPropagator(input1, privacyConstraints[0], input2, privacyConstraints[1]);
+					inst.output.setPrivacyConstraint(propagator.propagate());
 				}
-				inst.output.setPrivacyConstraint(mergedPrivacyConstraint);
+			}
+			else {
+				MatrixBlock input1 = ec.getMatrixInput(inst.input1.getName());
+				MatrixBlock input2 = ec.getMatrixInput(inst.input2.getName());
+				Propagator propagator = null;
+				if ( inst.getAppendType() == AppendCPInstruction.AppendType.RBIND )
+					propagator = new RBindPropagator(input1, privacyConstraints[0], input2, privacyConstraints[1]);
+				else if ( inst.getAppendType() == AppendCPInstruction.AppendType.CBIND )
+					propagator = new CBindPropagator(input1, privacyConstraints[0], input2, privacyConstraints[1]);
+				else throw new DMLPrivacyException("Instruction " + inst.getCPInstructionType() + " with append type " +
+						inst.getAppendType() + " is not supported by the privacy propagator");
+				inst.output.setPrivacyConstraint(propagator.propagate());
+				ec.releaseMatrixInput(inst.input1.getName(), inst.input2.getName());
+			}
 		}
 		return inst;
 	}
@@ -583,18 +608,12 @@ public class PrivacyPropagator
 		if (!instOutputs.isEmpty()){
 			for ( CPOperand output : instOutputs ){
 				PrivacyConstraint outputPrivacyConstraint = output.getPrivacyConstraint();
-				if ( privacyConstraintActivated(outputPrivacyConstraint) || (outputPrivacyConstraint != null && outputPrivacyConstraint.hasFineGrainedConstraints()))
+				if ( PrivacyUtils.someConstraintSetUnary(outputPrivacyConstraint) )
 					setOutputPrivacyConstraint(ec, outputPrivacyConstraint, output.getName());
 			}
 		}
 	}
 
-	private static boolean privacyConstraintActivated(PrivacyConstraint instructionPrivacyConstraint){
-		return instructionPrivacyConstraint != null && 
-			(instructionPrivacyConstraint.getPrivacyLevel() == PrivacyLevel.Private
-			|| instructionPrivacyConstraint.getPrivacyLevel() == PrivacyLevel.PrivateAggregation);
-	}
-
 	@SuppressWarnings("unused")
 	private static String[] getOutputVariableName(Instruction inst){
 		String[] instructionOutputNames = null;
@@ -624,6 +643,8 @@ public class PrivacyPropagator
 			return getSingletonList(((VariableCPInstruction) inst).getOutput());
 		else if ( inst instanceof SqlCPInstruction )
 			return getSingletonList(((SqlCPInstruction) inst).getOutput());
+		else if ( inst instanceof BuiltinNaryCPInstruction )
+			return getSingletonList(((BuiltinNaryCPInstruction)inst).getOutput());
 		return new ArrayList<>();
 	}
 
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java
index 48a261a..f14e250 100644
--- a/src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java
@@ -22,7 +22,7 @@ package org.apache.sysds.runtime.privacy.propagation;
 import org.apache.sysds.runtime.privacy.PrivacyConstraint;
 
 /**
- * Interface for all propagator instances.
+ * Interface for all propagator instances with a single output.
  */
 public interface Propagator {
 	/**
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/PropagatorMultiReturn.java
similarity index 84%
copy from src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java
copy to src/main/java/org/apache/sysds/runtime/privacy/propagation/PropagatorMultiReturn.java
index 48a261a..841ed61 100644
--- a/src/main/java/org/apache/sysds/runtime/privacy/propagation/Propagator.java
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/PropagatorMultiReturn.java
@@ -22,12 +22,12 @@ package org.apache.sysds.runtime.privacy.propagation;
 import org.apache.sysds.runtime.privacy.PrivacyConstraint;
 
 /**
- * Interface for all propagator instances.
+ * Interface for all propagator instances with multiple outputs.
  */
-public interface Propagator {
+public interface PropagatorMultiReturn {
 	/**
-	 * Activates the propagation and returns the output privacy constraint.
-	 * @return output privacy constraint.
+	 * Activates the propagation and returns the output privacy constraints.
+	 * @return output privacy constraints.
 	 */
-	PrivacyConstraint propagate();
+	PrivacyConstraint[] propagate();
 }
diff --git a/src/main/java/org/apache/sysds/runtime/privacy/propagation/RBindPropagator.java b/src/main/java/org/apache/sysds/runtime/privacy/propagation/RBindPropagator.java
new file mode 100644
index 0000000..15ec6e5
--- /dev/null
+++ b/src/main/java/org/apache/sysds/runtime/privacy/propagation/RBindPropagator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sysds.runtime.privacy.propagation;
+
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint;
+import org.apache.sysds.runtime.privacy.finegrained.DataRange;
+import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacy;
+
+public class RBindPropagator extends AppendPropagator {
+
+	public RBindPropagator(MatrixBlock input1, PrivacyConstraint privacyConstraint1, MatrixBlock input2,
+		PrivacyConstraint privacyConstraint2) {
+		super(input1, privacyConstraint1, input2, privacyConstraint2);
+	}
+
+	@Override
+	protected void appendInput2(FineGrainedPrivacy mergedConstraint, DataRange range,
+		PrivacyConstraint.PrivacyLevel privacyLevel) {
+		long rowBegin = range.getBeginDims()[0] + input1.getNumRows();
+		long colBegin = range.getBeginDims()[1]; //same as before
+		long[] beginDims = new long[]{rowBegin, colBegin};
+
+		long rowEnd = range.getEndDims()[0] + input1.getNumRows();
+		long colEnd = range.getEndDims()[1]; //same as before
+		long[] endDims = new long[]{rowEnd, colEnd};
+
+		DataRange outputRange = new DataRange(beginDims, endDims);
+
+		mergedConstraint.put(outputRange, privacyLevel);
+	}
+}
diff --git a/src/test/java/org/apache/sysds/test/AutomatedTestBase.java b/src/test/java/org/apache/sysds/test/AutomatedTestBase.java
index b97d907..c269742 100644
--- a/src/test/java/org/apache/sysds/test/AutomatedTestBase.java
+++ b/src/test/java/org/apache/sysds/test/AutomatedTestBase.java
@@ -70,6 +70,7 @@ import org.apache.sysds.runtime.meta.MatrixCharacteristics;
 import org.apache.sysds.runtime.privacy.CheckedConstraintsLog;
 import org.apache.sysds.runtime.privacy.PrivacyConstraint;
 import org.apache.sysds.runtime.privacy.PrivacyConstraint.PrivacyLevel;
+import org.apache.sysds.runtime.privacy.PrivacyUtils;
 import org.apache.sysds.runtime.util.DataConverter;
 import org.apache.sysds.runtime.util.HDFSTool;
 import org.apache.sysds.utils.ParameterBuilder;
@@ -828,6 +829,38 @@ public abstract class AutomatedTestBase {
 		return new DataExpression().readMetadataFile(fname, false);
 	}
 
+	/**
+	 * Returns the privacy constraint as read from metadata file.
+	 * @param fileName name of file
+	 * @return loaded privacy constraint
+	 * @throws DMLRuntimeException in case of problems with reading the metadata file
+	 */
+	public static PrivacyConstraint getPrivacyConstraintFromMetaData(String fileName, String dir) throws DMLRuntimeException {
+		PrivacyConstraint outputPrivacyConstraint = new PrivacyConstraint();
+		try {
+			JSONObject metadata = getMetaDataJSON(fileName, dir);
+			if ( metadata != null ){
+				if ( metadata.containsKey(DataExpression.PRIVACY) ){
+					PrivacyLevel readPrivacyLevel = PrivacyLevel.valueOf(metadata.get(DataExpression.PRIVACY).toString());
+					outputPrivacyConstraint.setPrivacyLevel(readPrivacyLevel);
+				} else {
+					outputPrivacyConstraint.setPrivacyLevel(PrivacyLevel.None);
+				}
+				if ( metadata.containsKey(DataExpression.FINE_GRAINED_PRIVACY)){
+					JSONObject fineGrainedJSON = (JSONObject) metadata.get(DataExpression.FINE_GRAINED_PRIVACY);
+					PrivacyUtils.putFineGrainedConstraintsFromString(outputPrivacyConstraint.getFineGrainedPrivacy(), fineGrainedJSON.toString());
+				}
+			}
+		} catch (JSONException e){
+			throw new DMLRuntimeException("Exception when reading from meta data file", e);
+		}
+		return outputPrivacyConstraint;
+	}
+
+	public static PrivacyConstraint getPrivacyConstraintFromMetaData(String fileName) throws DMLRuntimeException {
+		return getPrivacyConstraintFromMetaData(fileName, OUTPUT_DIR);
+	}
+
 	public static String readDMLMetaDataValue(String fileName, String outputDir, String key) throws JSONException {
 		JSONObject meta = getMetaDataJSON(fileName, outputDir);
 		return meta.get(key).toString();
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/ReadWriteTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/ReadWriteTest.java
index 02bcc31..6b0f941 100644
--- a/src/test/java/org/apache/sysds/test/functions/privacy/ReadWriteTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/ReadWriteTest.java
@@ -37,6 +37,7 @@ import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacyList;
 import org.apache.sysds.test.AutomatedTestBase;
 import org.apache.sysds.test.TestConfiguration;
 import org.apache.wink.json4j.JSONObject;
+import org.junit.Assert;
 import org.junit.Test;
 
 public class ReadWriteTest extends AutomatedTestBase {
@@ -88,19 +89,56 @@ public class ReadWriteTest extends AutomatedTestBase {
 		assertTrue(metadata.containsKey("fine_grained_privacy"));
 	}
 
+	@Test
+	public void writeAndEqualsFineGrainedConstraintsTest(){
+		TestConfiguration config = availableTestConfigurations.get("ReadWriteTest");
+		loadTestConfiguration(config);
+
+		writeA();
+
+		JSONObject metadata = getMetaDataJSON("a", "in/");
+		assertTrue(metadata.containsKey("fine_grained_privacy"));
+
+		PrivacyConstraint expectedPC = new PrivacyConstraint();
+		setFineGrained(expectedPC);
+		PrivacyConstraint constraint = getPrivacyConstraintFromMetaData("a", "in/");
+		Assert.assertEquals(expectedPC, constraint);
+	}
+
+	@Test
+	public void writeAndEqualsFineGrainedConstraintsTest2(){
+		TestConfiguration config = availableTestConfigurations.get("ReadWriteTest");
+		loadTestConfiguration(config);
+
+		writeA();
+
+		JSONObject metadata = getMetaDataJSON("a", "in/");
+		assertTrue(metadata.containsKey("fine_grained_privacy"));
+
+		PrivacyConstraint expectedPC = new PrivacyConstraint();
+		setFineGrained(expectedPC);
+		expectedPC.getFineGrainedPrivacy().put(new DataRange(new long[]{12,6}, new long[]{15,8}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint = getPrivacyConstraintFromMetaData("a", "in/");
+		Assert.assertNotEquals(expectedPC, constraint);
+	}
+
 	private double[][] writeA(){
 		int k = 15;
 		double[][] a = getRandomMatrix(m, n, -1, 1, 1, -1);
 
 		PrivacyConstraint privacyConstraint = new PrivacyConstraint();
-		FineGrainedPrivacy fgp = new FineGrainedPrivacyList();
+		setFineGrained(privacyConstraint);
+		MatrixCharacteristics dataCharacteristics = new MatrixCharacteristics(m,n,k,k);
+		writeInputMatrixWithMTD("a", a, false, dataCharacteristics, privacyConstraint);
+		return a;
+	}
+
+	private void setFineGrained(PrivacyConstraint privacyConstraint){
+		FineGrainedPrivacy fgp = privacyConstraint.getFineGrainedPrivacy();
 		fgp.put(new DataRange(new long[]{1,2}, new long[]{5,4}), PrivacyLevel.Private);
 		fgp.put(new DataRange(new long[]{7,1}, new long[]{9,1}), PrivacyLevel.Private);
 		fgp.put(new DataRange(new long[]{10,5}, new long[]{10,9}), PrivacyLevel.PrivateAggregation);
 		privacyConstraint.setFineGrainedPrivacyConstraints(fgp);
-		MatrixCharacteristics dataCharacteristics = new MatrixCharacteristics(m,n,k,k);
-		writeInputMatrixWithMTD("a", a, false, dataCharacteristics, privacyConstraint);
-		return a;
 	}
 
 	@Test
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/BuiltinGLMTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/algorithms/BuiltinGLMTest.java
similarity index 99%
rename from src/test/java/org/apache/sysds/test/functions/privacy/BuiltinGLMTest.java
rename to src/test/java/org/apache/sysds/test/functions/privacy/algorithms/BuiltinGLMTest.java
index 9de2265..7359e2f 100644
--- a/src/test/java/org/apache/sysds/test/functions/privacy/BuiltinGLMTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/algorithms/BuiltinGLMTest.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.sysds.test.functions.privacy;
+package org.apache.sysds.test.functions.privacy.algorithms;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/FederatedL2SVMTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/algorithms/FederatedL2SVMTest.java
similarity index 99%
rename from src/test/java/org/apache/sysds/test/functions/privacy/FederatedL2SVMTest.java
rename to src/test/java/org/apache/sysds/test/functions/privacy/algorithms/FederatedL2SVMTest.java
index 8991b13..f849e2b 100644
--- a/src/test/java/org/apache/sysds/test/functions/privacy/FederatedL2SVMTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/algorithms/FederatedL2SVMTest.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.sysds.test.functions.privacy;
+package org.apache.sysds.test.functions.privacy.algorithms;
 
 import org.apache.sysds.runtime.DMLRuntimeException;
 import org.junit.Test;
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/GLMTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/algorithms/GLMTest.java
similarity index 99%
rename from src/test/java/org/apache/sysds/test/functions/privacy/GLMTest.java
rename to src/test/java/org/apache/sysds/test/functions/privacy/algorithms/GLMTest.java
index 5919523..350ff4a 100644
--- a/src/test/java/org/apache/sysds/test/functions/privacy/GLMTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/algorithms/GLMTest.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.sysds.test.functions.privacy;
+package org.apache.sysds.test.functions.privacy.algorithms;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/propagation/AppendPropagatorTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/propagation/AppendPropagatorTest.java
new file mode 100644
index 0000000..560db59
--- /dev/null
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/propagation/AppendPropagatorTest.java
@@ -0,0 +1,1002 @@
+/*
+ * 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.sysds.test.functions.privacy.propagation;
+
+import org.apache.sysds.api.DMLScript;
+import org.apache.sysds.common.Types;
+import org.apache.sysds.parser.DataExpression;
+import org.apache.sysds.runtime.instructions.cp.*;
+import org.apache.sysds.runtime.matrix.data.MatrixBlock;
+import org.apache.sysds.runtime.meta.MatrixCharacteristics;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint;
+import org.apache.sysds.runtime.privacy.PrivacyConstraint.PrivacyLevel;
+import org.apache.sysds.runtime.privacy.PrivacyUtils;
+import org.apache.sysds.runtime.privacy.finegrained.DataRange;
+import org.apache.sysds.runtime.privacy.finegrained.FineGrainedPrivacy;
+import org.apache.sysds.runtime.privacy.propagation.*;
+import org.apache.sysds.test.AutomatedTestBase;
+import org.apache.sysds.test.TestConfiguration;
+import org.apache.sysds.test.TestUtils;
+import org.apache.sysds.test.functions.federated.primitives.FederatedRCBindTest;
+import org.apache.wink.json4j.JSONException;
+import org.apache.wink.json4j.JSONObject;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class AppendPropagatorTest extends AutomatedTestBase {
+
+	private final static String TEST_DIR = "functions/privacy/";
+	private final static String TEST_NAME_RBIND = "RBindTest";
+	private final static String TEST_NAME_CBIND = "CBindTest";
+	private final static String TEST_NAME_STRING = "StringAppendTest";
+	private final static String TEST_NAME_LIST = "ListAppendTest";
+	private final static String TEST_CLASS_DIR = TEST_DIR + AppendPropagatorTest.class.getSimpleName() + "/";
+
+	@Override public void setUp() {
+		TestUtils.clearAssertionInformation();
+		addTestConfiguration(TEST_NAME_RBIND, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME_RBIND, new String[] {"C"}));
+		addTestConfiguration(TEST_NAME_CBIND, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME_CBIND, new String[] {"C"}));
+		addTestConfiguration(TEST_NAME_STRING, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME_STRING, new String[] {"C"}));
+		addTestConfiguration(TEST_NAME_LIST, new TestConfiguration(TEST_CLASS_DIR, TEST_NAME_LIST, new String[] {"C"}));
+	}
+
+	@Test
+	public void generalOnlyRBindPrivate1Test(){
+		generalOnlyRBindTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyRBindPrivateAggregation1Test(){
+		generalOnlyRBindTest(new PrivacyConstraint(PrivacyLevel.PrivateAggregation), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyRBindNoneTest(){
+		generalOnlyRBindTest(new PrivacyConstraint(), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyRBindPrivate2Test(){
+		generalOnlyRBindTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.Private));
+	}
+
+	@Test
+	public void generalOnlyRBindPrivateAggregation2Test(){
+		generalOnlyRBindTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.PrivateAggregation));
+	}
+
+	@Test
+	public void generalOnlyRBindPrivatePrivateTest(){
+		generalOnlyRBindTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.Private));
+	}
+
+	@Test
+	public void generalOnlyRBindPrivatePrivateAggregationTest(){
+		generalOnlyRBindTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.PrivateAggregation));
+	}
+
+	private void generalOnlyRBindTest(PrivacyConstraint constraint1, PrivacyConstraint constraint2){
+		int columns = 2;
+		int rows1 = 4;
+		int rows2 = 3;
+		MatrixBlock inputMatrix1 = new MatrixBlock(rows1,columns,3);
+		MatrixBlock inputMatrix2 = new MatrixBlock(rows2,columns,4);
+		AppendPropagator propagator = new RBindPropagator(inputMatrix1, constraint1, inputMatrix2, constraint2);
+		PrivacyConstraint mergedConstraint = propagator.propagate();
+		Assert.assertEquals(mergedConstraint.getPrivacyLevel(), PrivacyLevel.None);
+		Map<DataRange, PrivacyLevel> firstHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0,0}, new long[]{rows1-1,columns-1}));
+		firstHalfPrivacy.forEach((range,level) -> Assert.assertEquals(constraint1.getPrivacyLevel(),level));
+		Map<DataRange, PrivacyLevel> secondHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{rows1,0}, new long[]{rows1+rows2-1,columns-1}));
+		secondHalfPrivacy.forEach((range,level) -> Assert.assertEquals(constraint2.getPrivacyLevel(),level));
+	}
+
+	@Test
+	public void generalOnlyCBindPrivate1Test(){
+		generalOnlyCBindTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyCBindPrivateAggregation1Test(){
+		generalOnlyCBindTest(new PrivacyConstraint(PrivacyLevel.PrivateAggregation), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyCBindNoneTest(){
+		generalOnlyCBindTest(new PrivacyConstraint(), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyCBindPrivate2Test(){
+		generalOnlyCBindTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.Private));
+	}
+
+	@Test
+	public void generalOnlyCBindPrivateAggregation2Test(){
+		generalOnlyCBindTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.PrivateAggregation));
+	}
+
+	@Test
+	public void generalOnlyCBindPrivatePrivateTest(){
+		generalOnlyCBindTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.Private));
+	}
+
+	@Test
+	public void generalOnlyCBindPrivatePrivateAggregationTest(){
+		generalOnlyCBindTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.PrivateAggregation));
+	}
+
+	private void generalOnlyCBindTest(PrivacyConstraint constraint1, PrivacyConstraint constraint2){
+		int rows = 2;
+		int columns1 = 4;
+		int columns2 = 3;
+		MatrixBlock inputMatrix1 = new MatrixBlock(rows,columns1,3);
+		MatrixBlock inputMatrix2 = new MatrixBlock(rows,columns2,4);
+		AppendPropagator propagator = new CBindPropagator(inputMatrix1, constraint1, inputMatrix2, constraint2);
+		PrivacyConstraint mergedConstraint = propagator.propagate();
+		Assert.assertEquals(mergedConstraint.getPrivacyLevel(), PrivacyLevel.None);
+		Map<DataRange, PrivacyLevel> firstHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0,0}, new long[]{rows-1,columns1-1}));
+		firstHalfPrivacy.forEach((range,level) -> Assert.assertEquals(constraint1.getPrivacyLevel(),level));
+		Map<DataRange, PrivacyLevel> secondHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0,columns1}, new long[]{rows,columns1+columns2-1}));
+		secondHalfPrivacy.forEach((range,level) -> Assert.assertEquals(constraint2.getPrivacyLevel(),level));
+	}
+
+	@Test
+	public void generalOnlyListAppendPrivate1Test(){
+		generalOnlyListAppendTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyListAppendPrivateAggregation1Test(){
+		generalOnlyCBindTest(new PrivacyConstraint(PrivacyLevel.PrivateAggregation), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyListAppendNoneTest(){
+		generalOnlyListAppendTest(new PrivacyConstraint(), new PrivacyConstraint());
+	}
+
+	@Test
+	public void generalOnlyListAppendPrivate2Test(){
+		generalOnlyListAppendTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.Private));
+	}
+
+	@Test
+	public void generalOnlyListAppendPrivateAggregation2Test(){
+		generalOnlyListAppendTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.PrivateAggregation));
+	}
+
+	@Test
+	public void generalOnlyListAppendPrivatePrivateTest(){
+		generalOnlyListAppendTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.Private));
+	}
+
+	@Test
+	public void generalOnlyListAppendPrivatePrivateAggregationTest(){
+		generalOnlyListAppendTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.PrivateAggregation));
+	}
+
+	private void generalOnlyListAppendTest(PrivacyConstraint constraint1, PrivacyConstraint constraint2){
+		int length1 = 6;
+		List<Data> dataList1 = Arrays.asList(new Data[length1]);
+		ListObject input1 = new ListObject(dataList1);
+		int length2 = 11;
+		List<Data> dataList2 = Arrays.asList(new Data[length2]);
+		ListObject input2 = new ListObject(dataList2);
+		Propagator propagator = new ListAppendPropagator(input1, constraint1, input2, constraint2);
+		PrivacyConstraint mergedConstraint = propagator.propagate();
+		Map<DataRange, PrivacyLevel> firstHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0}, new long[]{length1-1})
+		);
+		firstHalfPrivacy.forEach((range,level) -> Assert.assertEquals(constraint1.getPrivacyLevel(),level));
+		Map<DataRange, PrivacyLevel> secondHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[length1], new long[]{length1+length2-1})
+		);
+		secondHalfPrivacy.forEach((range,level) -> Assert.assertEquals(constraint2.getPrivacyLevel(),level));
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendPrivate1Test(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(),
+			PrivacyLevel.Private, PrivacyLevel.Private);
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendPrivateAggregation1Test(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(PrivacyLevel.PrivateAggregation), new PrivacyConstraint(),
+			PrivacyLevel.PrivateAggregation, PrivacyLevel.PrivateAggregation);
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendNoneTest(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(), new PrivacyConstraint(),
+			PrivacyLevel.None, PrivacyLevel.None);
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendPrivate2Test(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.Private),
+			PrivacyLevel.Private, PrivacyLevel.Private);
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendPrivateAggregation2Test(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(), new PrivacyConstraint(PrivacyLevel.PrivateAggregation),
+			PrivacyLevel.PrivateAggregation, PrivacyLevel.PrivateAggregation);
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendPrivatePrivateTest(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.Private),
+			PrivacyLevel.Private, PrivacyLevel.Private);
+	}
+
+	@Test
+	public void generalOnlyListRemoveAppendPrivatePrivateAggregationTest(){
+		generalOnlyListRemoveAppendTest(new PrivacyConstraint(PrivacyLevel.Private), new PrivacyConstraint(PrivacyLevel.PrivateAggregation),
+			PrivacyLevel.Private, PrivacyLevel.Private);
+	}
+
+	private void generalOnlyListRemoveAppendTest(
+		PrivacyConstraint constraint1, PrivacyConstraint constraint2, PrivacyLevel expected1, PrivacyLevel expected2){
+		int dataLength = 9;
+		List<Data> dataList = new ArrayList<>();
+		for ( int i = 0; i < dataLength; i++){
+			dataList.add(new DoubleObject(i));
+		}
+		ListObject inputList = new ListObject(dataList);
+
+		int removePositionInt = 5;
+		ScalarObject removePosition = new IntObject(removePositionInt);
+
+		PropagatorMultiReturn propagator = new ListRemovePropagator(inputList, constraint1, removePosition, constraint2);
+		PrivacyConstraint[] mergedConstraints = propagator.propagate();
+
+		Assert.assertEquals(expected1, mergedConstraints[0].getPrivacyLevel());
+		Assert.assertEquals(expected2, mergedConstraints[1].getPrivacyLevel());
+		Assert.assertFalse("The first output constraint should have no fine-grained constraints", mergedConstraints[0].hasFineGrainedConstraints());
+		Assert.assertFalse("The second output constraint should have no fine-grained constraints", mergedConstraints[1].hasFineGrainedConstraints());
+	}
+
+	@Test
+	public void finegrainedRBindPrivate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedRBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedRBindPrivateAndPrivateAggregate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedRBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedRBindPrivate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		finegrainedRBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedRBindPrivateAndPrivateAggregate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		finegrainedRBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedRBindPrivate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		finegrainedRBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedRBindPrivateAndPrivateAggregate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{2,0}), PrivacyLevel.PrivateAggregation);
+		finegrainedRBindTest(constraint1, constraint2);
+	}
+
+	private void finegrainedRBindTest(PrivacyConstraint constraint1, PrivacyConstraint constraint2){
+		int columns = 2;
+		int rows1 = 4;
+		int rows2 = 3;
+		MatrixBlock inputMatrix1 = new MatrixBlock(rows1,columns,3);
+		MatrixBlock inputMatrix2 = new MatrixBlock(rows2,columns,4);
+		AppendPropagator propagator = new RBindPropagator(inputMatrix1, constraint1, inputMatrix2, constraint2);
+		PrivacyConstraint mergedConstraint = propagator.propagate();
+		Assert.assertEquals(mergedConstraint.getPrivacyLevel(), PrivacyLevel.None);
+		Map<DataRange, PrivacyLevel> firstHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0,0}, new long[]{rows1-1,columns-1}));
+		constraint1.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+			constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 1",
+				firstHalfPrivacy.containsValue(constraint.getValue()))
+		);
+		Map<DataRange, PrivacyLevel> secondHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{rows1,0}, new long[]{rows1+rows2-1,columns-1}));
+		constraint2.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+			constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 2",
+				secondHalfPrivacy.containsValue(constraint.getValue()))
+		);
+	}
+
+	@Test
+	public void finegrainedCBindPrivate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedCBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedCBindPrivateAndPrivateAggregate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedCBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedCBindPrivate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		finegrainedCBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedCBindPrivateAndPrivateAggregate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		finegrainedCBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedCBindPrivate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		finegrainedCBindTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedCBindPrivateAndPrivateAggregate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{2,0}), PrivacyLevel.PrivateAggregation);
+		finegrainedCBindTest(constraint1, constraint2);
+	}
+
+	private void finegrainedCBindTest(PrivacyConstraint constraint1, PrivacyConstraint constraint2){
+		int rows = 6;
+		int columns1 = 4;
+		int columns2 = 3;
+		MatrixBlock inputMatrix1 = new MatrixBlock(rows,columns1,3);
+		MatrixBlock inputMatrix2 = new MatrixBlock(rows,columns2,4);
+		AppendPropagator propagator = new CBindPropagator(inputMatrix1, constraint1, inputMatrix2, constraint2);
+		PrivacyConstraint mergedConstraint = propagator.propagate();
+		Assert.assertEquals(mergedConstraint.getPrivacyLevel(), PrivacyLevel.None);
+		Map<DataRange, PrivacyLevel> firstHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0,0}, new long[]{rows-1,columns1-1}));
+		constraint1.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+			constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 1",
+				firstHalfPrivacy.containsValue(constraint.getValue()))
+		);
+		Map<DataRange, PrivacyLevel> secondHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0,columns1}, new long[]{rows,columns1+columns2-1}));
+		constraint2.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+			constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 2",
+				secondHalfPrivacy.containsValue(constraint.getValue()))
+		);
+	}
+
+	@Test
+	public void finegrainedListAppendPrivate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListAppendTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedListAppendPrivateAndPrivateAggregate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{3},new long[]{5}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListAppendTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedListAppendPrivate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		finegrainedListAppendTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedListAppendPrivateAndPrivateAggregate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{3},new long[]{5}), PrivacyLevel.PrivateAggregation);
+		finegrainedListAppendTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedListAppendPrivate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{4}), PrivacyLevel.Private);
+		finegrainedListAppendTest(constraint1, constraint2);
+	}
+
+	@Test
+	public void finegrainedListAppendPrivateAndPrivateAggregate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{0},new long[]{0}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2},new long[]{3}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{0},new long[]{1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{3},new long[]{5}), PrivacyLevel.PrivateAggregation);
+		finegrainedListAppendTest(constraint1, constraint2);
+	}
+
+	private void finegrainedListAppendTest(PrivacyConstraint constraint1, PrivacyConstraint constraint2){
+		int length1 = 6;
+		List<Data> dataList1 = Arrays.asList(new Data[length1]);
+		ListObject input1 = new ListObject(dataList1);
+		int length2 = 11;
+		List<Data> dataList2 = Arrays.asList(new Data[length2]);
+		ListObject input2 = new ListObject(dataList2);
+		Propagator propagator = new ListAppendPropagator(input1, constraint1, input2, constraint2);
+		PrivacyConstraint mergedConstraint = propagator.propagate();
+		Assert.assertEquals(mergedConstraint.getPrivacyLevel(), PrivacyLevel.None);
+		Map<DataRange, PrivacyLevel> firstHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{0}, new long[]{length1-1})
+		);
+		constraint1.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+			constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 1",
+				firstHalfPrivacy.containsValue(constraint.getValue()))
+		);
+		Map<DataRange, PrivacyLevel> secondHalfPrivacy = mergedConstraint.getFineGrainedPrivacy().getPrivacyLevel(
+			new DataRange(new long[]{length1}, new long[]{length1+length2-1})
+		);
+		constraint2.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+			constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 2",
+				secondHalfPrivacy.containsValue(constraint.getValue()))
+		);
+	}
+
+	@Test
+	public void testFunction(){
+		int dataLength = 9;
+		List<Data> dataList = new ArrayList<>();
+		for ( int i = 0; i < dataLength; i++){
+			dataList.add(new DoubleObject(i));
+		}
+		ListObject l = new ListObject(dataList);
+		ListObject lCopy = l.copy();
+		int position = 4;
+		ListObject output = l.remove(position);
+		Assert.assertEquals(lCopy.getData(position), output.getData().get(0));
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendNone1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.None);
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendPrivate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{6}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.Private);
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendPrivate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{6}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.Private);
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendPrivate3(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{6}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.Private);
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendPrivate4(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{4},new long[]{4}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.Private, true);
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendPrivateAndPrivateAggregate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1},new long[]{2}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{3},new long[]{5}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.PrivateAggregation);
+	}
+
+	@Test
+	public void finegrainedListRemoveAppendPrivateAggregate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{5},new long[]{8}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		finegrainedListRemoveAppendTest(constraint1, constraint2, PrivacyLevel.PrivateAggregation);
+	}
+
+	private void finegrainedListRemoveAppendTest(
+		PrivacyConstraint constraint1, PrivacyConstraint constraint2, PrivacyLevel expectedOutput2){
+		finegrainedListRemoveAppendTest(constraint1, constraint2, expectedOutput2, false);
+	}
+
+	private void finegrainedListRemoveAppendTest(
+		PrivacyConstraint constraint1, PrivacyConstraint constraint2, PrivacyLevel expectedOutput2, boolean singleElementPrivacy){
+		int dataLength = 9;
+		List<Data> dataList = new ArrayList<>();
+		for ( int i = 0; i < dataLength; i++){
+			dataList.add(new DoubleObject(i));
+		}
+		ListObject inputList = new ListObject(dataList);
+		int removePositionInt = 5;
+		ScalarObject removePosition = new IntObject(removePositionInt);
+		PropagatorMultiReturn propagator = new ListRemovePropagator(inputList, constraint1, removePosition, constraint2);
+		PrivacyConstraint[] mergedConstraints = propagator.propagate();
+
+		if ( !singleElementPrivacy ){
+			Map<DataRange, PrivacyLevel> outputPrivacy = mergedConstraints[0].getFineGrainedPrivacy().getPrivacyLevel(
+				new DataRange(new long[]{0}, new long[]{dataLength-1})
+			);
+			constraint1.getFineGrainedPrivacy().getAllConstraintsList().forEach(
+				constraint -> Assert.assertTrue("Merged constraint should contain same privacy levels as input 1",
+					outputPrivacy.containsValue(constraint.getValue()))
+			);
+		}
+
+		Assert.assertEquals(expectedOutput2, mergedConstraints[1].getPrivacyLevel());
+		Assert.assertFalse(mergedConstraints[1].hasFineGrainedConstraints());
+	}
+
+	@Test
+	public void integrationRBindTestNoneNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint(PrivacyLevel.None);
+		integrationRBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationRBindTestPrivateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.Private);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0}, new long[]{19,9}), PrivacyLevel.Private);
+		integrationRBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationRBindTestPrivateAggregateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0}, new long[]{19,9}), PrivacyLevel.PrivateAggregation);
+		integrationRBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationRBindTestNonePrivateAggregate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{20,0}, new long[]{49, 9}), PrivacyLevel.PrivateAggregation);
+		integrationRBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationRBindTestNonePrivate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.Private);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{20,0}, new long[]{49, 9}), PrivacyLevel.Private);
+		integrationRBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationFinegrainedRBindPrivate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		integrationRBindTest(constraint1, constraint2, constraint1);
+	}
+
+	@Test
+	public void integrationFinegrainedRBindPrivateAndPrivateAggregate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		integrationRBindTest(constraint1, constraint2, constraint1);
+	}
+
+	@Test
+	public void integrationFinegrainedRBindPrivate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint pcExcepted = new PrivacyConstraint();
+		pcExcepted.getFineGrainedPrivacy().put(new DataRange(new long[]{21,0}, new long[]{21,1}), PrivacyLevel.Private);
+		integrationRBindTest(constraint1, constraint2, pcExcepted);
+	}
+
+	@Test
+	public void integrationFinegrainedRBindPrivateAndPrivateAggregate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pcExcepted = new PrivacyConstraint();
+		pcExcepted.getFineGrainedPrivacy().put(new DataRange(new long[]{21,0},new long[]{21,1}), PrivacyLevel.Private);
+		pcExcepted.getFineGrainedPrivacy().put(new DataRange(new long[]{22,0}, new long[]{23,1}), PrivacyLevel.PrivateAggregation);
+		integrationRBindTest(constraint1, constraint2, pcExcepted);
+	}
+
+	@Test
+	public void integrationFinegrainedRBindPrivate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{21,0},new long[]{21,1}), PrivacyLevel.Private);
+		integrationRBindTest(constraint1, constraint2, pcExpected);
+	}
+
+	@Test
+	public void integrationFinegrainedRBindPrivateAndPrivateAggregate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{2,0}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{20,0},new long[]{20,1}), PrivacyLevel.Private);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0}, new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{21,0}, new long[]{22,0}), PrivacyLevel.PrivateAggregation);
+		integrationRBindTest(constraint1, constraint2, pcExpected);
+	}
+
+	private void integrationRBindTest(PrivacyConstraint privacyConstraint1, PrivacyConstraint privacyConstraint2,
+		PrivacyConstraint expectedOutput){
+		TestConfiguration config = getAndLoadTestConfiguration(TEST_NAME_RBIND);
+		fullDMLScriptName = SCRIPT_DIR + TEST_DIR + config.getTestScript() + ".dml";
+
+		int rows1 = 20;
+		int rows2 = 30;
+		int cols = 10;
+		double[][] A = getRandomMatrix(rows1, cols, -10, 10, 0.5, 1);
+		double[][] B = getRandomMatrix(rows2, cols, -10, 10, 0.5, 1);
+		writeInputMatrixWithMTD("A", A, false, new MatrixCharacteristics(rows1, cols),  privacyConstraint1);
+		writeInputMatrixWithMTD("B", B, false, new MatrixCharacteristics(rows2, cols),  privacyConstraint2);
+
+		programArgs = new String[]{"-nvargs", "A=" + input("A"), "B=" + input("B"), "C=" + output("C")};
+		runTest(true,false,null,-1);
+
+		PrivacyConstraint outputConstraint = getPrivacyConstraintFromMetaData("C");
+		Assert.assertEquals(expectedOutput, outputConstraint);
+	}
+
+	@Test
+	public void integrationCBindTestNoneNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint(PrivacyLevel.None);
+		integrationCBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationCBindTestPrivateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.Private);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0}, new long[]{9,19}), PrivacyLevel.Private);
+		integrationCBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationCBindTestPrivateAggregateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0}, new long[]{9,19}), PrivacyLevel.PrivateAggregation);
+		integrationCBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationCBindTestNonePrivateAggregate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,20}, new long[]{9, 49}), PrivacyLevel.PrivateAggregation);
+		integrationCBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationCBindTestNonePrivate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.Private);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,20}, new long[]{9, 49}), PrivacyLevel.Private);
+		integrationCBindTest(pc1, pc2, pcExpected);
+	}
+
+	@Test
+	public void integrationFinegrainedCBindPrivate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		integrationCBindTest(constraint1, constraint2, constraint1);
+	}
+
+	@Test
+	public void integrationFinegrainedCBindPrivateAndPrivateAggregate1(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		integrationCBindTest(constraint1, constraint2, constraint1);
+	}
+
+	@Test
+	public void integrationFinegrainedCBindPrivate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint pcExcepted = new PrivacyConstraint();
+		pcExcepted.getFineGrainedPrivacy().put(new DataRange(new long[]{1,20}, new long[]{1,21}), PrivacyLevel.Private);
+		integrationCBindTest(constraint1, constraint2, pcExcepted);
+	}
+
+	@Test
+	public void integrationFinegrainedCBindPrivateAndPrivateAggregate2(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pcExcepted = new PrivacyConstraint();
+		pcExcepted.getFineGrainedPrivacy().put(new DataRange(new long[]{1,20},new long[]{1,21}), PrivacyLevel.Private);
+		pcExcepted.getFineGrainedPrivacy().put(new DataRange(new long[]{2,20}, new long[]{3,21}), PrivacyLevel.PrivateAggregation);
+		integrationCBindTest(constraint1, constraint2, pcExcepted);
+	}
+
+	@Test
+	public void integrationFinegrainedCBindPrivate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{1,1}), PrivacyLevel.Private);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{1,20},new long[]{1,21}), PrivacyLevel.Private);
+		integrationCBindTest(constraint1, constraint2, pcExpected);
+	}
+
+	@Test
+	public void integrationFinegrainedCBindPrivateAndPrivateAggregate12(){
+		PrivacyConstraint constraint1 = new PrivacyConstraint();
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint1.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0},new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint constraint2 = new PrivacyConstraint();
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		constraint2.getFineGrainedPrivacy().put(new DataRange(new long[]{1,0},new long[]{2,0}), PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,0},new long[]{0,1}), PrivacyLevel.Private);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0,20},new long[]{0,21}), PrivacyLevel.Private);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{2,0}, new long[]{3,1}), PrivacyLevel.PrivateAggregation);
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{1,20}, new long[]{2,20}), PrivacyLevel.PrivateAggregation);
+		integrationCBindTest(constraint1, constraint2, pcExpected);
+	}
+
+	private void integrationCBindTest(PrivacyConstraint privacyConstraint1, PrivacyConstraint privacyConstraint2,
+		PrivacyConstraint expectedOutput){
+		TestConfiguration config = getAndLoadTestConfiguration(TEST_NAME_CBIND);
+		fullDMLScriptName = SCRIPT_DIR + TEST_DIR + config.getTestScript() + ".dml";
+
+		int cols1 = 20;
+		int cols2 = 30;
+		int rows = 10;
+		double[][] A = getRandomMatrix(rows, cols1, -10, 10, 0.5, 1);
+		double[][] B = getRandomMatrix(rows, cols2, -10, 10, 0.5, 1);
+		writeInputMatrixWithMTD("A", A, false, new MatrixCharacteristics(rows, cols1),  privacyConstraint1);
+		writeInputMatrixWithMTD("B", B, false, new MatrixCharacteristics(rows, cols2),  privacyConstraint2);
+
+		programArgs = new String[]{"-nvargs", "A=" + input("A"), "B=" + input("B"), "C=" + output("C")};
+		runTest(true,false,null,-1);
+
+		PrivacyConstraint outputConstraint = getPrivacyConstraintFromMetaData("C");
+		Assert.assertEquals(expectedOutput, outputConstraint);
+	}
+
+	@Test
+	public void integrationStringAppendTestNoneNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		integrationStringAppendTest(pc1, pc2, pc1);
+	}
+
+	@Test
+	public void integrationStringAppendTestPrivateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.Private);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		integrationStringAppendTest(pc1, pc2, pc1);
+	}
+
+	@Test
+	public void integrationStringAppendTestPrivateAggregateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		integrationStringAppendTest(pc1, pc2, pc1);
+	}
+
+	@Test
+	public void integrationStringAppendTestNonePrivateAggregate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		integrationStringAppendTest(pc1, pc2, pc2);
+	}
+
+	@Test
+	public void integrationStringAppendTestNonePrivate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.Private);
+		integrationStringAppendTest(pc1, pc2, pc2);
+	}
+
+	private void integrationStringAppendTest(PrivacyConstraint privacyConstraint1, PrivacyConstraint privacyConstraint2,
+		PrivacyConstraint expectedOutput){
+		TestConfiguration config = getAndLoadTestConfiguration(TEST_NAME_STRING);
+		fullDMLScriptName = SCRIPT_DIR + TEST_DIR + config.getTestScript() + ".dml";
+
+		int cols = 1;
+		int rows = 1;
+		double[][] A = getRandomMatrix(rows, cols, -10, 10, 0.5, 1);
+		double[][] B = getRandomMatrix(rows, cols, -10, 10, 0.5, 1);
+		writeInputMatrixWithMTD("A", A, false, new MatrixCharacteristics(rows, cols),  privacyConstraint1);
+		writeInputMatrixWithMTD("B", B, false, new MatrixCharacteristics(rows, cols),  privacyConstraint2);
+
+		programArgs = new String[]{"-nvargs", "A=" + input("A"), "B=" + input("B"), "C=" + output("C")};
+		runTest(true,false,null,-1);
+
+		PrivacyConstraint outputConstraint = getPrivacyConstraintFromMetaData("C");
+		Assert.assertEquals(expectedOutput, outputConstraint);
+	}
+
+	@Ignore
+	@Test
+	public void integrationListAppendTestNoneNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		integrationListAppendTest(pc1, pc2, pc1);
+	}
+
+	@Ignore
+	@Test
+	public void integrationListAppendTestPrivateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.Private);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pcExpected = new PrivacyConstraint();
+		pcExpected.getFineGrainedPrivacy().put(new DataRange(new long[]{0}, new long[]{0}), PrivacyLevel.Private);
+		integrationListAppendTest(pc1, pc2, pcExpected);
+	}
+
+	@Ignore
+	@Test
+	public void integrationListAppendTestPrivateAggregateNone(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.None);
+		integrationListAppendTest(pc1, pc2, pc1);
+	}
+
+	@Ignore
+	@Test
+	public void integrationListAppendTestNonePrivateAggregate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
+		integrationListAppendTest(pc1, pc2, pc2);
+	}
+
+	@Ignore
+	@Test
+	public void integrationListAppendTestNonePrivate(){
+		PrivacyConstraint pc1 = new PrivacyConstraint(PrivacyLevel.None);
+		PrivacyConstraint pc2 = new PrivacyConstraint(PrivacyLevel.Private);
+		integrationListAppendTest(pc1, pc2, pc2);
+	}
+
+	private void integrationListAppendTest(PrivacyConstraint privacyConstraint1, PrivacyConstraint privacyConstraint2,
+		PrivacyConstraint expectedOutput){
+		TestConfiguration config = getAndLoadTestConfiguration(TEST_NAME_LIST);
+		fullDMLScriptName = SCRIPT_DIR + TEST_DIR + config.getTestScript() + ".dml";
+
+		int cols = 1;
+		int rows = 5;
+		double[][] A = getRandomMatrix(rows, cols, -10, 10, 0.5, 1);
+		double[][] B = getRandomMatrix(rows, cols, -10, 10, 0.5, 1);
+		writeInputMatrixWithMTD("A", A, false, new MatrixCharacteristics(rows, cols),  privacyConstraint1);
+		writeInputMatrixWithMTD("B", B, false, new MatrixCharacteristics(rows, cols),  privacyConstraint2);
+
+		programArgs = new String[]{"-nvargs", "A=" + input("A"), "B=" + input("B"), "C=" + output("C")};
+		runTest(true,false,null,-1);
+
+		PrivacyConstraint outputConstraint = getPrivacyConstraintFromMetaData("C");
+		Assert.assertEquals(expectedOutput, outputConstraint);
+	}
+}
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/CorePropagatorTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/propagation/CorePropagatorTest.java
similarity index 98%
rename from src/test/java/org/apache/sysds/test/functions/privacy/CorePropagatorTest.java
rename to src/test/java/org/apache/sysds/test/functions/privacy/propagation/CorePropagatorTest.java
index a359a7d..15a625e 100644
--- a/src/test/java/org/apache/sysds/test/functions/privacy/CorePropagatorTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/propagation/CorePropagatorTest.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.sysds.test.functions.privacy;
+package org.apache.sysds.test.functions.privacy.propagation;
 
 import org.apache.sysds.test.AutomatedTestBase;
 import org.junit.Test;
diff --git a/src/test/java/org/apache/sysds/test/functions/privacy/PrivacyPropagatorTest.java b/src/test/java/org/apache/sysds/test/functions/privacy/propagation/MatrixMultiplicationPropagatorTest.java
similarity index 88%
rename from src/test/java/org/apache/sysds/test/functions/privacy/PrivacyPropagatorTest.java
rename to src/test/java/org/apache/sysds/test/functions/privacy/propagation/MatrixMultiplicationPropagatorTest.java
index 0092247..e4b3631 100644
--- a/src/test/java/org/apache/sysds/test/functions/privacy/PrivacyPropagatorTest.java
+++ b/src/test/java/org/apache/sysds/test/functions/privacy/propagation/MatrixMultiplicationPropagatorTest.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.sysds.test.functions.privacy;
+package org.apache.sysds.test.functions.privacy.propagation;
 
 import java.util.List;
 import java.util.Map;
@@ -35,7 +35,7 @@ import org.junit.Test;
 
 import static org.junit.Assert.*;
 
-public class PrivacyPropagatorTest extends AutomatedTestBase {
+public class MatrixMultiplicationPropagatorTest extends AutomatedTestBase {
 
 	@Override
 	public void setUp() {
@@ -44,7 +44,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained(){
+	public void mMPTestPrivateGeneralNoFineGrained(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
 		PrivacyConstraint constraint2 = new PrivacyConstraint();
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
@@ -52,7 +52,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained2(){
+	public void mMPTestPrivateGeneralNoFineGrained2(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint();
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.Private);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
@@ -60,7 +60,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrainedNaive(){
+	public void mMPTestPrivateGeneralNoFineGrainedNaive(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
 		PrivacyConstraint constraint2 = new PrivacyConstraint();
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
@@ -68,7 +68,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained2Naive(){
+	public void mMPTestPrivateGeneralNoFineGrained2Naive(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint();
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.Private);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
@@ -76,7 +76,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained3(){
+	public void mMPTestPrivateGeneralNoFineGrained3(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
@@ -84,7 +84,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained3Naive(){
+	public void mMPTestPrivateGeneralNoFineGrained3Naive(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
@@ -92,7 +92,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained4(){
+	public void mMPTestPrivateGeneralNoFineGrained4(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.Private);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
@@ -100,7 +100,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained4Naive(){
+	public void mMPTestPrivateGeneralNoFineGrained4Naive(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.Private);
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.Private);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
@@ -108,7 +108,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained5(){
+	public void mMPTestPrivateGeneralNoFineGrained5(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.Private);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
@@ -116,7 +116,7 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNoFineGrained5Naive(){
+	public void mMPTestPrivateGeneralNoFineGrained5Naive(){
 		PrivacyConstraint constraint1 = new PrivacyConstraint(PrivacyLevel.PrivateAggregation);
 		PrivacyConstraint constraint2 = new PrivacyConstraint(PrivacyLevel.Private);
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
@@ -124,91 +124,91 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneral(){
+	public void mMPTestPrivateGeneral(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		mmPropagationPrivateGeneralized(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneral2() {
+	public void mMPTestPrivateGeneral2() {
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		mmPropagationPrivateGeneralized(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralNaive(){
+	public void mMPTestPrivateGeneralNaive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		mmPropagationPrivateGeneralized(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneral2Naive() {
+	public void mMPTestPrivateGeneral2Naive() {
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		mmPropagationPrivateGeneralized(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneralPrivateFirstOptimized(){
+	public void mMPTestPrivateGeneralPrivateFirstOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		mmPropagationPrivateGeneralized(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateGeneral2PrivateFirstOptimized() {
+	public void mMPTestPrivateGeneral2PrivateFirstOptimized() {
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		mmPropagationPrivateGeneralized(PrivacyLevel.PrivateAggregation, propagator);
 	}
 	
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateFineGrained(){
+	public void mMPTestPrivateFineGrained(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		mmPropagationTestPrivateFineGrainedGeneralized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateFineGrainedNaive(){
+	public void mMPTestPrivateFineGrainedNaive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		mmPropagationTestPrivateFineGrainedGeneralized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateFineGrainedPrivateFirstOptimized(){
+	public void mMPTestPrivateFineGrainedPrivateFirstOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		mmPropagationTestPrivateFineGrainedGeneralized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateFineGrained2(){
+	public void mMPTestPrivateFineGrained2(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		mmPropagationTestPrivateFineGrained2Generalized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateFineGrained2Naive(){
+	public void mMPTestPrivateFineGrained2Naive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		mmPropagationTestPrivateFineGrained2Generalized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivateFineGrained2PrivateFirstOptimized(){
+	public void mMPTestPrivateFineGrained2PrivateFirstOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		mmPropagationTestPrivateFineGrained2Generalized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivatePrivateAggregationFineGrained(){
+	public void mMPTestPrivatePrivateAggregationFineGrained(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		mmPropagationTestPrivatePrivateAggregationFineGrainedGeneralized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivatePrivateAggregationFineGrainedNaive(){
+	public void mMPTestPrivatePrivateAggregationFineGrainedNaive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		mmPropagationTestPrivatePrivateAggregationFineGrainedGeneralized(propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestPrivatePrivateAggregationFineGrainedPrivateFirstOptimized(){
+	public void mMPTestPrivatePrivateAggregationFineGrainedPrivateFirstOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		mmPropagationTestPrivatePrivateAggregationFineGrainedGeneralized(propagator);
 	}
@@ -277,109 +277,109 @@ public class PrivacyPropagatorTest extends AutomatedTestBase {
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAgg(){
+	public void mMPTestNonAgg(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		NonAggGeneralizedTest(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivate(){
+	public void mMPTestNonAggPrivate(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		NonAggGeneralizedTest(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggNaive(){
+	public void mMPTestNonAggNaive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		NonAggGeneralizedTest(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivateNaive(){
+	public void mMPTestNonAggPrivateNaive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		NonAggGeneralizedTest(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivateOptimized(){
+	public void mMPTestNonAggPrivateOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		NonAggGeneralizedTest(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivatePrivateOptimized(){
+	public void mMPTestNonAggPrivatePrivateOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		NonAggGeneralizedTest(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAgg2(){
+	public void mMPTestNonAgg2(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		NonAggGeneralizedColTest(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivate2(){
+	public void mMPTestNonAggPrivate2(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		NonAggGeneralizedColTest(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAgg2Naive(){
+	public void mMPTestNonAgg2Naive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		NonAggGeneralizedColTest(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivate2Naive(){
+	public void mMPTestNonAggPrivate2Naive(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		NonAggGeneralizedColTest(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAgg2PrivateFirstOptimized(){
+	public void mMPTestNonAgg2PrivateFirstOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		NonAggGeneralizedColTest(PrivacyLevel.PrivateAggregation, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggPrivate2PrivateFirstOptimized(){
+	public void mMPTestNonAggPrivate2PrivateFirstOptimized(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		NonAggGeneralizedColTest(PrivacyLevel.Private, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggRowColNA(){
+	public void mMPTestNonAggRowColNA(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		NonAggGeneralizedRowColTest(PrivacyLevel.PrivateAggregation, true, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggRowColNAA(){
+	public void mMPTestNonAggRowColNAA(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirst();
 		NonAggGeneralizedRowColTest(PrivacyLevel.PrivateAggregation, false, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggRowColNaiveNA(){
+	public void mMPTestNonAggRowColNaiveNA(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		NonAggGeneralizedRowColTest(PrivacyLevel.PrivateAggregation, true, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggRowColNaiveNAA(){
+	public void mMPTestNonAggRowColNaiveNAA(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorNaive();
 		NonAggGeneralizedRowColTest(PrivacyLevel.PrivateAggregation, false, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggRowColPrivateFirstOptimizedNA(){
+	public void mMPTestNonAggRowColPrivateFirstOptimizedNA(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		NonAggGeneralizedRowColTest(PrivacyLevel.PrivateAggregation, true, propagator);
 	}
 
 	@Test
-	public void matrixMultiplicationPropagationTestNonAggRowColPrivateFirstOptimizedNAA(){
+	public void mMPTestNonAggRowColPrivateFirstOptimizedNAA(){
 		MatrixMultiplicationPropagator propagator = new MatrixMultiplicationPropagatorPrivateFirstOptimized();
 		NonAggGeneralizedRowColTest(PrivacyLevel.PrivateAggregation, false, propagator);
 	}
diff --git a/src/test/scripts/functions/privacy/CBindTest.dml b/src/test/scripts/functions/privacy/CBindTest.dml
new file mode 100644
index 0000000..e38dfcb
--- /dev/null
+++ b/src/test/scripts/functions/privacy/CBindTest.dml
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+A = read($A)
+B = read($B)
+C = cbind(A,B)
+write(C, $C)
\ No newline at end of file
diff --git a/src/test/scripts/functions/privacy/ListAppendTest.dml b/src/test/scripts/functions/privacy/ListAppendTest.dml
new file mode 100644
index 0000000..0f097c2
--- /dev/null
+++ b/src/test/scripts/functions/privacy/ListAppendTest.dml
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+A = read($A)
+B = read($B)
+C = cbind(list(A),list(B))
+write(C, $C)
\ No newline at end of file
diff --git a/src/test/scripts/functions/privacy/RBindTest.dml b/src/test/scripts/functions/privacy/RBindTest.dml
new file mode 100644
index 0000000..ad37b29
--- /dev/null
+++ b/src/test/scripts/functions/privacy/RBindTest.dml
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+A = read($A)
+B = read($B)
+C = rbind(A,B)
+write(C, $C)
\ No newline at end of file
diff --git a/src/test/scripts/functions/privacy/StringAppendTest.dml b/src/test/scripts/functions/privacy/StringAppendTest.dml
new file mode 100644
index 0000000..80852cc
--- /dev/null
+++ b/src/test/scripts/functions/privacy/StringAppendTest.dml
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------
+#
+# 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.
+#
+#-------------------------------------------------------------
+
+A = read($A)
+B = read($B)
+C = cbind("A: " + as.scalar(A), "B: " + as.scalar(B))
+write(C, $C)
\ No newline at end of file