diff --git a/docs/Formula.md b/docs/Formula.md
new file mode 100644
index 0000000000000000000000000000000000000000..d731f5159bd748c10e2d7ffac72ad3c08b6f48ff
--- /dev/null
+++ b/docs/Formula.md
@@ -0,0 +1,140 @@
+# Formula syntax
+The formula is an expression with operators, operands and functions. Operands can be variables, constant values, or other expression optionally enclosed by parentheses.
+
+## Operands
+
+### Variables
+
+- Attributes names with or without fqdn (e.g. ```tango://host:port/name/of/dev/attr```, ```name/of/dev/attr```)
+- attribute properties ```.quality```, ```.alarm```, ```.normal``` so that
+  - ```name/of/dev/attr.quality``` returns the Tango quality (the integer value) of the attribute
+  - ```name/of/dev/attr.alarm``` returns true if the attribute ==UNACK or ==ACK
+  - ```name/of/dev/attr.normal``` returns true if the attribute ==NORM or ==RTNUN
+
+### Constants
+
+- Real numbers (e.g. ```name/of/dev/attr >= 35```, ```name/of/dev/attr < -23.5```)
+- Hexadecimal numbers (e.g. ```name/of/dev/attr != 0xaf```, ```name/of/dev/attr & 0x1A```)
+- Strings as any character between an opening and a closing ' (e.g. ```name/of/dev/status == 'The device is in ON state.'```)
+- Tango states enum labels (*ON, OFF, CLOSE, OPEN, INSERT, EXTRACT, MOVING, STANDBY, FAULT, INIT, RUNNING, ALARM, DISABLE, UNKNOWN*) (e.g. ```name/of/dev/state == FAULT```)
+- Tango quality enum labels (*ATTR_VALID, ATTR_INVALID, ATTR_WARNING, ATTR_ALARM, ATTR_CHANGING*) (e.g. ```name/of/dev/attr.quality == ATTR_ALARM```)
+- Alarm state enum labels (*NORM, UNACK, ACKED, RTNUN, SHLVD, DSUPR, OOSRV*) (e.g. ```name/of/dev/alarm_attr != NORM```)
+
+### Expressions
+
+- A combination of operands and operators enclosed by parentheses
+
+## Operators
+
+### Binary Math
+- Multiplication ```*```
+- Division ```/```
+- Addition ```+```
+- Subtraction ```-```
+### Binary Comparison
+- Equal ```==```
+- Not equal ```!=```
+- Greater than ```>```
+- Greater than or equal to  ```>=```
+- Less than ```<```
+- Less than or equal to  ```<=```
+### Binary Logical
+- Logical AND ```&&```
+- Logical OR ```||```
+### Binary Bitwise
+- Left shift ```<<```
+- Right shift ```>>```
+- Bitwise AND ```&```
+- Bitwise OR ```|```
+- Bitwise XOR ```^```
+### Unary Math
+- Minus ```-```
+### Unary Logical
+- Logical NOT ```!```
+
+### Binary operators order of precedence
+
+```
+*, /, +, -, <<, >>, <=, >=, >, <, ==, !=, &, |, ^, &&, ||
+```
+
+## Functions
+
+### Unary Functions
+- Absolute value of X ```abs(X)```
+- Sine of X ```sin(X)```
+- Cosine of X ```cos(X)```
+
+### Binary Functions
+- Minimum between two values X and Y ```min(X,Y)```
+- Maximum between two values X and Y ```max(X,Y)```
+- Power: X raised to the power of Y ```pow(X,Y)```
+
+### Ternary Functions
+- Conditional operator: if X then Y else Z ```X ? Y : Z```
+
+### Reduce Functions
+- Reduce OR: reduce array X applying logical OR to each element ```OR(X)```
+- Reduce AND: reduce array X applying logical AND to each element ```OR(X)```
+
+# Attributes types
+
+The following types of attribute are supported:
+
+```
+Scalar, Spectrum, Image
+```
+
+with data types:
+
+```
+DevBoolean, DevUChar, DevShort, DevUShort, DevLong, DevULong, DevLong64, DevULong64, DevFloat, DevDouble, DevString, DevState, DevEnum
+```
+
+```DevEncoded``` is not supported.
+
+The read part of every attribute is internally extracted in a vector of double with the ```extract_read``` method of the ```DeviceAttribute``` class. In this ways operations between attribute with different data types and sizes can be performed with the following constraints:
+- DevString attributes can only be compared with 'equal' or 'not equal' operators to DevString attributes or string constants
+- Binary operators can operate on arrays if both operands have the same size, or one of the two has size equal to one.
+
+# Operation on arrays
+
+## Indexes to access elements
+
+- A single element of a one-dimensional array attribute (Spectrum) can be extracted with a single index between square brackets (e.g. ```name/of/dev/attr[ind]```).
+- A single element of a two-dimensional array attribute (Image) can be extracted with two indexes between square brackets (e.g. ```name/of/dev/attr[ind_row][ind_column]```).
+- A one-dimensional array can be extracted from a two-dimensional array attribute (Image) with a single index between square brackets (e.g. ```name/of/dev/attr[ind_row]```).
+
+If any index exceeds actual dimensions of the array, the formula is evaluated to ERROR with an out of bounds exception.
+
+## Limitations
+
+- It is not possible to specify array constants (e.g. ```name/of/dev/attr > [val1,val2]```).
+- It is not possible to use indexes on expressions (e.g. ```(any_expression)[ind]```).
+
+## Unary operators and functions
+
+Unary operators and functions are applied to every element of the array
+
+## Binary operators and functions
+
+- If both operands have the same size, operators are applied element by element. Result is an array with the same size.
+- If one operand has size one, operators apply it to every element of the other operand. Result is an array with the same size.
+- Otherwise an exception is raised and the formula is evaluated to the *ERROR* state with the Reason, Descrption and Origin DevFailed fields properly filled.
+
+## Ternary Function
+- Conditional operator: if X then Y else Z. X is implicitly reduced with *OR* to have a boolean value, then Y or Z are evaluated depending on the result
+
+# Formula result
+Every formula produce a boolean result in the following way:
+1. each element of the array is tested as not equal to zero in order to have an array of booleans
+2. the array of boolean is reduced with OR (i.e. if at least one element of the array is TRUE, the result is TRUE) 
+
+# Errors
+
+If a formula cannot be evaluated, the corresponding alarm is set to the *ERROR* value with the Reason, Description and Origin DevFailed fields properly filled.
+Possible errors are:
+- Errors coming from the event system for one or more attributes involved in the formula
+- Errors coming from evaluation of array with different sizes
+- Errors coming from indexes out of bound while extracting elements from arrays
+- Unexpected errors while evaluating formulas
diff --git a/src/AlarmHandler.cpp b/src/AlarmHandler.cpp
index 274f4b5cd06127a060fbfbd9f8baf716b4079a2c..8b50b963bef78486307cf490100500ef302cbc0e 100644
--- a/src/AlarmHandler.cpp
+++ b/src/AlarmHandler.cpp
@@ -37,6 +37,7 @@
 #include <AlarmHandler.h>
 #include <AlarmHandlerClass.h>
 #include <ctype.h>		//for tolower
+#include <numeric>		//for std::accumulate
 
 #include "alarm-thread.h"
 #include "alarm_grammar.h"
@@ -2354,7 +2355,7 @@ void AlarmHandler::modify(Tango::DevString argin)
 	//4: load modified alarm
 	//------------------------------
 	load(argin);
-
+	usleep(150000);//wait some time before updating attributes with prepare_alarm_attr so that event are subscribed and first evaluation done
 	prepare_alarm_attr();
 	try
 	{
@@ -3859,9 +3860,12 @@ void AlarmHandler::do_alarm(bei_t& e)
 		}
 	}
 	if (found != events->v_event.end())
