Project: engagement_generation License: BSD Dependencies:
Used by:
None |
engagement_generation/src/edu/wpi/hri/gen/policy/ref/ReferencePolicy.javaGo to the documentation of this file.00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2010, Worcester Polytechnic Institute 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of Worcester Polytechnic Institute. nor the names 00018 * of its contributors may be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 */ 00034 package edu.wpi.hri.gen.policy.ref; 00035 00036 import java.util.HashSet; 00037 import java.util.List; 00038 import java.util.Set; 00039 00040 import edu.wpi.hri.bml.behavior.ConstraintBehavior; 00041 import edu.wpi.hri.bml.behavior.ConstraintBehavior.SyncBlock; 00042 import edu.wpi.hri.bml.behavior.EmitBehavior; 00043 import edu.wpi.hri.bml.behavior.GazeBehavior; 00044 import edu.wpi.hri.bml.behavior.GestureBehavior; 00045 import edu.wpi.hri.bml.behavior.SpeechBehavior; 00046 import edu.wpi.hri.bml.behavior.SyncRef; 00047 import edu.wpi.hri.bml.behavior.SyncRef.SyncPoint; 00048 import edu.wpi.hri.gen.comm.BMLEmitListener; 00049 import edu.wpi.hri.gen.comm.GazeKnowledge; 00050 import edu.wpi.hri.gen.comm.SituationKnowledge; 00051 import edu.wpi.hri.gen.comm.SituationKnowledge.InvalidIDException; 00052 import edu.wpi.hri.gen.ebml.EBMLList; 00053 import edu.wpi.hri.gen.ebml.ReferenceBehavior; 00054 import edu.wpi.hri.gen.policy.ref.ReferenceOptions.UnreferencableException; 00055 import edu.wpi.hri.log.Logger; 00056 import edu.wpi.hri.log.Logger.Colors; 00057 import edu.wpi.hri.log.Logger.LoggerLevel; 00058 00067 public class ReferencePolicy { 00068 00069 protected final Logger logger; 00070 protected final BMLEmitListener emitListener; 00071 protected final NoPointZone noZone; 00072 00084 public ReferencePolicy(Logger logger, BMLEmitListener emit, 00085 NoPointZone noZone) { 00086 this.logger = logger.sub(Colors.POLICY, "REF"); 00087 this.emitListener = emit; 00088 this.noZone = noZone; 00089 this.logger.debug(LoggerLevel.INIT, "Created ..."); 00090 } 00091 00105 public boolean apply(EBMLList list, GazeKnowledge knowledge, 00106 SituationKnowledge world, String actor) { 00107 try { 00108 logger.debug(LoggerLevel.POLICY_EXECUTION, 00109 "Applying for entire list"); 00110 // create the data structures required to find the optimal series of 00111 // behaviors. 00112 ReferenceBehavior[] orderedRefs = this.findOrderedList(list); 00113 ReferenceOptions[] orderedOptions = new ReferenceOptions[orderedRefs.length]; 00114 00115 // just return success on nothing to do 00116 if (orderedRefs.length == 0) 00117 return true; 00118 00119 // create a reference option for each behavior, in the same order 00120 // this automatically filters out the unreliable options 00121 for (int c = 0; c < orderedRefs.length; c++) { 00122 orderedOptions[c] = new ReferenceOptions(logger, 00123 orderedRefs[c], world); 00124 } 00125 return this.applyOptions(list, knowledge, world, orderedOptions, 00126 actor); 00127 } catch (InvalidIDException e) { 00128 logger.error("Reference policy failed: " + e.getMessage()); 00129 return false; 00130 } 00131 } 00132 00133 protected boolean applyOptions(EBMLList list, GazeKnowledge knowledge, 00134 SituationKnowledge world, ReferenceOptions[] orderedOptions, 00135 String actor) { 00136 logger.debug(LoggerLevel.POLICY_EXECUTION, 00137 "created options, finding best"); 00138 00139 try { 00140 // then find the sequence of lowest cost actions 00141 this.findLowestCost(orderedOptions, world, new GestureState( 00142 knowledge, world)); 00143 00144 logger.debug(LoggerLevel.POLICY_EXECUTION, 00145 "found best, adding to list"); 00146 00147 // then add each group of actions to the list and constraints 00148 for (ReferenceOptions opt : orderedOptions) 00149 this.addToList(list, opt, world, actor); 00150 00151 // once we're done, clear out the references 00152 list.getReferences().clear(); 00153 logger.debug(LoggerLevel.POLICY_EXECUTION, 00154 "finished applying all list"); 00155 } catch (UnreferencableException e) { 00156 logger.warn("unreferencable: " + e.getMessage()); 00157 return false; 00158 } 00159 return true; 00160 } 00161 00172 protected ReferenceBehavior[] findOrderedList(EBMLList list) { 00173 return list.getReferences().toArray(new ReferenceBehavior[0]); 00174 } 00175 00191 private void findLowestCost(ReferenceOptions[] options, 00192 SituationKnowledge situation, GestureState state) 00193 throws UnreferencableException { 00194 // make sure that we have options to begin with 00195 if (options.length > 0) { 00196 ReferenceOptions last = options[0]; 00197 for (int c = 1; c < options.length; c++) { 00198 last.setNextOption(options[c]); 00199 last = options[c]; 00200 } 00201 options[0].findBest(situation, state, noZone); 00202 } 00203 } 00204 00205 private void addToList(EBMLList list, ReferenceOptions option, 00206 SituationKnowledge situation, String actor) 00207 throws UnreferencableException { 00208 // first create the behaviors which are required 00209 GazeBehavior gaze = option.createGaze(); 00210 GestureBehavior point = option.createPoint(situation); 00211 SpeechBehavior speech = option.createSpeech(); 00212 GazeBehavior finalGaze = (gaze == null) ? null : new GazeBehavior( 00213 logger, "gaze-actor-" + option.getBehavior().getID(), actor, 00214 option.getBehavior().isRequired()); 00215 EmitBehavior emit = option.createDG(actor, emitListener, 00216 gaze != null ? gaze : speech); 00217 00218 logger.debug(LoggerLevel.POLICY_EXECUTION, "Created all behaviors"); 00219 00220 // find the required and optional constraints to use 00221 ConstraintBehavior constraint = option.getBehavior().isRequired() ? list 00222 .getRequiredConstraints() : list.getOptionalConstraints(); 00223 00224 // then add in the relative constraints since those are standard 00225 // constrain gaze:stroke_start -> point:start 00226 if (gaze != null && point != null) { 00227 SyncBlock block = new SyncBlock(new SyncRef(gaze, 00228 SyncPoint.STROKE_START, 0)); 00229 block.addRef(new SyncRef(point, SyncPoint.START, 0)); 00230 constraint.addSynchronized(block); 00231 } 00232 00233 // constrain gaze:stroke -> point:ready 00234 if (gaze != null && point != null) { 00235 SyncBlock block = new SyncBlock(new SyncRef(gaze, SyncPoint.STROKE, 00236 0)); 00237 block.addRef(new SyncRef(point, SyncPoint.READY, 0)); 00238 constraint.addSynchronized(block); 00239 } 00240 00241 // constraint point:stroke_start -> speech:start 00242 if (point != null) { 00243 SyncBlock block = new SyncBlock(new SyncRef(point, 00244 SyncPoint.STROKE_START, 0)); 00245 block.addRef(new SyncRef(speech, SyncPoint.START, 0)); 00246 constraint.addSynchronized(block); 00247 } 00248 // otherwise constrain gaze:stroke -> speech:start 00249 else if (gaze != null) { 00250 SyncBlock block = new SyncBlock(new SyncRef(gaze, SyncPoint.STROKE, 00251 0)); 00252 block.addRef(new SyncRef(speech, SyncPoint.START, 0)); 00253 constraint.addSynchronized(block); 00254 } 00255 00256 // constrain point:stroke -> finalGaze:start 00257 if (gaze != null && point != null) { 00258 SyncBlock block = new SyncBlock(new SyncRef(point, 00259 SyncPoint.STROKE, 0)); 00260 block.addRef(new SyncRef(finalGaze, SyncPoint.START, 0)); 00261 constraint.addSynchronized(block); 00262 } 00263 00264 // constrain speech:end -> finalGaze:stroke 00265 if (gaze != null) { 00266 SyncBlock block = new SyncBlock(new SyncRef(speech, SyncPoint.END, 00267 0)); 00268 block.addRef(new SyncRef(finalGaze, SyncPoint.STROKE, 0)); 00269 constraint.addSynchronized(block); 00270 } 00271 00272 // constrain (speech OR emit):end ->point:stroke_end 00273 if (point != null) { 00274 SyncBlock block = new SyncBlock(new SyncRef(option.isLast() ? emit 00275 : speech, SyncPoint.END, 0)); 00276 block.addRef(new SyncRef(point, SyncPoint.STROKE_END, 0)); 00277 constraint.addSynchronized(block); 00278 } 00279 00280 logger.debug(LoggerLevel.POLICY_EXECUTION, 00281 "added in all known constraints"); 00282 00283 // then deal with adding the other constraints from higher up 00284 SyncRef start = (gaze != null) ? new SyncRef(gaze, SyncPoint.START, 0) 00285 : new SyncRef(speech, SyncPoint.START, 0); 00286 SyncRef stroke = (point != null) ? new SyncRef(point, 00287 SyncPoint.STROKE_START, 0) : new SyncRef(speech, 00288 SyncPoint.START, 0); 00289 SyncRef end = (gaze != null) ? new SyncRef(finalGaze, SyncPoint.STROKE, 00290 0) : new SyncRef(speech, SyncPoint.END, 0); 00291 this.dealWithAllConstraints(list, option, start, stroke, end); 00292 00293 // then add the behaviors to their respective lists 00294 if (speech != null) 00295 list.getSpeeches().add(speech); 00296 if (gaze != null) { 00297 list.getGazes().add(gaze); 00298 list.getGazes().add(finalGaze); 00299 } 00300 if (point != null) 00301 list.getGestures().add(point); 00302 if (emit != null) 00303 list.getEmits().add(emit); 00304 00305 logger.debug(LoggerLevel.POLICY_EXECUTION, 00306 "added in all incoming constraints"); 00307 } 00308 00309 private void dealWithAllConstraints(EBMLList list, ReferenceOptions option, 00310 SyncRef start, SyncRef stroke, SyncRef end) 00311 throws UnreferencableException { 00312 // first we need to find the constraints which this reference is tied to 00313 String id = option.getBehavior().getID(); 00314 00315 ConstraintBehavior reqCons = list.getRequiredConstraints(); 00316 Set<SyncBlock> required = this.findConstraints(reqCons, id); 00317 ConstraintBehavior optCons = list.getOptionalConstraints(); 00318 Set<SyncBlock> optional = this.findConstraints(optCons, id); 00319 00320 logger.debug(LoggerLevel.POLICY_EXECUTION, "Found " + required.size() 00321 + " required blocks and " + optional.size() 00322 + " optional blocks"); 00323 00324 if ((required.size() + optional.size()) == 0) 00325 logger.warn("Could not find constraints, you should add some"); 00326 00327 // then for each constraint, ensure the reference id's are replaced 00328 // with the correct start, stroke, or end sync ref 00329 for (SyncBlock block : required) { 00330 fixBlock(block, id, start, stroke, end); 00331 } 00332 for (SyncBlock block : optional) { 00333 try { 00334 fixBlock(block, id, start, stroke, end); 00335 } catch (UnreferencableException e) { 00336 logger.warn("optional constraint ignored: " + e.getMessage()); 00337 } 00338 } 00339 } 00340 00341 private void fixBlock(SyncBlock block, String id, SyncRef start, 00342 SyncRef stroke, SyncRef end) throws UnreferencableException { 00343 // first deal with the start ref 00344 if (block.getStartRef().getID().equals(id)) { 00345 // determine the sync ref to use in the constraint 00346 SyncRef blockStart = null; 00347 if (block.getStartRef().getPoint() == SyncPoint.START) 00348 blockStart = start; 00349 else if (block.getStartRef().getPoint() == SyncPoint.STROKE) 00350 blockStart = stroke; 00351 else if (block.getStartRef().getPoint() == SyncPoint.END) 00352 blockStart = end; 00353 else 00354 throw new UnreferencableException("Can not constrain"); 00355 block.setStartRef(blockStart); 00356 } 00357 00358 // then all of the sub refs 00359 for (SyncRef ref : block.getRefs()) { 00360 if (ref.getID().equals(id)) { 00361 // determine the sync ref to use in the constraint 00362 SyncRef refStart = null; 00363 if (ref.getPoint() == SyncPoint.START) 00364 refStart = start; 00365 else if (ref.getPoint() == SyncPoint.STROKE) 00366 refStart = stroke; 00367 else if (ref.getPoint() == SyncPoint.END) 00368 refStart = end; 00369 else 00370 throw new UnreferencableException("Can not constrain"); 00371 block.removeRef(ref); 00372 block.addRef(refStart); 00373 return; 00374 } 00375 } 00376 } 00377 00378 private Set<SyncBlock> findConstraints(ConstraintBehavior cb, String id) { 00379 logger.debug(LoggerLevel.POLICY_EXECUTION, "Finding constraints for " 00380 + id); 00381 Set<SyncBlock> allBlocks = new HashSet<SyncBlock>(); 00382 allBlocks.addAll(this.findFromList(cb.getBefore(), id)); 00383 allBlocks.addAll(this.findFromList(cb.getSynchronize(), id)); 00384 allBlocks.addAll(this.findFromList(cb.getAfter(), id)); 00385 return allBlocks; 00386 } 00387 00388 private Set<SyncBlock> findFromList(List<SyncBlock> list, String id) { 00389 Set<SyncBlock> allBlocks = new HashSet<SyncBlock>(); 00390 logger.debug(LoggerLevel.ALL, "comparing " + list.size() 00391 + " constraints ..."); 00392 for (SyncBlock sb : list) { 00393 logger.debug(LoggerLevel.ALL, "Comparing start Constraint: [" 00394 + sb.getStartRef().getID() + "] to [" + id + "]"); 00395 if (sb.getStartRef().getID().equals(id)) 00396 allBlocks.add(sb); 00397 for (SyncRef ref : sb.getRefs()) { 00398 logger.debug(LoggerLevel.ALL, "Comparing ref Constraint: [" 00399 + ref.getID() + "] to [" + id + "]"); 00400 if (ref.getID().equals(id)) 00401 allBlocks.add(sb); 00402 } 00403 } 00404 return allBlocks; 00405 } 00406 } |