Example #1
0
    def work_entity_retrieval(self, belief, global_summary):
        '''
        '''
        array_slot_summary = SummaryUtils.arraySlotSummary(belief, self.domainString)
        logger.debug(str(global_summary))
        logger.debug('HDC policy: getGlobal') 
        done, output = self._getGlobal(belief, global_summary)
        
        if not done:
            logger.debug('HDC policy: getConfirmSelect')
            done, output = self._getConfirmSelect(belief, array_slot_summary)
        if not done:
            logger.debug('HDC policy: getInform')
            inform_summary = []
            for num_accepted in range(1, MAX_NUM_ACCEPTED+1):
                temp = SummaryUtils.actionSpecificInformSummary(belief, num_accepted, self.domainString)
                inform_summary.append(temp)
                       
            done, output = self._getInform(belief, global_summary, inform_summary)
        if not done:
            logger.debug('HDC policy: getRequest')
            done, output = self._getRequest(belief, array_slot_summary)
        if not done:
            logger.warning("HDCPolicy couldn't find action: execute reqmore().")
            output = 'reqmore()'

        if output == 'badact()' or output == 'null()':
            logger.warning('HDCPolicy chose bad or null action')
            output = 'null()'

        if self.use_confreq:
            #TODO - known problem here if use_confreq is True (ie being used)  FIXME
            output = PolicyUtils.add_venue_count(output, belief)
        return output
Example #2
0
def _getInformAlternativeEntities(acceptanceList, acceptanceList80, prohibitedList, domainString):
    '''
    Returns the dialogue act representing either
    1) there is not matching venue: inform(name=none, slot=value, ...)
    2) it offers a venue which is not on the prohibited list
    3) if all matching venues are on the prohibited list then it says
       there is no venue except x,y,z,... with such features:
       inform(name=none, name!=x, name!=y, name!=z, ..., slot=value, ...)
    '''
    acceptedValues = {}
    numFeats = len(acceptanceList80)
    for slot in acceptanceList80:
        (topvalue, topbelief) = acceptanceList80[slot]
        if topvalue != 'dontcare':
            acceptedValues[slot] = topvalue

    if len(acceptedValues) == 0:
        logger.warning("User didn't specify any constraints or all are dontcare")
        #return 'null()'

    result = Ontology.global_ontology.entity_by_features(domainString, acceptedValues)
    if len(result) == 0:
        return SummaryUtils.getInformNoneVenue(acceptedValues)
    else:
        for ent in result:
            name = ent['name']
            if name not in prohibitedList:
                return getInformAcceptedSlotsAboutEntity(acceptanceList80, ent, numFeats)

        return SummaryUtils.getInformNoMoreVenues(acceptanceList, result)

    return 'null()'
Example #3
0
def _getInformRequestedSlots(acceptanceList80, requestedSlots, name, domainString, bookinginfo=None):
    result = Ontology.global_ontology.entity_by_features(domainString, {'name':name})
    print ("aaa", name)
    print ("bbb", domainString)

    acceptedValues = {}
    for slot in acceptanceList80:
        (topvalue, topbelief) = acceptanceList80[slot]
        if topvalue != 'dontcare':
            acceptedValues[slot] = topvalue

    # add bookinginfo info to acceptedValues
    if bookinginfo is not None:
        for slot,constraint in bookinginfo.iteritems():
            if constraint is not None:
                acceptedValues[slot] = constraint
        

    if len(result) > 0 and name != 'none':
        # We found exactly one or more matching entities. Use the first one
        ent = result[0]
#         return SummaryUtils._getInformRequestedSlotsForEntity(acceptedValues, requestedSlots, ent) CHECK
        return SummaryUtils._getInformRequestedSlotsForEntity(requestedSlots, ent, domainString)
    else:
        logger.debug('Couldn\'t find the provided name ' + name)
        # We have not informed about an entity yet, or there are too many entities.
        return 'null()'
