diff --git a/libwccl/CMakeLists.txt b/libwccl/CMakeLists.txt
index 3027aeee0356e9bfac135891afd256ce5b307159..ccf8411efe36d703c682860466fce78732a3b6e3 100644
--- a/libwccl/CMakeLists.txt
+++ b/libwccl/CMakeLists.txt
@@ -16,6 +16,7 @@ set(LIBS ${LIBS} ${Boost_LIBRARIES})
 SET(libwccl_STAT_SRC
 	exception.cpp
 	main.cpp
+	ops/and.cpp
 	ops/logicalpredicate.cpp
 	ops/predicate.cpp
 	sentencecontext.cpp
diff --git a/libwccl/ops/and.cpp b/libwccl/ops/and.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..893eb6a2ee911046686e9657c9265b68edeeeac5
--- /dev/null
+++ b/libwccl/ops/and.cpp
@@ -0,0 +1,19 @@
+#include "and.h"
+
+namespace Wccl {
+
+And::BaseRetValPtr And::apply_internal(const SentenceContext &context) const
+{
+	foreach(boost::shared_ptr< Function<Bool> > expression, *expressions_) {
+		if(!(expression->apply(context)->get_value())) {
+			return Predicate::False->apply(context);
+		}
+	}
+	return Predicate::True->apply(context);
+}
+
+const std::string And::raw_operator_name() const {
+	return "and";
+}
+
+} /* end ns Wccl */
diff --git a/libwccl/ops/and.h b/libwccl/ops/and.h
new file mode 100644
index 0000000000000000000000000000000000000000..1f533d4a58bf2cf5cc5e1fd0fb917bfdd59249d3
--- /dev/null
+++ b/libwccl/ops/and.h
@@ -0,0 +1,32 @@
+#ifndef AND_H
+#define AND_H
+
+#include <boost/foreach.hpp>
+#define foreach         BOOST_FOREACH
+
+#include <libwccl/ops/logicalpredicate.h>
+
+namespace Wccl {
+
+class And : public LogicalPredicate
+{
+public:
+	And(const boost::shared_ptr<BoolFunctionPtrVector>& expressions)
+		: LogicalPredicate(expressions)
+	{
+	}
+
+protected :
+	typedef FunctionBase::BaseRetValPtr BaseRetValPtr ;
+
+	/**
+	 * "And" predicate returns True only when all expressions are true,
+	 * otherwise it returns False
+	 */
+	virtual BaseRetValPtr apply_internal(const SentenceContext&) const;
+
+	virtual const std::string raw_operator_name() const;
+};
+
+} /* end ns Wccl */
+#endif // AND_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 2a538ca4e24e79fb799deb0d6702d6540b044e39..167604e830421a6612c5260df0de5c9cc9739020 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -7,6 +7,7 @@ add_definitions(-DLIBWCCL_TEST_DATA_DIR="${PROJECT_SOURCE_DIR}/")
 add_executable(tests
 	constant_tests.cpp
 	context.cpp
+	logicalpredicates.cpp
 	main.cpp
 	position.cpp
 	values.cpp
diff --git a/tests/logicalpredicates.cpp b/tests/logicalpredicates.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..31ef9fb5ad973a86c2d4f0955398bb730b6211ab
--- /dev/null
+++ b/tests/logicalpredicates.cpp
@@ -0,0 +1,120 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <libcorpus2/sentence.h>
+
+#include <libwccl/ops/constant.h>
+#include <libwccl/ops/logicalpredicate.h>
+#include <libwccl/ops/and.h>
+#include <libwccl/values/bool.h>
+#include <libwccl/sentencecontext.h>
+
+using namespace Wccl;
+
+BOOST_AUTO_TEST_SUITE(logical_predicates)
+
+struct PredFix
+{
+	PredFix()
+		: sc(boost::make_shared<Corpus2::Sentence>()),
+		  tagset(),
+		  true_value(true),
+		  false_value(false),
+		  true_constant(new Constant<Bool>(true_value)),
+		  false_constant(new Constant<Bool>(false_value))
+	{
+	}
+	SentenceContext sc;
+	Corpus2::Tagset tagset;
+
+	Bool true_value;
+	Bool false_value;
+	LogicalPredicate::BoolFunctionPtr true_constant;
+	LogicalPredicate::BoolFunctionPtr false_constant;
+};
+
+BOOST_FIXTURE_TEST_CASE(predicate_constants, PredFix)
+{
+	BOOST_CHECK_EQUAL(true, Predicate::True->apply(sc)->get_value());
+	BOOST_CHECK_EQUAL(false, Predicate::False->apply(sc)->get_value());
+}
+
+BOOST_FIXTURE_TEST_CASE(and_1arg, PredFix)
+{
+	boost::shared_ptr<And::BoolFunctionPtrVector> v(new And::BoolFunctionPtrVector());
+	v->push_back(true_constant);
+	And pred_and(v);
+	BOOST_CHECK_EQUAL(true, pred_and.apply(sc)->get_value());
+	v->clear();
+	v->push_back(false_constant);
+	BOOST_CHECK_EQUAL(false, pred_and.apply(sc)->get_value());
+}
+
+BOOST_FIXTURE_TEST_CASE(and_2arg, PredFix)
+{
+	for(int arg1 = 0; arg1 < 2; ++arg1) {
+		for(int arg2 = 0; arg2 < 2; ++arg2) {
+			boost::shared_ptr<And::BoolFunctionPtrVector> v(new And::BoolFunctionPtrVector());
+			v->push_back(arg1 != 0 ? true_constant : false_constant);
+			v->push_back(arg2 != 0 ? true_constant : false_constant);
+			And pred_and(v);
+			BOOST_CHECK_EQUAL((arg1 != 0) && (arg2 != 0), pred_and.apply(sc)->get_value());
+		}
+	}
+}
+
+BOOST_FIXTURE_TEST_CASE(and_3arg, PredFix)
+{
+	for(int arg1 = 0; arg1 < 2; ++arg1) {
+		for(int arg2 = 0; arg2 < 2; ++arg2) {
+			for(int arg3 = 0; arg3 < 2; ++arg3) {
+				boost::shared_ptr<And::BoolFunctionPtrVector> v(new And::BoolFunctionPtrVector());
+				v->push_back(arg1 != 0 ? true_constant : false_constant);
+				v->push_back(arg2 != 0 ? true_constant : false_constant);
+				v->push_back(arg3 != 0 ? true_constant : false_constant);
+				And pred_and(v);
+				BOOST_CHECK_EQUAL((arg1 != 0) && (arg2 != 0) && (arg3 != 0), pred_and.apply(sc)->get_value());
+			}
+		}
+	}
+}
+
+BOOST_FIXTURE_TEST_CASE(and_to_string, PredFix)
+{
+	boost::shared_ptr<And::BoolFunctionPtrVector> v(new And::BoolFunctionPtrVector());
+	v->push_back(true_constant);
+	boost::shared_ptr<Function<Bool> > pred_and(new And(v));
+	BOOST_CHECK_EQUAL("and(true)", pred_and->to_string(tagset));
+	v->push_back(false_constant);
+	BOOST_CHECK_EQUAL("and(true, false)", pred_and->to_string(tagset));
+	v->push_back(true_constant);
+	BOOST_CHECK_EQUAL("and(true, false, true)", pred_and->to_string(tagset));
+
+	boost::shared_ptr<And::BoolFunctionPtrVector> v2(new And::BoolFunctionPtrVector());
+	v2->push_back(false_constant);
+	v2->push_back(pred_and);
+	And another_and(v2);
+	BOOST_CHECK_EQUAL("and(false, and(true, false, true))", another_and.to_raw_string());
+	v2->push_back(false_constant);
+	BOOST_CHECK_EQUAL("and(false, and(true, false, true), false)", another_and.to_raw_string());
+}
+
+BOOST_FIXTURE_TEST_CASE(and_to_raw_string, PredFix)
+{
+	boost::shared_ptr<And::BoolFunctionPtrVector> v(new And::BoolFunctionPtrVector());
+	v->push_back(false_constant);
+	boost::shared_ptr<Function<Bool> > pred_and(new And(v));
+	BOOST_CHECK_EQUAL("and(false)", pred_and->to_raw_string());
+	v->push_back(true_constant);
+	BOOST_CHECK_EQUAL("and(false, true)", pred_and->to_raw_string());
+	v->push_back(true_constant);
+	BOOST_CHECK_EQUAL("and(false, true, true)", pred_and->to_raw_string());
+
+	boost::shared_ptr<And::BoolFunctionPtrVector> v2(new And::BoolFunctionPtrVector());
+	v2->push_back(true_constant);
+	v2->push_back(pred_and);
+	And another_and(v2);
+	BOOST_CHECK_EQUAL("and(true, and(false, true, true))", another_and.to_raw_string());
+}
+
+BOOST_AUTO_TEST_SUITE_END()