-	{	
+	{
 		found->value = e.value;
 		found->value_string = e.value_string;
+		found->read_size = e.read_size;
+		found->dim_x = e.dim_x;
+		found->dim_y = e.dim_y;
 		found->quality = e.quality;
 		//found->errors = e.errors;
 		found->ex_reason = e.ex_reason;
@@ -3983,7 +3987,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 			it->second.to_be_evaluated = false;
 			it->second.attr_values.erase(it->second.attr_values.size()-1);
 			it->second.attr_values += string("}");
-			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Evaluation of " << it->second.formula << "; result=" << res.value << " quality=" << res.quality << " valid=" << (int)res.valid << endl;
+			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": Evaluation of " << it->second.formula << "; result=" << print_vector(res.value) << " quality=" << res.quality << " valid=" << (int)res.valid << endl;
 			changed = alarms.update(tmpname, ts, res, it->second.attr_values, it->second.grp2str(), it->second.msg, it->second.formula); 		//update internal structure and log to db
 			changed = changed || (prev_error && res.valid);
 			DEBUG_STREAM << "AlarmHandler::"<<__func__<<": changed=" << (int)changed << " error=" << (int)it->second.error << endl;
@@ -4040,7 +4044,8 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 			}
 		} catch(std::out_of_range& ex)
 		{
-			changed = !prev_error;
+			events->veclock.readerOut(); //readerIn called in eval_expression
+			changed = true;//force update attributes in case of modify/load alarm with out_of_range exception
 			it->second.to_be_evaluated = true;
 			ostringstream o;
 			o << tmpname << ": in formula array index out of range!";
@@ -4051,7 +4056,7 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 				Tango::DevErrorList errors(1);
 				errors.length(1);
 				it->second.ex_reason = string("OUT_OF_RANGE");
-				it->second.ex_desc = ev_name + ": " + o.str();
+				it->second.ex_desc = o.str();
 				it->second.ex_origin = ev_name;
 				errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
 				errors[0].severity = Tango::ERR;
@@ -4061,6 +4066,13 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 				bool enabled=it->second.enabled;
 				bool shelved=it->second.shelved;
 				int silenced=it->second.silenced;
+				Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
+				it->second.error=true;
+				it->second.quality = Tango::ATTR_INVALID;
+				if(enabled && !(shelved && silenced >0))
+				{
+					*attr_value = _ERROR;
+				}
 				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
 				if(enabled && !(shelved && silenced >0))
 				{
@@ -4094,6 +4106,54 @@ bool AlarmHandler::do_alarm_eval(string alm_name, string ev_name, Tango::TimeVal
 				bool enabled=it->second.enabled;
 				bool shelved=it->second.shelved;
 				int silenced=it->second.silenced;
+				Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
+				it->second.error=true;
+				it->second.quality = Tango::ATTR_INVALID;
+				if(enabled && !(shelved && silenced >0))
+				{
+					*attr_value = _ERROR;
+				}
+				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
+				if(enabled && !(shelved && silenced >0))
+				{
+					push_change_event(attr_name, &except);
+					push_archive_event(attr_name, &except);
+				}
+			} catch(Tango::DevFailed & ex)
+			{
+				WARN_STREAM << "AlarmHandler::"<<__func__<<": " << attr_name << " - EXCEPTION PUSHING EVENTS: " << ex.errors[0].desc << endl;
+			}
+		}
+		catch(Tango::DevFailed & ex)
+		{
+			changed = !prev_error;
+			it->second.to_be_evaluated = true;
+			ostringstream o;
+			o << ex.errors[0].desc;
+			WARN_STREAM << "AlarmHandler::"<<__func__<<": " << o.str() << endl;
+			set_internal_alarm(INTERNAL_ERROR, gettime(), o.str());
+			try
+			{	//DevFailed for push events
+				Tango::DevErrorList errors(1);
+				errors.length(1);
+				it->second.ex_reason = ex.errors[0].reason;
+				it->second.ex_desc = ex.errors[0].desc;
+				it->second.ex_origin = ex.errors[0].origin;
+				errors[0].desc = CORBA::string_dup(it->second.ex_desc.c_str());
+				errors[0].severity = Tango::ERR;
+				errors[0].reason = CORBA::string_dup(it->second.ex_reason.c_str());
+				errors[0].origin = CORBA::string_dup(it->second.ex_origin.c_str());
+				Tango::DevFailed except(errors);
+				bool enabled=it->second.enabled;
+				bool shelved=it->second.shelved;
+				int silenced=it->second.silenced;
+				Tango::DevEnum *attr_value = get_AlarmState_data_ptr(attr_name);
+				it->second.error=true;
+				it->second.quality = Tango::ATTR_INVALID;
+				if(enabled && !(shelved && silenced >0))
+				{
+					*attr_value = _ERROR;
+				}
 				alarms.vlock->readerOut();	//Don't hold alarms lock while pushing events to prevent deadlocks
 				if(enabled && !(shelved && silenced >0))
 				{
@@ -4168,6 +4228,7 @@ void AlarmHandler::timer_update()
 	{
 		return;
 	}
+	DEBUG_STREAM << "AlarmHandler::timer_update(): changed -> prepare_alarm_attr" << endl;
 	prepare_alarm_attr();//TODO: frequencyAlarm should be updated anyway
 	try
 	{
@@ -4453,8 +4514,9 @@ void AlarmHandler::set_internal_alarm(string name, Tango::TimeVal t, string msg,
 formula_res_t AlarmHandler::eval_formula(tree_parse_info_t tree, string &attr_values)
 {
 	formula_res_t res = eval_expression(tree.trees.begin(), attr_values);
+	res.extract_result(); //from Array res.value to Scalar res.value
 #ifdef _DEBUG_FORMULA
-	DEBUG_STREAM << __func__ << ": 		 finally value=" << res.value << " valid=" << (int)res.valid << " error='" << res.error << "' ex_desc='" << res.ex_desc<<"' quality=" << res.quality << endl;
+	DEBUG_STREAM << __func__ << ": 		 finally value=" << print_vector(res.value) << " valid=" << (int)res.valid << " error='" << res.error << "' ex_desc='" << res.ex_desc<<"' quality=" << res.quality << endl;
 #endif
 	if(res.valid)
 	{
@@ -4466,7 +4528,7 @@ formula_res_t AlarmHandler::eval_formula(tree_parse_info_t tree, string &attr_va
     return res;
 }
 
-formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values, int ev_ind) //throw (string &), std::out_of_range
+formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values, vector<double> ev_ind)
 {
 
     ostringstream err;
@@ -4482,10 +4544,10 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }
         string val_d(i->value.begin(), i->value.end());
 		formula_res_t res;
-		res.value = strtod(val_d.c_str(), 0);
+		res.value = {(strtod(val_d.c_str(), 0))};
 		res.valid = true;
 #ifdef _DEBUG_FORMULA
-		DEBUG_STREAM << "		node value real = " << val_d << "(value="<<res.value<<" quality="<<res.quality<<")" << endl;
+		DEBUG_STREAM << "		node value real = " << val_d << "(value="<<print_vector(res.value)<<" quality="<<res.quality<<")" << endl;
 #endif
 		return res;
     }
@@ -4501,7 +4563,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value hex = " << val_d << endl;
 #endif
 		formula_res_t res;
-		res.value = strtod(val_d.c_str(), 0);
+		res.value = {(strtod(val_d.c_str(), 0))};
 		res.valid = true;
         return res;
     } 
@@ -4518,7 +4580,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value state : " << val_st << "=" << st << endl;
 #endif
 		formula_res_t res;
-		res.value = st;
+		res.value = {(double)st};
 		res.valid = true;
         return res;
     }
@@ -4535,7 +4597,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value alarm enum state : " << val_st << "=" << st << endl;
 #endif
 		formula_res_t res;
-		res.value = st;
+		res.value = {(double)st};
 		res.valid = true;
         return res;
     }
@@ -4553,7 +4615,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node value quality : " << val_quality << "=" << quality << endl;
 #endif
 		formula_res_t res;
-		res.value = quality;
+		res.value = {(double)quality};
 		res.valid = true;
         return res;
 	}
@@ -4567,26 +4629,23 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         	err <<  "in node unary_exprID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();
         	throw err.str(); 
         }
-		formula_res_t res;
-		res = eval_expression(i->children.begin(), attr_values);
         if (*i->value.begin() == '+')
         {
-        	res.value = + res.value;
+			return eval_expression(i->children.begin(), attr_values);
         }
         else if (*i->value.begin() == '-')
         {
-        	res.value = - res.value;
+			return -eval_expression(i->children.begin(), attr_values);
         }
         else if (*i->value.begin() == '!')
         {
-        	res.value = ! res.value;
+			return !eval_expression(i->children.begin(), attr_values);
         }
         else
         {
         	err <<  "in node unary_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
         	throw err.str();
         }