Example #4
0
def arraySlotSummaryRel(belief, domainString):
    '''
    Gets the summary vector for goal slots, including the top probabilities, entropy, etc.

    :param belief: dict representing the full belief state
    :param domainString: string representing the domain
    :return: (dict) of slot goal summaries
    '''
    summary = {}
    slots = Ontology.global_ontology.get_common_slots_for_all_types(
        domainString)

    for domain in slots:
        for s in slots[domain]:
            slot = domain + '_' + s
            summary[slot] = {}
            slot_belief = belief['beliefs'][slot]
            summary[slot]['TOPHYPS'], summary[slot][
                'ISTOPNONE'] = SummaryUtils.getTopBeliefsExcludingNone(
                    belief['beliefs'][slot])
            belief_dist = slot_belief.values()
            summary[slot]['ENTROPY'] = entropy(belief_dist)
            summary[slot][
                'ISREQUESTTOP'] = belief['beliefs']['requested'][slot] > 0.5

    return summary
Example #5
0
def getInformExactEntity(acceptanceList, numAccepted, domainString):
    '''**Method for global inform action:** creates inform act with none or an entity

    :param acceptanceList: of slots with value:prob mass pairs 
    :type acceptanceList: dict
    :param numAccepted: number of *accepted slots* (>80 prob mass)
    :type numAccepted: int
    :param domainString: domain tag
    :type domainString: str
    :returns: getInformNoneVenue() or getInformAcceptedSlotsAboutEntity() as appropriate
    '''
    acceptedValues = {}
    for i, slot in enumerate(acceptanceList):
        if i >= numAccepted:
            break
        #(topvalue, topbelief) = acceptanceList[slot]
        (topvalue, _) = acceptanceList[slot]
        if topvalue != 'dontcare':
            acceptedValues[slot] = topvalue

    result = Ontology.global_ontology.entity_by_features(domainString, acceptedValues)
    if len(result) == 0:
        return SummaryUtils.getInformNoneVenue(acceptedValues)
    else:
        ent = result[0]
        return getInformAcceptedSlotsAboutEntity(acceptanceList, ent, numAccepted)
Example #6
0
 def _updateDBfeatures(self, belief, eType):
     features = []
     for numAccepted in range(1, 6):
         temp = SummaryUtils.actionSpecificInformSummary(
             belief, numAccepted, eType)
         features += temp
     return features
Example #7
0
    def _getRequest(self, belief, array_slot_summary):
        '''
        '''

        # This is added for confreq.
        need_grounding = SummaryUtils.getTopBeliefs(
            belief, 0.8, domainString=self.domainString)

        for slot in Ontology.global_ontology.get_sorted_system_requestable_slots(
                self.domainString):
            summary = array_slot_summary[slot]
            (_, topprob) = summary['TOPHYPS'][0]
            #(_, secprob) = summary['TOPHYPS'][1]

            if topprob < 0.8:
                # Add implicit confirmation (for confreq.)
                grounding_slots = copy.deepcopy(need_grounding)
                if slot in grounding_slots:
                    del grounding_slots[slot]

                grounding_result = []
                for grounding_slot in grounding_slots:
                    if len(grounding_result) < 3:
                        (value, _) = grounding_slots[grounding_slot]
                        #(value, prob) = grounding_slots[grounding_slot]
                        grounding_result.append('%s="%s"' %
                                                (grounding_slot, value))

                if not grounding_result or not self.use_confreq:
                    return True, 'request(%s)' % slot
                else:
                    return True, 'confreq(' + ','.join(
                        grounding_result) + ',%s)' % slot

        return False, 'null()'
Example #8
0
def getInformRequestedSlots(requested_slots, name, domainString):
    '''
    Informs about the requested slots from the last informed venue of form the venue informed by name

    :param requested_slots: list of requested slots
    :param name: name of the last informed venue
    :param domainString: string representing the domain
    :return: string representing the inform dialogue act
    '''
    result = Ontology.global_ontology.entity_by_features(
        domainString, {'name': name})

    if len(result) > 0:
        ent = result[0]
        return _getInformRequestedSlotsForEntity(requested_slots, ent,
                                                 domainString)
    else:
        if not name:
            # Return a random venue
            result = []
            while len(result) == 0:
                rand_name = Ontology.global_ontology.getRandomValueForSlot(
                    domainString, 'name', nodontcare=True)
                result = Ontology.global_ontology.entity_by_features(
                    domainString, {'name': rand_name})
            ent = result[0]
            return _getInformRequestedSlotsForEntity(requested_slots, ent,
                                                     domainString)

        else:
            logger.warning('Couldn\'t find the provided name: ' + name)
            return SummaryUtils.getInformNoneVenue({'name': name})
