300 likes | 428 Views
Implementing an ADT. Example: Sum-Constraint ADT Part II Ohad Barzilay May 2004. Cell implementation. /** * A cell contains a value, and may be connected to * several constraint ports. * * @invariant connections != null, "Non - null connections" */ public class Cell {
E N D
Implementing an ADT Example: Sum-Constraint ADT Part II Ohad Barzilay May 2004
Cell implementation /** *Acellcontainsavalue,andmaybeconnectedto *severalconstraintports. * *@invariantconnections!=null,"Non-nullconnections" */ publicclassCell { protectedObject_value; protectedListSetconnections;
Cell implementation /** *CreatesanewCellwithnovalue. * *@postvalue()==null,"Nullvalue" */ publicCell() { connections=newListSet(); _value=null; } /** *CreatesanewCellwithagivenvalue. * *@postvalue()==new_val,"Valuestored" */ publicCell(Objectnew_val) { this(); _value=new_val; }
value() /** *ReturnsthevaluestoredinthisCell. */ public Object value() { return _value; } • Don’t access fields directly • No postcondition
add_connection /** *Addsaconnection(a'constraint-port' *pair)totheCell. * *@prec!=null,"Non-nullconstraint" *@prec.port_valid(port),"Validport" */ publicvoid add_connection(Constraint c, int port) { connections.extend(new Pair(c, new Integer(port))); }
set_value /** *SetsthevaluestoredintheCelltothegivenone. *Notifieristheuserprogram. * *@prenew_val!=null,"Non-nullnewvalue" *@postvalue()==new_val,"Valuestored" */ publicvoid set_value(Object new_val) { set_value(new_val, null, 0); }
set_value /** *SetsthevaluestoredintheCelltothegivenone. *Ifnull,notifieristheuserprogram. * *@prenew_val!=null,"Non-nullnewvalue" *@prenotifier==null||notifier.port_valid(port), * "Validport" *@prenotifier==null||value()==null, *"Constraintcannotoverrideexistingvalue" * *@postvalue()==new_val,"Valuestored" */ publicvoid set_value(Object new_val, Constraint notifier, int port)
set_value publicvoid set_value(Object new_val, Constraint notifier, int port) { Set agenda = null; if (_value != null) { agenda = new ListSet(); forget(agenda); } _value = new_val; ...
set_value ... Linear iter = connections.iterator(); for (iter.start(); !iter.after(); iter.forth()) { Pair connection = (Pair)iter.item(); Constraint c = (Constraint)connection.car(); int p = ((Integer)connection.cdr()).intValue(); if (!(c == notifier && p == port)) c.new_port_value(p); } if (agenda != null) { iter = agenda.iterator(); for (iter.start(); !iter.after(); iter.forth()) ((Constraint)iter.item()).deduce(); } }
forget /** *BeginsavalueretractionchainfromthisCell. *Whenfinished,thevalueofthisCell,andeveryvalue *inthenetworkdependingonitwillberetracted.Then *itwillbededucedifpossible. */ publicvoid forget() { Set agenda = new ListSet(); forget(agenda); Linear iter = agenda.iterator(); for (iter.start(); !iter.after(); iter.forth()) ((Constraint)iter.item()).deduce(); }
forget /** *Alinkwithinaretractingchain. *Whenfinished,thevalueofthisCellwillberetracted. * *@preagenda!=null,"Non-nullagenda" *@postvalue()==null */ protectedvoid forget(Set agenda) { if (_value != null) { _value = null; Linear iter = connections.iterator(); for (iter.start(); !iter.after(); iter.forth()) { Pair connection = (Pair)iter.item(); Constraint c = (Constraint)connection.car(); int p = ((Integer)connection.cdr()).intValue(); c.forget(p, agenda); } } }
toString public String toString() { StringBuffer result = new StringBuffer("<Cell: "); result.append(value() == null ? "---" : value().toString()); result.append(">"); return result.toString(); }
The Solution Implementing SumConstraint
SumConstraint publicclassSumConstraintextendsConstraint { publicstaticfinalintADDEND=0; publicstaticfinalintAUGEND=1; publicstaticfinalintSUM=2; publicstaticfinalintNUM_OF_PORTS=3; protectedCell[]ports; protectedboolean[]_deduced;
SumConstraint publicSumConstraint(Celladdend,Cellaugend,Cellsum) { ports=newCell[NUM_OF_PORTS]; ports[ADDEND]=addend; ports[AUGEND]=augend; ports[SUM]=sum; addend.add_connection(this,ADDEND); augend.add_connection(this,AUGEND); sum.add_connection(this,SUM); _deduced=newboolean[NUM_OF_PORTS]; for(inti=0;i<NUM_OF_PORTS;i++) _deduced[i]=false; deduce(); }
SumConstraint - contract /** *CreatesanewSumConstraintwhichisconnectedtothe * givenCells. *TheCellsarefixedduringthelifeoftheconstraint. * *@preaddend!=null,"Non-nulladdend" *@preaugend!=null,"Non-nullaugend" *@presum!=null,"Non-nullsum" *@post($prev(addend.value())==null)||defined(ADDEND), *"Addenddefinedifcellhadvalue" *@post($prev(augend.value())==null)||defined(AUGEND), *"Augenddefinedifcellhadvalue" *@post($prev(sum.value())==null)||defined(SUM), *"Sumdefinedifcellhadvalue" */ publicSumConstraint(Celladdend,Cellaugend,Cellsum)
port_valid /** *Returnstrueifthegivenportisoneof * ADDEND,AUGENDorSUM. */ publicboolean port_valid(int port) { return 0 <= port && port < NUM_OF_PORTS; }
get_port /** *Returnsthevaluestoredinthegivenport. * *@preport_valid(port),"Validport" *// @pre known(port), "Port value is known" // * possible,butbetter: *@post!known(port)==($ret==null), * "Unknowniffnull" */ public Object get_port(int port) { return ports[port].value(); }
defined /** *returnstrueiffthegivenportisdefined. * *@preport_valid(port),"Validport" * *@post$ret==(!deduced(port)&&get_port(port)!=null), *"Definediffhasvaluebutnotdeduced" */ publicboolean defined(int port) { return !_deduced[port] && ports[port].value() != null; }
deduced /** *Istheportdeduced? * *@preport_valid(port),"Validport" * *@post$ret==(!defined(port)&&get_port(port)!=null), *"Deducediffhasvaluebutnotdefined" *@post!$ret||(((Integer)get_port(SUM)).intValue()== * ((Integer)get_port(ADDEND)).intValue()+ * ((Integer)get_port(AUGEND)).intValue()), *"Deductionobeysconstraint" */ publicboolean deduced(int port) { return _deduced[port]; }
known /** *Returnstrueifthisportiseitherdefinedordeduced. * *@preport_valid(port),"Validport" * *@post$ret==(get_port(port)!=null), *"Knowniffportisnon-null" */ publicboolean known(int port) { return ports[port].value() != null; }
contradiction /** *Returnstrueifalltheportsaredefined,andthesumoftheaddend *andtheaugendport'svaluesisn'tequaltothevalueofthesumport. * *@post$ret==(defined(ADDEND)&&defined(AUGEND)&&defined(SUM) *&&(((Integer)get_port(ADDEND)).intValue()+ *((Integer)get_port(AUGEND)).intValue()!= *((Integer)get_port(SUM)).intValue())), *"Contradictioniffconstraintnotobeyed" */ publicboolean contradiction() { return defined(ADDEND) && defined(AUGEND) && defined(SUM) && (((Integer)get_port(ADDEND)).intValue() + ((Integer)get_port(AUGEND)).intValue() != ((Integer)get_port(SUM)).intValue()); }
new_port_value /** *Informconstraintofnewvalueinport.Tobecalledby *connectedcellafterchangingthecell'sownvalue. * *@preport_valid(port),"Validport" * *@postdefined(port),"Portdefined" *@post!deduced(port),"Portnotdeduced" */ protectedvoid new_port_value(int port) { deduced[port] = false; deduce(); }
forget /** *Retractsthevaluefromthegivenportrecursively.Tobe *calledbyconnectedcellafteritforgotitsownvalue.Ifthe *givenportisnotdefinedand/orisdeducednothinghappens. *Theconstraintaddsitselftotheagendainordertocheck *deductionsaftertheprocessisfinished. * *@preport_valid(port),"Validport" *@preagenda!=null,"Non-nullagenda" * *@post!defined(port),"Portundefined" */ protectedvoid forget(int port, Set agenda) { agenda.extend(this); retract(agenda); }
retract /**Retractpreviousdeductionifnolongervalid. */ protectedvoid retract(Set agenda) { if (_deduced[ADDEND] && !(defined(AUGEND) && defined(SUM))) { _deduced[ADDEND] = false; ports[ADDEND].forget(agenda); } elseif (_deduced[AUGEND] && !(defined(ADDEND) && defined(SUM))) { _deduced[AUGEND] = false; ports[AUGEND].forget(agenda); } elseif (_deduced[SUM] && !(defined(ADDEND) && defined(AUGEND))) { _deduced[SUM] = false; ports[SUM].forget(agenda); } }
deduce /**Attempttodeducenewinformationforportsinthisconstraint. */ protectedvoid deduce() { if (defined(ADDEND) && defined(AUGEND) && !known(SUM)) { _deduced[SUM] = true; ports[SUM].set_value( new Integer(((Integer)get_port(ADDEND)).intValue() + ((Integer)get_port(AUGEND)).intValue()), this, SUM); } ...
deduce ... if (defined(ADDEND) && !known(AUGEND) && defined(SUM)) { _deduced[AUGEND] = true; ports[AUGEND].set_value (new Integer(((Integer)get_port(SUM)).intValue() - ((Integer)get_port(ADDEND)).intValue()), this, AUGEND); } if (!known(ADDEND) && defined(AUGEND) && defined(SUM)) { _deduced[ADDEND] = true; ports[ADDEND].set_value (new Integer(((Integer)get_port(SUM)).intValue() - ((Integer)get_port(AUGEND)).intValue()), this, ADDEND); } }
port_string /** *@preport_valid(port),"Validport" */ protected String port_string(int port) { if (defined(port)) return"defined(" + get_port(port).toString() + ")"; elseif (deduced(port)) return"deduced(" + get_port(port).toString() + ")"; elsereturn"---"; }
toString public String toString() { StringBuffer result = new StringBuffer("<Sum: "); result.append(port_string(ADDEND)); result.append(" + "); result.append(port_string(AUGEND)); result.append(" = "); result.append(port_string(SUM)); if (contradiction()) result.append(" ***"); result.append(">"); return result.toString(); }