-        return res;
     }
     else if (i->value.id() == formula_grammar::mult_exprID)
     {
@@ -4646,49 +4705,81 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		DEBUG_STREAM << "		node event" << string(i->value.begin(), i->value.end()) << endl;
 #endif
 		formula_res_t ind;
-		if(i->children.size() != 2)		
+		if(i->children.size() < 2)
 		{
         	err <<  "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children=" << i->children.size();;
         	throw err.str(); 
         }
-		if((i->children.begin()+1)->value.id() == formula_grammar::indexID)
-			ind = eval_expression(i->children.begin()+1, attr_values);		//array index
-		else if((i->children.begin()+1)->value.id() == formula_grammar::propertyID)
+		size_t child_ind=0;
+		while((child_ind < i->children.size() -1) && ((i->children.begin()+child_ind+1)->value.id() == formula_grammar::indexID))
 		{
-			if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".quality")
+			formula_res_t ind_tmp;
+			ind_tmp = eval_expression(i->children.begin()+child_ind+1, attr_values);		//array index
+			if(ind_tmp.value.size() == 1 && ind_tmp.value[0]>=0)
 			{
-				formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
-				res.value = res.quality;
+				ind.value.push_back(ind_tmp.value[0]);
+			}
+			child_ind++;
+		}
+		if(child_ind+1 == i->children.size() -1  && (i->children.begin()+child_ind+1)->value.id() == formula_grammar::propertyID)
+		{
+			if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".quality")
+			{
+				formula_res_t res;
+				res = eval_expression(i->children.begin(), attr_values);
+				res.value = {(double)res.quality};
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  res.attr_name << string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) << "\":[" <<print_vector(res.value) << "],";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "		node event.quality -> " << res.value << endl;
+				DEBUG_STREAM << "		node event.quality -> " << print_vector(res.value) << endl;
 #endif
 				return res;
 			}
-			else if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".alarm")
+			else if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".alarm")
 			{
-				formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
-				res.value = (res.value == _UNACK) || (res.value == _ACKED);
+				formula_res_t res;
+				if(!ind.value.empty())
+					res = eval_expression(i->children.begin(), attr_values, ind.value);
+				else
+					res = eval_expression(i->children.begin(), attr_values);
+				std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+								[](double n) { return (double)((n == _UNACK) || (n == _ACKED)); });
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  res.attr_name << string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) << "\":[" <<print_vector(res.value) << "],";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "		node event.alarm -> " << res.value << endl;
+				DEBUG_STREAM << "		node event.alarm -> " << print_vector(res.value)<< endl;
 #endif
 				return res;
 			}
-			else if(string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end()) == ".normal")
+			else if(string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) == ".normal")
 			{
-				formula_res_t res = eval_expression(i->children.begin(), attr_values, (int)ind.value);
-				res.value = (res.value == _NORM) || (res.value == _RTNUN);
+				formula_res_t res;
+				if(!ind.value.empty())
+					res = eval_expression(i->children.begin(), attr_values, ind.value);
+				else
+					res = eval_expression(i->children.begin(), attr_values);
+				std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+								[](double n) { return (double)((n == _NORM) || (n == _RTNUN)); });
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  res.attr_name << string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end()) << "\":[" <<print_vector(res.value) << "],";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "		node event.normal -> " << res.value << endl;
+				DEBUG_STREAM << "		node event.normal -> " << print_vector(res.value) << endl;
 #endif
 				return res;
 			}
 		}
-		else
+		else if(child_ind+1 < i->children.size() -1)//unsupported more indexes/qualities
 		{
-        	err <<  "in node event_ID(" << string(i->value.begin(), i->value.end()) << ") children2 is not an index ->" << string((i->children.begin()+1)->value.begin(), (i->children.begin()+1)->value.end());
+        	err <<  "expecting indexes or properties after attribute name, found instead: "<< string((i->children.begin()+child_ind+1)->value.begin(), (i->children.begin()+child_ind+1)->value.end());
         	throw err.str(); 
         }
-		return eval_expression(i->children.begin(), attr_values, (int)ind.value);
+		if(!ind.value.empty())
+			return eval_expression(i->children.begin(), attr_values, ind.value);
+		else
+			return eval_expression(i->children.begin(), attr_values);
     }    
     else if (i->value.id() == formula_grammar::nameID)
     {
@@ -4713,11 +4804,17 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 					err <<  "attribute " << string(i->value.begin(), i->value.end()) << " value not valid while evaluating formula";
 				formula_res_t res;
 				res.valid = false;
+				res.dim_x = it->dim_x;
+				res.dim_y = it->dim_y;
 				res.quality = it->quality;
 				res.ex_reason = it->ex_reason;
 				res.ex_desc = it->ex_desc;
 				res.ex_origin = it->ex_origin;
 				res.error = err.str();
+				res.attr_name = it->name;
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  it->name << "\":{\"Reason\":\"" << res.ex_reason << "\",\"Desc\":\"" << res.ex_desc << "\",\"Origin\":\"" << res.ex_origin << "\"},";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
 				DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value not valid, desc=" << res.ex_desc << " quality=" << res.quality << endl;
 #endif
@@ -4733,35 +4830,130 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 					err <<  "attribute " << string(i->value.begin(), i->value.end()) << " value not initialized while evaluating formula";
 				formula_res_t res;
 				res.valid = false;
+				res.dim_x = it->dim_x;
+				res.dim_y = it->dim_y;
 				res.quality = it->quality;
 				res.ex_reason = it->ex_reason;
 				res.ex_desc = it->ex_desc;
 				res.ex_origin = it->ex_origin;
 				res.error = err.str();
+				res.attr_name = it->name;
+				ostringstream temp_attr_val;
+				temp_attr_val << "\"" <<  it->name << "\":{\"Reason\":\"" << res.ex_reason << "\",\"Desc\":\"" << res.ex_desc << "\",\"Origin\":\"" << res.ex_origin << "\"},";
+				attr_values += temp_attr_val.str();
 #ifdef _DEBUG_FORMULA
 				DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value empty, desc=" << res.ex_desc << " quality=" << res.quality << endl;
 #endif
 				events->veclock.readerOut();
         		//throw err.str();
 				return res;
-        	}        	
-			ostringstream temp_attr_val;
-			if(it->value.size() > 1)
-				temp_attr_val << "\"" <<  it->name << "[" << ev_ind << "]\":" <<it->value.at(ev_ind) << ",";//throw  std::out_of_range
-			else
-				temp_attr_val << "\"" <<  it->name << "\":" <<it->value.at(ev_ind) << ",";//throw  std::out_of_range
-			attr_values += temp_attr_val.str();
+        	} 
 			formula_res_t res;
 			res.valid = true;
+			res.dim_x = it->dim_x;
+			res.dim_y = it->dim_y;
 			res.quality = it->quality;
 			res.ex_reason = it->ex_reason;
 			res.ex_desc = it->ex_desc;
 			res.ex_origin = it->ex_origin;
+			res.attr_name = it->name;    	
+			ostringstream temp_attr_val;
+			if(it->value.size() > 0)
+			{
+				if(!ev_ind.empty())
+				{
+					size_t ev_ind_1d = ev_ind[0];
+					temp_attr_val << "\"" <<  it->name;
+					for(auto ei : ev_ind)
+					{
+						temp_attr_val << "[" << ei << "]";
+					}
+					temp_attr_val << "\":";
+					if(ev_ind.size() ==1 && it->dim_y <=1)//single element of 1D array
+					{
+						res.dim_x = 1;
+						res.dim_y = 0;
+						if(ev_ind[0] >= it->value.size())
+						{
+							err << "Requested element " << ev_ind[0] << " is out of bounds with dim=" << it->value.size();
+							events->veclock.readerOut();
+							DEBUG_STREAM << __func__ << ": " << err.str() << endl;
+							Tango::Except::throw_exception(	//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+								(const char *)"OUT_OF_RANGE",
+								err.str(),
+								it->name);
+						}
+						res.value = {it->value.at(ev_ind[0])};//throw  std::out_of_range
+						temp_attr_val << "[" << res.value[0] << "],";
+					}
+					else if(ev_ind.size() == 1 && it->dim_y > 1)//single row of 2D array
+					{
+						res.dim_y = 0;
+						if(ev_ind[0] >= it->dim_y)
+						{
+							err << "Requested row " << ev_ind[0] << " is out of bounds with dim_y=" << it->dim_y;
+							events->veclock.readerOut();
+							DEBUG_STREAM << __func__ << ": " << err.str() << endl;
+							Tango::Except::throw_exception(	//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+								(const char *)"OUT_OF_RANGE",
+								err.str(),
+								it->name);
+						}
+						auto vstart = it->value.begin();
+						auto vend = it->value.begin();
+						advance(vstart,(int)(ev_ind[0] * (it->dim_x)));
+						advance(vend,(int)(ev_ind[0]+1)*it->dim_x);
+						res.value = value_t(vstart,vend);
+						temp_attr_val << "[" << print_vector(res.value) << "],";
+					}
+					else if(ev_ind.size() == 2 && it->dim_y > 1)//single element of 2D array
+					{
+						res.dim_x = 1;
+						res.dim_y = 0;
+						if(ev_ind[0] >= it->dim_y)
+						{
+							err << "Requested row " << ev_ind[0] << " is out of bounds with dim_y=" << it->dim_y;
+							events->veclock.readerOut();
+							DEBUG_STREAM << __func__ << ": " << err.str() << endl;
+							Tango::Except::throw_exception(	//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+								(const char *)"OUT_OF_RANGE",
+								err.str(),
+								it->name);
+						}
+						if(ev_ind[1] >= it->dim_x)
+						{
+							err << "Requested column " << ev_ind[1] << " is out of bounds with dim_x=" << it->dim_x;
+							events->veclock.readerOut();
+							DEBUG_STREAM << __func__ << ": " << err.str() << endl;
+							Tango::Except::throw_exception(	//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+								(const char *)"OUT_OF_RANGE",
+								err.str(),
+								it->name);
+						}
+						res.value = {it->value.at(ev_ind[0]*it->dim_x + ev_ind[1])};//throw  std::out_of_range
+						temp_attr_val << "[" <<res.value[0] << "],";//throw  std::out_of_range
+					}
+					else //TODO N-DIMENSIONAL arrays
+					{
+						err << "UNSUPPORTED array indexes: " << ev_ind.size() << " indexes given, dim_x=" << it->dim_x << " dim_y=" << it->dim_y;
+						DEBUG_STREAM << __func__ << ": " << err.str() << endl;
+						events->veclock.readerOut();
+						throw err.str();
+					}
+				}
+				else
+				{
+					res.value = it->value;
+					temp_attr_val << "\"" <<  it->name << "\":[" <<print_vector(res.value) << "],";
+				}
+			}
+			else
+				temp_attr_val << "\"" <<  it->name << "\":[],";
+			attr_values += temp_attr_val.str();
+			events->veclock.readerOut();
 #ifdef _DEBUG_FORMULA
 			DEBUG_STREAM << "		node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