Example #9
0
    def _getInform(self, belief, global_summary, inform_summary):
        act = 'null()'

        count80 = global_summary['GLOBAL_COUNTACCEPTED']
        offer_happened = global_summary['GLOBAL_OFFERHAPPENED']

        if count80 >= MAX_NUM_ACCEPTED:
            count80 = MAX_NUM_ACCEPTED - 1

        arr = inform_summary[count80]
        first = arr[0]  # True if there is no matching entities
        second = arr[1]  # True if there is one matching entities
        #third = arr[2]  # True if there is two~four matching entities
        discr = arr[4]  # True if we can discriminate more

        logger.debug(
            '%d among %d slots are accepted (>=0.8 belief).' %
            (count80,
             Ontology.global_ontology.get_length_system_requestable_slots(
                 self.domainString)))

        count80_logic = count80 >= Ontology.global_ontology.get_length_system_requestable_slots(
            self.domainString)
        if first or second or not discr or count80_logic:
            # If this inform gives either 0 or 1 or we've found everything we can ask about
            logger.debug(
                'Trying to get inform action, have enough accepted slots.')
            logger.debug('Is there no matching entity? %s.' % str(first))
            logger.debug('Is there only one matching entity? %s.' %
                         str(second))
            logger.debug('Can we discriminate more? %s.' % str(discr))
            requested_slots = SummaryUtils.getRequestedSlots(belief)

            if len(requested_slots) > 0 and offer_happened:
                logger.debug('Getting inform requested action.')
                act = PolicyUtils.getGlobalAction(
                    belief, 'INFORM_REQUESTED', domainString=self.domainString)
            else:
                logger.debug(
                    'Getting inform exact action with %d accepted slots.' %
                    count80)
                act = PolicyUtils.getInformAction(
                    count80, belief, domainString=self.domainString)

        if act != 'null()':
            return True, act
        return False, act
Example #10
0
def getInformAction(numAccepted, belief, domainString):
    '''**Method for global inform action:** returns inform act via getInformExactEntity() method \
            or null() if not enough accepted 
    
    :param belief: full belief state
    :type belief: dict
    :param numAccepted: number of slots with prob. mass > 80
    :type numAccepted: int
    :param domainString: domain tag
    :type domainString: str
    :returns: getInformExactEntity(acceptanceList,numAccepted)
    '''

    acceptanceList = SummaryUtils.getTopBeliefs(belief, domainString=domainString) # dict containing the slots with top values diferent to **NONE** and their top values
    if numAccepted > len(acceptanceList): # ic340: When would this happen?
        return 'null()'

    return getInformExactEntity(acceptanceList, numAccepted, domainString)
Example #11
0
def getInformAcceptedSlotsAboutEntity(acceptanceList, ent, numFeats):
    '''**Method for global inform action:** returns filled out inform() string
    need to be cleaned (Dongho)
    
    :param acceptanceList: of slots with value:prob mass pairs 
    :type acceptanceList: dict
    :param ent: slot:value properties for this entity
    :type ent: dict
    :param numFeats: result of globalOntology.entity_by_features(acceptedValues)
    :type numFeats: int
    :returns: (str) filled out inform() act
    '''

    ans = 'inform('
    feats = {'name': ent['name']}
    acceptanceKeys = acceptanceList.keys()

    maxNumFeats = 5
    if Settings.config.has_option("policy", "maxinformslots"):
        maxNumFeats = int(Settings.config.get('policy', 'maxinformslots'))

    if numFeats > maxNumFeats:
        Settings.random.shuffle(acceptanceKeys)
        acceptanceKeys = acceptanceKeys[:maxNumFeats]

    for i, slot in enumerate(acceptanceKeys):
        if i >= numFeats:
            break
        if slot == 'name':
            continue

        (value, belief) = acceptanceList[slot]
        if value == 'dontcare' and slot in ent and ent[slot] != "not available":
            feats[slot] = ent[slot]
        else:
            if slot in ent:
                feats[slot] = ent[slot]#value
            else:
                logger.debug('Slot %s is not found in data for entity %s' % (slot, ent['name']))

    ans += SummaryUtils.convertFeatsToStr(feats) + ')'
    return ans