-#endif
-			res.value = it->value.at(ev_ind);		//throw  std::out_of_range
-			events->veclock.readerOut();
+#endif  
 			return 	res;
 		}
 		else
@@ -4784,7 +4976,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 #endif
      	formula_res_t res;
 		res.valid = true;
-     	res.value = strtod(val_d.c_str(), 0);
+     	res.value = {(strtod(val_d.c_str(), 0))};
         return res;
     }   
     else if (i->value.id() == formula_grammar::logical_exprID)
@@ -4825,56 +5017,72 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }	 		
 		formula_res_t res_1=eval_expression(i->children.begin(), attr_values),
            	res_2=eval_expression(i->children.begin()+1, attr_values);
-        long val_l1,val_l2;
+        vector<long> val_l1(res_1.value.size()),val_l2(res_2.value.size());
 		bool valid = res_1.valid && res_2.valid;
             
-    	string err2("ERROR: non-int value in bitwise operation!");
-    	val_l1 = (long)trunc(res_1.value);		//transform to long
-    	val_l2 = (long)trunc(res_2.value);		//transform to long
-
-	    if((val_l1 != res_1.value) || (val_l2 != res_2.value))	//if different, lost something with truncf
-    		throw err2;
+    	string err2("Non int value in bitwise operation");
+		std::transform(res_1.value.begin(), res_1.value.end(), val_l1.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		std::transform(res_2.value.begin(), res_2.value.end(), val_l2.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		size_t ii;
+		for(ii=0; ii<res_1.value.size(); ii++)
+		{
+			if(val_l1[ii] != res_1.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception(	//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
+		for(ii=0; ii<res_2.value.size(); ii++)
+		{
+			if(val_l2[ii] != res_2.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception( //throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
     		  
         if (*i->value.begin() == '&')
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 & val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
 				res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
 				res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(val_l1, res_1.dim_x,res_1.dim_y,val_l2,res_2.dim_x,res_2.dim_y,res.value,res.dim_x,res.dim_y, "Bitwise &", vectorUtils::fBitAnd);
             return res;
         }
         else if (*i->value.begin() == '|')
         {      
         	formula_res_t res;
-        	res.value = (double)(val_l1 | val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
 				res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
 				res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(val_l1, res_1.dim_x,res_1.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "Bitwise |", vectorUtils::fBitOr);
             return res;
         }  
         else if (*i->value.begin() == '^')
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 ^ val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
 				res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
 				res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(val_l1, res_1.dim_x,res_1.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "Bitwise ^", vectorUtils::fBitXor);
             return res;
         }  
         else
@@ -4895,42 +5103,59 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }			
 		formula_res_t res_1=eval_expression(i->children.begin(), attr_values),
            	res_2=eval_expression(i->children.begin()+1, attr_values);
-        long val_l1,val_l2;
+        vector<long> val_l1(res_1.value.size()),val_l2(res_2.value.size());
 		bool valid = res_1.valid && res_2.valid;
             
-    	string err2("ERROR: non-int value in bitwise operation!");
-    	val_l1 = (long)trunc(res_1.value);		//transform to long
-    	val_l2 = (long)trunc(res_2.value);		//transform to long
-
-	    if((val_l1 != res_1.value) || (val_l2 != res_2.value))	//if different, lost something with truncf
-    		throw err2;
+    	string err2("Non int value in bitwise operation");
+		std::transform(res_1.value.begin(), res_1.value.end(), val_l1.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		std::transform(res_2.value.begin(), res_2.value.end(), val_l2.begin(),
+                   [](double n) { return (long)trunc(n); });//transform to long
+		bool non_int_error=false;
+		size_t ii;
+		for(ii=0; ii<res_1.value.size(); ii++)
+		{
+			if(val_l1[ii] != res_1.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception(//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
+		for(ii=0; ii<res_2.value.size(); ii++)
+		{
+			if(val_l2[ii] != res_2.value[ii])	//if different, lost something with truncf
+				Tango::Except::throw_exception(//throw exception to have error not delayed otherwise it is subject to err_delay (delayed error notification)
+					(const char *)"FORMULA_ERROR",
+					err2,
+					string("Bitwise ") + string(i->value.begin(), i->value.end()));
+		}
     		  
         if (string(i->value.begin(), i->value.end()) == string("<<"))
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 << val_l2);
+			res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			res.valid = valid;
-        	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
 			{
 				res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
 				res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
 				res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(val_l1, res_2.dim_x,res_2.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "Bitwise <<", vectorUtils::fBitShiftL);
             return res;
         }
         else if (string(i->value.begin(), i->value.end()) == string(">>"))
         {
         	formula_res_t res;
-        	res.value = (double)(val_l1 >> val_l2);
-			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
+			res.valid = valid;
 			if(!res.valid)
 			{
 				res.ex_reason = res.combine_exception(res_1.ex_reason, res_2.ex_reason);
 				res.ex_desc = res.combine_exception(res_1.ex_desc, res_2.ex_desc);
 				res.ex_origin = res.combine_exception(res_1.ex_origin, res_2.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(val_l1, res_1.dim_x,res_1.dim_y, val_l2,res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, "Bitwise >>", vectorUtils::fBitShiftR);
             return res;
         }  
         else
@@ -4976,21 +5201,45 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 						err <<  "in node equality_exprID -> nameID(" << string(i2_1->value.begin(), i2_1->value.end()) << ") value not valid!";
 						if(it->ex_desc.length() > 0)
 							err << " EX: '" << it->ex_desc << "'";
+						res.valid = false;
+						res.dim_x = it->dim_x;
+						res.dim_y = it->dim_y;
+						res.quality = it->quality;
+						res.ex_reason = it->ex_reason;
+						res.ex_desc = it->ex_desc;
+						res.ex_origin = it->ex_origin;
 						events->veclock.readerOut();
-						throw err.str();
+						/*Tango::Except::throw_exception( //throw exception to have error not delayed
+							it->ex_reason,//or Event_ERROR
+							it->ex_desc,
+							it->ex_origin);*/
+						return res;
 					}
 					else if(it->type != Tango::DEV_STRING && it->value.empty())
 					{
 						err <<  "in node nameID(" << string(i2_1->value.begin(), i2_1->value.end()) << ") value not initialized!!";
 						if(it->ex_desc.length() > 0)
 							err << " EX: '" << it->ex_desc << "'";
+						res.valid = false;
+						res.dim_x = it->dim_x;
+						res.dim_y = it->dim_y;
+						res.quality = it->quality;
+						res.ex_reason = it->ex_reason;
+						res.ex_desc = it->ex_desc;
+						res.ex_origin = it->ex_origin;
 						events->veclock.readerOut();
-						throw err.str();
+						/*Tango::Except::throw_exception( //throw exception to have error not delayed
+							it->ex_reason,//or Event_ERROR
+							it->ex_desc,
+							it->ex_origin);*/
+						return res;
 					}
 					ostringstream temp_attr_val;
 					temp_attr_val << "\"" << it->name << "\":\"" <<it->value_string << "\",";
 					attr_values += temp_attr_val.str();
 					res.valid = true;
+					res.dim_x = it->dim_x;
+					res.dim_y = it->dim_y;
 					res.quality = it->quality;
 					res.ex_reason = it->ex_reason;
 					res.ex_desc = it->ex_desc;
@@ -5013,12 +5262,12 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 
 				if (string(i->value.begin(), i->value.end()) == string("!="))
 				{
-					res.value = attr_val != val_string;
+					res.value = {(double)(attr_val != val_string)};
 					return res;
 				}
 				else if (string(i->value.begin(), i->value.end()) == string("=="))
 				{
-					res.value = attr_val == val_string;
+					res.value = {(double)(attr_val == val_string)};
 					return res;
 				}
 				else
@@ -5079,7 +5328,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }        
         else
         {
-        	err <<  "in node equality_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
+        	err <<  "in node compare_exprID(" << string(i->value.begin(), i->value.end()) << ") value not allowed";
         	throw err.str(); 
         }	
     }   
@@ -5098,132 +5347,45 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		if (string(i->value.begin(), i->value.end()) == string("abs"))
 		{
 			res = eval_expression(i->children.begin(), attr_values);
-			res.value = fabs(res.value);
+			std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+							[](double n) { return fabs(n); });
 			return res;
 		}
 		else if (string(i->value.begin(), i->value.end()) == string("cos"))
 		{
 			res = eval_expression(i->children.begin(), attr_values);
-			res.value = cos(res.value);
+			std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+							[](double n) { return cos(n); });
 			return res;
 		}
 		else if (string(i->value.begin(), i->value.end()) == string("sin"))
 		{
 			res = eval_expression(i->children.begin(), attr_values);
-			res.value = sin(res.value);
+			std::transform(res.value.begin(), res.value.end(), res.value.begin(),
+							[](double n) { return sin(n); });
 			return res;
 		}
 		else if (string(i->value.begin(), i->value.end()) == string("quality"))
 		{
 			res = eval_expression(i->children.begin(), attr_values);
-			res.value = res.quality;
+			res.value = {(double)res.quality};//ignore values and keep quality as result
 			return res;
 		}
-		else if ((string(i->value.begin(), i->value.end()) == string("AND") || string(i->value.begin(), i->value.end()) == string("OR")) && i->children.begin()->value.id() == formula_grammar::nameID)
+		else if ((string(i->value.begin(), i->value.end()) == string("AND") || string(i->value.begin(), i->value.end()) == string("OR")))
 		{
-			events->veclock.readerIn();
-			vector<event>::iterator it = events->v_event.begin();
-			string s(i->children.begin()->value.begin(), i->children.begin()->value.end());
-			std::transform(s.begin(), s.end(), s.begin(), (int(*)(int))tolower);            //transform to lowercase
-#ifdef _DEBUG_FORMULA
-			DEBUG_STREAM << "                       -> " << string(i->value.begin(), i->value.end()) << "(" << s << ")" << endl;
-#endif
-			while ((it != events->v_event.end()) && (it->name != s))
-				it++;
-			if (it != events->v_event.end())
+			res = eval_expression(i->children.begin(), attr_values);
+			if(string(i->value.begin(), i->value.end()) == string("AND"))
 			{
-				if(!it->valid)
-				{
-					err <<  "in node funcID(" << string(i->value.begin(), i->value.end()) << "), (" << s << ") value not valid!" << ends;
-					if(it->ex_desc.length() > 0)
-						err << it->ex_desc << "";
-					else
-						err <<  "attribute " << string(i->value.begin(), i->value.end()) << " value not valid while evaluating formula";
-					formula_res_t res;
-					res.valid = false;
-					res.quality = it->quality;
-					res.ex_reason = it->ex_reason;
-					res.ex_desc = it->ex_desc;
-					res.ex_origin = it->ex_origin;
-					res.error = err.str();
-#ifdef _DEBUG_FORMULA
-					DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value not valid, desc=" << res.ex_desc << endl;
-#endif
-					events->veclock.readerOut();
-					//throw err.str();
-					return res;
-				}
-				else if(it->type != Tango::DEV_STRING && it->value.empty())
-				{
-					if(it->ex_desc.length() > 0)
-						err << it->ex_desc << "";
-					else
-						err <<  "attribute " << string(i->value.begin(), i->value.end()) << " value not initialized while evaluating formula";
-					formula_res_t res;
-					res.valid = false;
-					res.quality = it->quality;
-					res.ex_reason = it->ex_reason;
-					res.ex_desc = it->ex_desc;
-					res.ex_origin = it->ex_origin;
-					res.error = err.str();
-#ifdef _DEBUG_FORMULA
-					DEBUG_STREAM << "		attribute -> " << string(i->value.begin(), i->value.end()) << " value empty, desc=" << res.ex_desc << endl;
-#endif
-					events->veclock.readerOut();
-					//throw err.str();
-					return res;
-				}     
-
-				ostringstream temp_attr_val;
-				bool result;
-				if (string(i->value.begin(), i->value.end()) == string("AND"))
-					result = true;
-				else if (string(i->value.begin(), i->value.end()) == string("OR"))
-					result = false;
-
-				temp_attr_val << "\"" << it->name << "\":";
-				if(it->read_size > 1)
-					temp_attr_val << "[";
-				for(int att_ind = 0; att_ind < it->read_size && att_ind < it->value.size(); att_ind++)
-				{
-					temp_attr_val << it->value.at(att_ind);
-					if (string(i->value.begin(), i->value.end()) == string("AND"))
-					{
-						result = result && (bool)it->value.at(att_ind);
-						if(!result)     //comment to have all array values in attr_values
-							break;  //comment to have all array values in attr_values
-					}
-					else if (string(i->value.begin(), i->value.end()) == string("OR"))
-					{
-						result = result || (bool)it->value.at(att_ind);
-						if(result)      //comment to have all array values in attr_values
-							break;  //comment to have all array values in attr_values
-					}
-					if(att_ind < it->read_size-1 && att_ind < it->value.size()-1)
-						temp_attr_val << ",";
-				}
-				if(it->read_size > 1)
-					temp_attr_val << "]";
-				temp_attr_val << ",";
-				attr_values += temp_attr_val.str();
-				res.quality = it->quality;
-				res.ex_reason = it->ex_reason;
-				res.ex_desc = it->ex_desc;
-				res.ex_origin = it->ex_origin;
-				res.valid = true;
-#ifdef _DEBUG_FORMULA
-				DEBUG_STREAM << "               node name -> " << temp_attr_val.str() << " quality=" << res.quality << endl;
-#endif
-				res.value = result;
-				events->veclock.readerOut();
-				return res;    
+				res.value = {(double)std::accumulate(res.value.begin(), res.value.end(), (bool)true, [](bool acc, double n) { return (bool)(acc && (bool)(n));})};
 			}
-			else
+			else if(string(i->value.begin(), i->value.end()) == string("OR"))
 			{
-				events->veclock.readerOut();
-				err <<  "in function " << string(i->value.begin(), i->value.end()) << " event (" << s << ") not found in event table" << ends;
-				throw err.str();
+				res.value = {(double)std::accumulate(res.value.begin(), res.value.end(), (bool)false, [](bool acc, double n) { return (bool)(acc || (bool)(n));})};
 			}
+#ifdef _DEBUG_FORMULA
+			DEBUG_STREAM << "		node funcID("<<string(i->value.begin(), i->value.end())<<") value="<<print_vector(res.value)<<" quality="<<res.quality<< endl;
+#endif
+			return res;
 		}
 		else
 		{
@@ -5247,7 +5409,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		if (string(i->value.begin(), i->value.end()) == string("min"))
 		{
         	formula_res_t res;
-        	res.value = min(res_1.value, res_2.value);
+			vectorUtils::applyVectorFunc(res_1.value, res_1.dim_x,res_1.dim_y, res_2.value, res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, string(i->value.begin(), i->value.end()), vectorUtils::fMin);
 			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
@@ -5261,7 +5423,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		else if (string(i->value.begin(), i->value.end()) == string("max"))
 		{
         	formula_res_t res;
-        	res.value = max(res_1.value, res_2.value);
+			vectorUtils::applyVectorFunc(res_1.value, res_1.dim_x,res_1.dim_y, res_2.value, res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, string(i->value.begin(), i->value.end()), vectorUtils::fMax);
 			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
@@ -5275,7 +5437,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 		else if (string(i->value.begin(), i->value.end()) == string("pow"))
 		{
         	formula_res_t res;
-        	res.value = pow(res_1.value, res_2.value);
+			vectorUtils::applyVectorFunc(res_1.value, res_1.dim_x,res_1.dim_y, res_2.value, res_2.dim_x,res_2.dim_y, res.value,res.dim_x,res.dim_y, string(i->value.begin(), i->value.end()), vectorUtils::fPow);
 			res.valid = valid;
         	res.quality = res.combine_quality(res_1.quality, res_2.quality);
 			if(!res.valid)
@@ -5303,7 +5465,15 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
 			throw err.str();
 		}
 		formula_res_t res_1=eval_expression(i->children.begin(), attr_values);
-		if(res_1.value)
+		if(!res_1.valid || res_1.value.empty())
+		{
+#ifdef _DEBUG_FORMULA
+			DEBUG_STREAM << "		node ternary_if expression: returning Error=" << res_1.ex_desc << endl;
+#endif
+			return res_1;
+		}
+		res_1.extract_result();
+		if(res_1.value[0])
 		{
         	formula_res_t res = eval_expression(i->children.begin()+1, attr_values);
             return res;
@@ -5325,7 +5495,7 @@ formula_res_t AlarmHandler::eval_expression(iter_t const& i, string &attr_values
         }	
     }
     formula_res_t res;
-    res.value = 0;
+    res.value = {(double)0.0};
 	res.valid = false;
     return res;
 }
diff --git a/src/AlarmHandler.h b/src/AlarmHandler.h
index 1f0fe2e80cc8152fd09e99e2842a7de2cf20acd7..d8b6007263cb8a37dda7660794787613ea49b381 100644
--- a/src/AlarmHandler.h
+++ b/src/AlarmHandler.h
@@ -607,7 +607,7 @@ private:
 	formula_res_t eval_formula(tree_parse_info_t tree, string &attr_values);
 	void find_event_formula(tree_parse_info_t tree, vector<string> &);
 	
-	formula_res_t eval_expression(iter_t const& i, string &attr_values, int ev_ind=0);			//recursive tree node evaluation
+	formula_res_t eval_expression(iter_t const& i, string &attr_values, vector<double> ev_ind={});			//recursive tree node evaluation
 	void eval_node_event(iter_t const& i, vector<string> & ev);		//recursive tree node evaluation		
 
 	void prepare_alarm_attr();	//for read attribute alarm and push_change_event
diff --git a/src/alarm-thread.cpp b/src/alarm-thread.cpp
index 9a9874420fdf7d6f48c13f4feece634bd5f4b92e..a3a9c8b7ad467f4d2d545168578a3cd8948f1289 100644
--- a/src/alarm-thread.cpp
+++ b/src/alarm-thread.cpp
@@ -120,20 +120,20 @@ void alarm_thread::run(void *)
 			ostringstream err;
 			err << "omni_thread_fatal exception running alarm thread, err=" << ex.error << ends;
 			//WARN_STREAM << "alarm_thread::run(): " << err.str() << endl;	
-			printf("alarm_thread::run(): %s", err.str().c_str());
+			printf("alarm_thread::run(): %s\n", err.str().c_str());
 		}			
 		catch(Tango::DevFailed& ex)
 		{
 			ostringstream err;
 			err << "exception running alarm thread: '" << ex.errors[0].desc << "'" << ends;
 			//WARN_STREAM << "alarm_thread::run(): " << err.str() << endl;	
-			printf("alarm_thread::run(): %s", err.str().c_str());
+			printf("alarm_thread::run(): %s\n", err.str().c_str());
 			//Tango::Except::print_exception(ex);
 		}		
 		catch(...)
 		{
 			//WARN_STREAM << "alarm_thread::run(): catched unknown exception!!" << endl;
-			printf("alarm_thread::run(): catched unknown exception!!");
+			printf("alarm_thread::run(): catched unknown exception!!\n");
 		}		
 	}
 	//TANGO_LOG << "alarm_thread::run(): returning" << endl;
diff --git a/src/alarm_table.cpp b/src/alarm_table.cpp
index 1783cdaa8c6ffee21f6b29da5e990c23d5b112f5..6c1932c1f8cc225a4ce0655b16fee3b6493ea87b 100644
--- a/src/alarm_table.cpp
+++ b/src/alarm_table.cpp
@@ -374,14 +374,14 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 		found->second.quality = res.quality;
 		bool status_on_delay;
 		if(found->second.on_delay > 0)		//if enabled on delay
-			status_on_delay = ((bool)(res.value != 0)) && (found->second.on_counter >= 1) && ((ts.tv_sec - found->second.on_delay) > found->second.ts_on_delay.tv_sec);	//formula gives true and on delay has passed
+			status_on_delay = ((bool)(res.value[0] != 0)) && (found->second.on_counter >= 1) && ((ts.tv_sec - found->second.on_delay) > found->second.ts_on_delay.tv_sec);	//formula gives true and on delay has passed
 		else
-			status_on_delay = (bool)(res.value != 0);
+			status_on_delay = (bool)(res.value[0] != 0);
 		bool status_off_delay;
 		if(found->second.off_delay > 0)		//if enabled off delay
-			status_off_delay = (!(bool)(res.value != 0)) && (found->second.off_counter >= 1) && ((ts.tv_sec - found->second.off_delay) > found->second.ts_off_delay.tv_sec);	//formula gives false and off delay has passed
+			status_off_delay = (!(bool)(res.value[0] != 0)) && (found->second.off_counter >= 1) && ((ts.tv_sec - found->second.off_delay) > found->second.ts_off_delay.tv_sec);	//formula gives false and off delay has passed
 		else
-			status_off_delay = !(bool)(res.value != 0);
+			status_off_delay = !(bool)(res.value[0] != 0);
 		//if status changed:
 		// - from S_NORMAL to S_ALARM considering also on delay
 		//or
@@ -389,12 +389,12 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 		if((status_on_delay && (found->second.stat == S_NORMAL)) || (status_off_delay && (found->second.stat == S_ALARM)))
 		{
 			ret_changed=true;
-			if((bool)(res.value != 0))
+			if((bool)(res.value[0] != 0))
 				found->second.ack = NOT_ACK;	//if changing from NORMAL to ALARM -> NACK
 			//a.grp = found->second.grp2str();
-			//a.msg = (int)(res.value) ? found->second.msg : "";
+			//a.msg = (int)(res.value[0]) ? found->second.msg : "";
 			found->second.ts = ts;	/* store event timestamp into alarm timestamp */ //here update ts only if status changed
-			if((bool)(res.value != 0))
+			if((bool)(res.value[0] != 0))
 			{
 				found->second.is_new = 1;		//here set this alarm as new, read attribute set it to 0	//12-06-08: StopNew command set it to 0
 				if(found->second.dp_a && ((ts.tv_sec - startup_complete.tv_sec) > 10))		//action from S_NORMAL to S_ALARM
@@ -525,7 +525,7 @@ bool alarm_table::update(const string& alm_name, Tango::TimeVal ts, formula_res_
 			found->second.error = true;
 		}
 
-		if((bool)(res.value != 0)) {
+		if((bool)(res.value[0] != 0)) {
 			found->second.on_counter++;
 			found->second.off_counter = 0;
 		} else {
diff --git a/src/alarm_table.h b/src/alarm_table.h
index 8155101a0710e39a645ae3d81b77fdc61a46ca86..d3701ec44af780ad8a29fb7d9b9f41cdced421a2 100644
--- a/src/alarm_table.h
+++ b/src/alarm_table.h
@@ -14,6 +14,7 @@
 #include <iostream>
 #include <string>
 #include <map>
+#include <numeric>		//for std::accumulate
 
 #include <tango/tango.h>
 
@@ -49,6 +50,7 @@
 
 using namespace std;
 
+typedef vector<Tango::DevDouble> value_t;
 
 #if BOOST_VERSION  < 103600
 typedef std::string::iterator  iterator_t;
@@ -109,11 +111,99 @@ struct rwlock_t
 };
 #endif
 
+template <typename T>
+string print_vector(const std::vector<T>& v, const char * const separator = ",")
+{
+	ostringstream out;
+    if(!v.empty())
+    {
+        std::copy(v.begin(),
+                  --v.end(),
+                  std::ostream_iterator<T>(out/*std::cout*/, separator));
+        out << v.back();
+    }
+	return out.str();
+}
+
+struct vectorUtils
+{
+static double fBitAnd(long a, long b){	return (double)(a & b);}
+static double fBitOr(long a, long b){	return (double)(a | b);}
+static double fBitXor(long a, long b){	return (double)(a ^ b);}
+static double fBitShiftL(long a, long b){	return (double)(a << b);}
+static double fBitShiftR(long a, long b){	return (double)(a >> b);}
+static double fMin(double a, double b){	return (double)min(a, b);}
+static double fMax(double a, double b){	return (double)max(a, b);}
+static double fPow(double a, double b){	return (double)pow(a, b);}
+static double fEqual(double a, double b){	return (double)(a == b);}
+static double fDifferent(double a, double b){	return (double)(a != b);}
+static double fGreaterEqual(double a, double b){	return (double)(a >= b);}
+static double fGreater(double a, double b){	return (double)(a > b);}
+static double fLessEqual(double a, double b){	return (double)(a <= b);}
+static double fLess(double a, double b){	return (double)(a < b);}
+static double fPlus(double a, double b){	return (double)(a + b);}
+static double fMinus(double a, double b){	return (double)(a - b);}
+static double fMult(double a, double b){	return (double)(a * b);}
+static double fDiv(double a, double b){	return (double)(a / b);}
+static double fAnd(double a, double b){	return (double)((bool)a && (bool)b);}
+static double fOr(double a, double b){	return (double)((bool)a || (bool)b);}
+
+template<class T >
+static void applyVectorFunc(const vector<T> & v1, long v1_x, long v1_y, const vector<T> & v2, long v2_x, long v2_y, value_t &res, long &res_x, long &res_y, const string& origin, double (*func)(T, T))
+{
+	if(v1.size() > 0 && v2.size() > 0 && (v1.size() == v2.size()))
+	{
+		res_x = v1_x;
+		res_y = v1_y;
+		if(v1_x != v2_x || (v1_y != v2_y && (v1_y > 1 || v2_y > 1)))//dim_y 0 and 1 are the same
+		{
+			ostringstream o;
+			o << "Array sizes do not match: " << (v1_y ? v1_y : 1) << "x" << v1_x <<  " != " << (v2_y ? v2_y : 1) << "x" << v2_x;
+			Tango::Except::throw_exception( //throw exception to have error not delayed
+				"FORMULA_ERROR",
+				o.str(),
+				origin);
+		}
+		res.resize(v1.size());
+		std::transform(v1.begin(), v1.end(), v2.begin(),res.begin(),
+					[func](T a, T b) { return func(a, b); });				
+	}
+	else if(v2.size() == 1)
+	{
+		res_x = v1_x;
+		res_y = v1_y;
+		T b = v2[0];
+		res.resize(v1.size());
+		std::transform(v1.begin(), v1.end(), res.begin(),
+					[b,func](T a) { return func(a, b); });
+	}
+	else if(v1.size() == 1)
+	{
+		res_x = v2_x;
+		res_y = v2_y;
+		T a = v1[0];
+		res.resize(v2.size());
+		std::transform(v2.begin(), v2.end(), res.begin(),
+					[a,func](T b) { return func(a, b); });
+	}
+	else if(v1.size() > 0 && v2.size() > 0)
+	{
+		ostringstream o;
+		o << "Array sizes do not match: " << (v1_y ? v1_y : 1) << "x" << v1_x <<  " != " << (v2_y ? v2_y : 1) << "x" << v2_x;
+		Tango::Except::throw_exception( //throw exception to have error not delayed
+			"FORMULA_ERROR",
+			o.str(),
+			origin);
+	}
+}
+};
 
 struct formula_res_t
 {
-	formula_res_t(){value=0;valid=false;quality=Tango::ATTR_VALID;ex_reason=string("");ex_desc=string("");ex_origin=string("");}
-	double value;
+	formula_res_t(){valid=false;quality=Tango::ATTR_VALID;ex_reason=string("");ex_desc=string("");ex_origin=string("");dim_x=0;dim_y=0;}
+	value_t value;
+	long dim_x;
+	long dim_y;
 	int quality;
 	bool valid;
 	string error;
@@ -121,6 +211,7 @@ struct formula_res_t
 	string ex_reason;
 	string ex_desc;
 	string ex_origin;
+	string attr_name; //last evaluated attr name
 	int combine_quality(int quality1, int quality2)
 	{
 		int res;
@@ -143,10 +234,14 @@ struct formula_res_t
 		else
 			return ex_2;
 	}
+	void extract_result()
+	{
+		value = {(double)std::accumulate(value.begin(), value.end(), (bool)false, [](bool a, double b) { return (bool)(a || (bool)b); })};
+	}
+
 	formula_res_t operator==(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value == e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -155,12 +250,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fEqual);
 			return res;
 		}
 	formula_res_t operator!=(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value != e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -169,12 +264,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fDifferent);
 			return res;
 		}
 	formula_res_t operator<=(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value <= e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -183,12 +278,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fLessEqual);
 			return res;
 		}
 	formula_res_t operator>=(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value >= e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -197,12 +292,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fGreaterEqual);
 			return res;
 		}
 	formula_res_t operator<(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value < e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -211,12 +306,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fLess);
 			return res;
 		}
 	formula_res_t operator>(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value > e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -225,13 +320,19 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fGreater);
 			return res;
 		}
 	formula_res_t operator||(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = (valid && value) || (e.valid && e.value);
-			res.valid = (valid && value) || (e.valid && e.value) || (valid && e.valid);
+			if(value.size() <= 1 && e.value.size() <= 1) //apply special logic ov validity only if comparing scalars. Being careful that if valid=false, then size could be 0
+			{
+				res.value = {(double)((valid && value[0]) || (e.valid && e.value[0]))}; //in OR one operand TRUE and valid is enough
+				res.valid = (valid && value[0]) || (e.valid && e.value[0]) || (valid && e.valid); //in OR one operand TRUE and valid is enough, otherwise both valid as usual 
+			}
+			else
+				res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
 			{
@@ -239,13 +340,22 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			if(!(value.size() <= 1 && e.value.size() <= 1))
+			{
+				vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fOr);
+			}
 			return res;
 		}
 	formula_res_t operator&&(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = !((valid && !value) || (e.valid && !e.value)) || (valid && value && e.valid && e.value);
-			res.valid = (valid && !value) || (e.valid && !e.value) || (valid && e.valid);
+			if(value.size() <= 1 && e.value.size() <= 1) //apply special logic ov validity only if comparing scalars
+			{
+				res.value = {(double)(!((valid && !value[0]) || (e.valid && !e.value[0])) || (valid && value[0] && e.valid && e.value[0]))}; //if at least one operand is FALSE and valid, result is FALSE for sure (and valid)
+				res.valid = (valid && !value[0]) || (e.valid && !e.value[0]) || (valid && e.valid);
+			}
+			else
+				res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
 			{
@@ -253,12 +363,15 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			if(!(value.size() <= 1 && e.value.size() <= 1))
+			{
+				vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fAnd);
+			}
 			return res;
 		}
 	formula_res_t operator+(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value + e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -267,12 +380,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fPlus);
 			return res;
 		}
 	formula_res_t operator-(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value - e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -281,12 +394,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fMinus);
 			return res;
 		}
 	formula_res_t operator*(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value * e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -295,12 +408,12 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fMult);
 			return res;
 		}
 	formula_res_t operator/(const formula_res_t& e)
 		{
 			formula_res_t res;
-			res.value = value / e.value;
 			res.valid = valid && e.valid;
 			res.quality = combine_quality(quality, e.quality);
 			if(!res.valid)
@@ -309,6 +422,25 @@ struct formula_res_t
 				res.ex_desc = combine_exception(ex_desc, e.ex_desc);
 				res.ex_origin = combine_exception(ex_origin, e.ex_origin);
 			}
+			vectorUtils::applyVectorFunc(value,dim_x,dim_y,e.value,e.dim_x,e.dim_y,res.value,res.dim_x,res.dim_y,__func__,vectorUtils::fDiv);
+			return res;
+		}
+	formula_res_t operator!()
+		{
+			formula_res_t res;
+			for(size_t ii=0; ii < value.size(); ii++)
+			{
+				res.value.push_back(!value[ii]);
+			}
+			return res;
+		}
+	formula_res_t operator-()
+		{
+			formula_res_t res;
+			for(size_t ii=0; ii < value.size(); ii++)
+			{
+				res.value.push_back(-value[ii]);
+			}
 			return res;
 		}
 	/*string operator<<(const formula_res_t& e)
diff --git a/src/event_table.cpp b/src/event_table.cpp
index 2a19323790c259bafcf4d3554e605ffce2fb07ee..2f9f97731dc9670edbc4d958c0c03b45d69ff65b 100644
--- a/src/event_table.cpp
+++ b/src/event_table.cpp
@@ -1278,7 +1278,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
 			e.ev_name = ev->attr_name;
 #endif
 			e.ts = ev->attr_value->time;
-			extract_values(ev->attr_value, e.value, e.value_string, e.type, e.read_size);
+			extract_values(ev->attr_value, e.value, e.value_string, e.type, e.read_size, e.dim_x, e.dim_y);
 		} else {
 			e.quality = Tango::ATTR_INVALID;
 #if 0//TANGO_VER >= 711
@@ -1341,7 +1341,7 @@ void EventCallBack::push_event(Tango::EventData* ev)
 	static_cast<AlarmHandler_ns::AlarmHandler *>(mydev)->evlist.push_back(e);
 }  /* push_event() */
 