Example #12
0
def add_venue_count(input, belief, domainString):
    '''Add venue count.

    :param input: String input act.
    :param belief: Belief state
    :param domainString: domain tag like 'SFHotels'
    :type domainString: str
    :returns: act with venue count.
    '''
    acceptanceList = SummaryUtils.getTopBeliefs(belief, domainString)
    accepted_slots = {}
    for i, slot in enumerate(acceptanceList):
        (topvalue, topbelief) = acceptanceList[slot]
        if topvalue != 'dontcare':
            accepted_slots[slot] = topvalue

    count = Ontology.global_ontology.get_length_entity_by_features(domainString, accepted_slots)
    input_act = DiaAct.DiaAct(input)
    if input_act.act == 'confreq':
        if count > 1:
            output = copy.deepcopy(input_act)
            for slot in accepted_slots:
                val = accepted_slots[slot]
                if not input_act.contains(slot, val):
                    output.append_front(slot, val)

            output.append_front('count', str(count))
            return str(output)
    #     else:
    #         logger.warning('accepted slots: ' + str(accepted_slots))
    #         logger.error('badact in add_venue_count: input=%s, count=%d' % (input, count))
    #         return 'badact()'
    # elif count <=1 and len(accepted_slots) > 0 and input_act.act in ['confirm', 'request', 'select']:
    #     logger.warning('accepted slots: ' + str(accepted_slots))
    #     logger.error('badact in add_venue_count: input=%s, count=%d' % (input, count))
    #     return 'badact()'
    return input
Example #13
0
    def _updateMactFeat(self, last_feature, lastact):
        '''
        Add features into self.prevstate  - recording actions taken by machine

        :param last_feature: last system state features
        :type last_feature: dict
        
        :param lastact: last system dialgoue act
        :type lastact: string

        :return: None
        '''
        features = {}
        if self.turn == 0:
            features['lastInformedVenue'] = ''
            features['informedVenueSinceNone'] = []
            features['lastActionInformNone'] = False
            features['offerHappened'] = False

        else:
            last_system_act = dact.ParseAct(lastact, user=False)

            # lastInformedVenue
            current_informed_venue = BeliefTrackingUtils._getCurrentInformedVenue(last_system_act)
            current_informed_venue = self._list2str_bugfix(current_informed_venue)
            
            if current_informed_venue != '':
                features['lastInformedVenue'] = current_informed_venue
            elif last_feature != None and last_feature['lastInformedVenue'] != None:
                features['lastInformedVenue'] = last_feature['lastInformedVenue']

            # informedVenueSinceNone
            if last_feature['informedVenueSinceNone'] == None or \
		last_system_act == None or BeliefTrackingUtils._hasType(last_system_act, 'canthelp'):
                informedVenueSinceNone = []
            else:
                informedVenueSinceNone = last_feature['informedVenueSinceNone']
            if BeliefTrackingUtils._hasTypeSlot(last_system_act, 'offer', 'name'):
                venue = BeliefTrackingUtils._getTypeSlot(last_system_act, 'offer', 'name')
                venue = self._list2str_bugfix(venue)
                informedVenueSinceNone.append(venue)
            features['informedVenueSinceNone'] = informedVenueSinceNone

            # lastActionInformNone
            if BeliefTrackingUtils._hasType(last_system_act, 'canthelp'):
                features['lastActionInformNone'] = True
            else:
                features['lastActionInformNone'] = False

            # offerhappened
            if BeliefTrackingUtils._hasTypeSlot(last_system_act, 'offer', 'name'):
                features['offerHappened'] = True
            else:
                features['offerHappened'] = False

        # inform_info
        features['inform_info'] = []
        for numAccepted in range(1,6):
            temp =  SummaryUtils.actionSpecificInformSummary(self.prevbelief, numAccepted, self.domainString)
            features['inform_info'] += temp
           
        self.prevbelief['features'] = features
Example #14
0
 def nextAction(self, belief):
     """Primary response function of HDC policy - hands off control to entity-retrieval policy.
     """
     global_summary = SummaryUtils.globalSummary(
         belief, domainString=self.domainString)
     return self.work_entity_retrieval(belief, global_summary)
Example #15
0
 def getInformByName(self, belief):
     requested_slots = SummaryUtilsRel.getRequestedSlots(belief)
     name = SummaryUtils.getTopBelief(belief['beliefs']['name'])[0]
     if name == '**NONE**':
         name = belief['features']['lastInformedVenue']
     return SummaryUtilsRel.getInformRequestedSlots(requested_slots, name, self.domainString)
Example #16
0
    def getNonExecutable(self, belief, lastSystemAction):
        '''
        Set of rules defining the mask over the action set, given the current belief state
        :param belief: the current master belief
        :type belief: dict
        :param lastSystemAction: the system action of the previous turn
        :type lastSystemAction: string
        :return: list of non-executable (masked) actions
        '''

        array_slot_summary = SummaryUtils.arraySlotSummary(belief, self.domainString)
        array_slot_summary_rel = SummaryUtilsRel.arraySlotSummaryRel(belief, self.domainString)
        global_summary = SummaryUtils.globalSummary(belief, self.domainString)
        if global_summary['GLOBAL_BYALTERNATIVES'] and not global_summary['GLOBAL_THANKYOU'] and not global_summary['GLOBAL_ACK']:
            self.alternatives_requested = True

        nonexec = ['pass']

        for action in self.action_names:
            mask_action = False
            
            if 'rel' in action:
                if "request_" in action:
                    nonexec.append(action)
#                     pass
#                     if mask_action and self.request_mask:
#                         nonexec.append(action)
    
                elif "select_" in action:
                    slot_summary = array_slot_summary_rel['_'.join(action.split('_')[2:])]
                    top_prob = slot_summary['TOPHYPS'][0][1]
                    sec_prob = slot_summary['TOPHYPS'][1][1]
                    if top_prob == 0 or sec_prob == 0:
                        mask_action = True
                    if mask_action and self.request_mask:
                        nonexec.append(action)
    
                elif "confirm_" in action:
                    slot_summary = array_slot_summary_rel['_'.join(action.split('_')[2:])]
                    top_prob = slot_summary['TOPHYPS'][0][1]
                    if top_prob == 0:
                        mask_action = True
                    if mask_action and self.request_mask:
                        nonexec.append(action)
    
                
            else:
                if action == "inform":
                    acceptance_list = SummaryUtils.getTopBeliefs(belief, domainString=self.domainString)
                    discriminable = SummaryUtils.acceptanceListCanBeDiscriminated(acceptance_list,
                                                                                                         self.domainString)
                    if not global_summary['GLOBAL_BYCONSTRAINTS']:
                        mask_action = True
                    if global_summary['GLOBAL_COUNTACCEPTED'] < self.inform_count_accepted and discriminable:
                        mask_action = True
                    if mask_action and self.inform_mask:
                        nonexec.append(action)
    
                elif action == "inform_byname":
                    if not global_summary['GLOBAL_BYNAME']:
                        mask_action = True
                    if belief['features']['lastInformedVenue'] == '' \
                            and SummaryUtils.getTopBelief(belief['beliefs']['name'])[0] == '**NONE**' :
                        mask_action = True
                    if mask_action and self.inform_mask:
                        nonexec.append(action)
    
                elif action == "inform_alternatives":
                    if not self.alternatives_requested:
                        mask_action = True
                    if belief['features']['lastInformedVenue'] == '':
                        mask_action = True
                    if mask_action and self.inform_mask:
                        nonexec.append(action)
    
                elif action == "bye":
                    if not global_summary['GLOBAL_FINISHED']:
                        mask_action = True
                    if mask_action and self.bye_mask:
                        nonexec.append(action)
    
                elif action == "repeat":
                    if not global_summary['GLOBAL_REPEAT'] or lastSystemAction is None:
                        mask_action = True
                    mask_action = True  # ic340: this action is "deactivated" because simuser doesnt know how to react to it
                    if mask_action:
                        nonexec.append(action)
    
                elif action == "reqmore":
                    if belief['features']['lastInformedVenue'] == '':
                        mask_action = True
                    if mask_action and self.request_mask:
                        nonexec.append(action)
    
                elif action == "restart":
                    if not global_summary['GLOBAL_RESTART']:
                        mask_action = True
                    mask_action = True  # ic340: this action is "deactivated" because simuser doesnt know how to react to it
                    if mask_action:
                        nonexec.append(action)
    
                elif "request_" in action:
                    pass
                    if mask_action and self.request_mask:
                        nonexec.append(action)
    
                elif "select_" in action:
                    slot_summary = array_slot_summary[action.split("_")[1]]
                    top_prob = slot_summary['TOPHYPS'][0][1]
                    sec_prob = slot_summary['TOPHYPS'][1][1]
                    if top_prob == 0 or sec_prob == 0:
                        mask_action = True
                    if mask_action and self.request_mask:
                        nonexec.append(action)
    
                elif "confirm_" in action:
                    slot_summary = array_slot_summary[action.split("_")[1]]
                    top_prob = slot_summary['TOPHYPS'][0][1]
                    if top_prob == 0:
                        mask_action = True
                    if mask_action and self.request_mask:
                        nonexec.append(action)
    
                elif "confreq_" in action:
                    slot_summary = array_slot_summary[action.split("_")[1]]
                    top_prob = slot_summary['TOPHYPS'][0][1]
                    if top_prob == 0:
                        mask_action = True
                    if mask_action and self.request_mask:
                        nonexec.append(action)

        logger.dial('masked inform actions:' + str([act for act in nonexec if 'inform' in act]))
        return nonexec