-void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size)
+void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size, long &dim_x, long &dim_y)
 {
 	Tango::DevState stval;
 	vector<Tango::DevState> v_st;
@@ -1375,76 +1375,79 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
                 attr_r_dim.dim_y = 0;
                 //attr_w_dim.dim_y = 0;
         }
+		dim_x = attr_r_dim.dim_x;
+		dim_y = attr_r_dim.dim_y;
         read_size = attr_r_dim.dim_x;
         if(attr_r_dim.dim_y > 1)
                 read_size *= attr_r_dim.dim_y;
 
 	if (attr_value->get_type() == Tango::DEV_UCHAR) {
-		*(attr_value) >> v_uch;
+		attr_value->extract_read(v_uch);
 		for(vector<Tango::DevUChar>::iterator it = v_uch.begin(); it != v_uch.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_UCHAR;		
 	} else if (attr_value->get_type() == Tango::DEV_SHORT) {
-		*(attr_value) >> v_sh;
+		attr_value->extract_read(v_sh);
 		for(vector<Tango::DevShort>::iterator  it = v_sh.begin(); it != v_sh.end(); it++)
 			val.push_back((double)(*it));		//convert all to double				
 		type = Tango::DEV_SHORT;
 	} else if (attr_value->get_type() == Tango::DEV_USHORT) {
-		*(attr_value) >> v_ush;
+		attr_value->extract_read(v_ush);
 		for(vector<Tango::DevUShort>::iterator  it = v_ush.begin(); it != v_ush.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_USHORT;			
 	} else if (attr_value->get_type() == Tango::DEV_LONG) {
-		*(attr_value) >> v_lo;
+		attr_value->extract_read(v_lo);
 		for(vector<Tango::DevLong>::iterator  it = v_lo.begin(); it != v_lo.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_LONG;
 	} else if (attr_value->get_type() == Tango::DEV_STATE) {
 		//*(attr_value) >> v_st;		//doesn't work in tango 5
 		*(attr_value) >> stval;
-		v_st.push_back(stval);
-		for(vector<Tango::DevState>::iterator it = v_st.begin(); it != v_st.end(); it++)
-			val.push_back((double)(*it));		//convert all to double
+		//v_st.push_back(stval);
+		//attr_value->extract_read(stval);
+		//for(vector<Tango::DevState>::iterator it = v_st.begin(); it != v_st.end(); it++)
+		val.push_back((double)(stval));		//convert all to double
 		type = Tango::DEV_STATE;
 #if 1//TANGO_VER >= 600
 	} else if (attr_value->get_type() == Tango::DEV_ULONG) {
-		*(attr_value) >> v_ulo;
+		attr_value->extract_read(v_ulo);
 		for(vector<Tango::DevULong>::iterator  it = v_ulo.begin(); it != v_ulo.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_ULONG;
 #endif  //TANGO_VER >= 600								
 	} else if (attr_value->get_type() == Tango::DEV_DOUBLE) {
-		*(attr_value) >> v_do;
+		attr_value->extract_read(v_do);
 		for(vector<Tango::DevDouble>::iterator  it = v_do.begin(); it != v_do.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_DOUBLE;
 	} else if (attr_value->get_type() == Tango::DEV_FLOAT) {
-		*(attr_value) >> v_fl;
+		attr_value->extract_read(v_fl);
 		for(vector<Tango::DevFloat>::iterator  it = v_fl.begin(); it != v_fl.end(); it++)
 			val.push_back((double)(*it));		//convert all to double						
 		type = Tango::DEV_FLOAT;
 	} else if (attr_value->get_type() == Tango::DEV_BOOLEAN) {
-		*(attr_value) >> v_bo;
+		attr_value->extract_read(v_bo);
 		for(vector<Tango::DevBoolean>::iterator  it = v_bo.begin(); it != v_bo.end(); it++)
 			val.push_back((double)(*it));		//convert all to double		
 		type = Tango::DEV_BOOLEAN;
 	} else if (attr_value->get_type() == Tango::DEV_LONG64) {
-		*(attr_value) >> v_lo64;
+		attr_value->extract_read(v_lo64);
 		for(vector<Tango::DevLong64>::iterator  it = v_lo64.begin(); it != v_lo64.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_LONG64;
 	} else if (attr_value->get_type() == Tango::DEV_ULONG64) {
-		*(attr_value) >> v_ulo64;
+		attr_value->extract_read(v_ulo64);
 		for(vector<Tango::DevULong64>::iterator  it = v_ulo64.begin(); it != v_ulo64.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_ULONG64;
 	} else if (attr_value->get_type() == Tango::DEV_ENUM) {
-		*(attr_value) >> v_enum;
+		attr_value->extract_read(v_enum);
 		for(vector<Tango::DevEnum>::iterator  it = v_enum.begin(); it != v_enum.end(); it++)
 			val.push_back((double)(*it));		//convert all to double
 		type = Tango::DEV_ENUM;
 	} else if (attr_value->get_type() == Tango::DEV_STRING) {
-		*(attr_value) >> v_string;
+		attr_value->extract_read(v_string);
 		val_string = *(v_string.begin());	//TODO: support string spectrum attrbutes
 		type = Tango::DEV_STRING;
 	}
@@ -1452,7 +1455,7 @@ void EventCallBack::extract_values(Tango::DeviceAttribute *attr_value, vector<do
 		ostringstream o;
 		o << "unknown type";
 		throw o.str();
-	}	
+	}
 }
 
 /*void EventCallBack::init(event_list* e)
diff --git a/src/event_table.h b/src/event_table.h
index 764369b3feed7d55fac9eff7f8d1a3e1fee08ad3..21758e040c3f4b637cc30124484da301e03f0564 100644
--- a/src/event_table.h
+++ b/src/event_table.h
@@ -66,7 +66,8 @@ class event {
 		int type,							/* attribute data type */
 				read_size,                                      /* attribute size of read part */
 				counter,					/* molteplicita' */
-				err_counter;					/* molteplicita' errore */				
+				err_counter;					/* molteplicita' errore */		
+		long dim_x, dim_y;		
 		alarm_list m_alarm;
 		bool valid;	//TODO: old
 		bool 	first;//TODO: new
@@ -116,6 +117,8 @@ typedef struct basic_event_info_s {
 	string ex_origin;
 	int type;
 	int read_size;
+	long dim_x;
+	long dim_y;
 	Tango::TimeVal ts;
 	string msg;
 } bei_t;
@@ -202,7 +205,7 @@ class EventCallBack : public Tango::CallBack, public Tango::LogAdapter
 		~EventCallBack(void);
 		void push_event(Tango::EventData* ev);
 		//void init(event_list* e);
-		void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size);
+		void extract_values(Tango::DeviceAttribute *attr_value, vector<double> &val, string &val_string, int &type, int &read_size, long &dim_x, long &dim_y);
 	private:
 		//event_list* e_ptr;
 		Tango::DeviceImpl *mydev;
diff --git a/src/formula_grammar.h b/src/formula_grammar.h
index 0aba5d0664c363d02eeb24ca3630e8b5269dc8db..8a83118f0c19bcd2401af1cfa6fb68bd76fd90c9 100644
--- a/src/formula_grammar.h
+++ b/src/formula_grammar.h
@@ -263,8 +263,8 @@ struct formula_grammar : public grammar<formula_grammar>
 
 			event_
 				=	name
-					>> !( (index)
-						| (property)
+					>> ( *(index)//0 or more indexex
+						>> !(property) //followed by 0 or 1 property
 						)
 				;