Example #17
0
def getGlobalAction(belief, globalact, domainString):
    '''**Method for global action:** returns action 

    :param belief: full belief state
    :type belief: dict
    :param globalact: - str of globalActionName, e.g. 'INFORM_REQUESTED'
    :type globalact: int
    :param domainString: domain tag
    :type domainString: str
    :returns: (str) action
    '''

    # First get the name for the name goal.
    topvalue, topbelief = SummaryUtils.getTopBelief(belief['beliefs']['name'])
    toptwo, _ = SummaryUtils.getTopBeliefsExcludingNone(belief['beliefs']['name'])
    if topvalue == '**NONE**' or topvalue == 'dontcare' or topbelief < 0.8:
        topnamevalue = ''
    else:
        topnamevalue = toptwo[0][0]

    lastInformedVenue = belief['features']['lastInformedVenue']
    informedVenueSinceNone = belief['features']['informedVenueSinceNone']
    acceptanceList = SummaryUtils.getTopBeliefs(belief, domainString=domainString)
    inform_threshold = 0
    if Settings.config.has_option("policy", "informthreshold"):
        inform_threshold = float(Settings.config.get('policy','informthreshold'))
    if inform_threshold > 0:
        acceptanceList80 = SummaryUtils.getTopBeliefs(belief, inform_threshold, domainString=domainString)
    else:
        acceptanceList80 = acceptanceList
    requestedSlots = SummaryUtils.getRequestedSlots(belief)

    # logger.debug('topnamevalue = %s, lastInformedVenue = %s' % (topnamevalue, lastInformedVenue))
    if topnamevalue == '' and lastInformedVenue != '':
        # logger.debug('topnamevalue is None, but copy lastInformedVenue')
        topnamevalue = lastInformedVenue


    if globalact == 'INFORM_REQUESTED':
        if topnamevalue != '':
            return _getInformRequestedSlots(acceptanceList80, requestedSlots, topnamevalue, domainString)
        else:
            return _getInformRequestedSlots(acceptanceList80, requestedSlots, 'none', domainString)
    elif globalact == 'INFORM_ALTERNATIVES':
        #if lastInformedVenue == '':
        #    print 'Cant inform alternatives no last informed venue'
        #    return 'null()'
        #else:
        return _getInformAlternativeEntities(acceptanceList, acceptanceList80, informedVenueSinceNone, domainString)
    elif globalact == 'INFORM_MORE': #ic340: is this ever used?
        if len(informedVenueSinceNone) > 0 and topnamevalue != '':
            return _getInformMoreEntity(topnamevalue, domainString)
        else:
            return _getInformMoreEntity('none', domainString)
    elif globalact == 'INFORM_BYNAME':
        return _getInformAlternativeEntities(acceptanceList, acceptanceList80, [], domainString)
    elif globalact == 'INFORM_REPEAT':
        return 'null()'
    elif globalact == 'REQMORE':
        if lastInformedVenue != '':
            return 'reqmore()'
        else:
            return 'null()'
    elif globalact == 'BYE':
        return 'bye()'
    elif globalact == 'RESTART':
        return 'null()'
    else:
        logger.warning('Invalid global summary action name: ' + globalact)
        return 'null()'