def add_hcons(self, hcons): """ Incorporate the list of HandleConstraints given by *hcons*. """ # (hi, relation, lo) _vars = self._vars _hcons = self._hcons for hc in hcons: try: if not isinstance(hc, HandleConstraint): hc = HandleConstraint(*hc) except TypeError: raise XmrsError('Invalid HCONS data: {}'.format(repr(hc))) hi = hc.hi lo = hc.lo if hi in _hcons: raise XmrsError( 'Handle constraint already exists for hole %s.' % hi) _hcons[hi] = hc # the following should also ensure lo and hi are in _vars if 'hcrefs' not in _vars[lo]: _vars[lo]['hcrefs'] = [] for role, refs in _vars[hi]['refs'].items(): for nodeid in refs: _vars[lo]['hcrefs'].append((nodeid, role, hi))
def add_eps(self, eps): """ Incorporate the list of EPs given by *eps*. """ # (nodeid, pred, label, args, lnk, surface, base) _nodeids, _eps, _vars = self._nodeids, self._eps, self._vars for ep in eps: try: if not isinstance(ep, ElementaryPredication): ep = ElementaryPredication(*ep) except TypeError: raise XmrsError('Invalid EP data: {}'.format(repr(ep))) # eplen = len(ep) # if eplen < 3: # raise XmrsError( # 'EPs must have length >= 3: (nodeid, pred, label, ...)' # ) nodeid, lbl = ep.nodeid, ep.label if nodeid in _eps: raise XmrsError('EP already exists in Xmrs: {} ({})'.format( nodeid, ep[1])) _nodeids.append(nodeid) _eps[nodeid] = ep if lbl is not None: _vars[lbl]['refs']['LBL'].append(nodeid) for role, val in ep.args.items(): # if the val is not in _vars, it might still be a # variable; check with var_re if val in _vars or var_re.match(val): vardict = _vars[val] vardict['refs'][role].append(nodeid)
def is_connected(self): """ Return `True` if the Xmrs represents a connected graph. Subgraphs can be connected through things like arguments, QEQs, and label equalities. """ nids = set(self._nodeids) # the nids left to find if len(nids) == 0: raise XmrsError('Cannot compute connectedness of an empty Xmrs.') # build a basic dict graph of relations edges = [] # label connections for lbl in self.labels(): lblset = self.labelset(lbl) edges.extend((x, y) for x in lblset for y in lblset if x != y) # argument connections _vars = self._vars for nid in nids: for rarg, tgt in self.args(nid).items(): if tgt not in _vars: continue if IVARG_ROLE in _vars[tgt]['refs']: tgtnids = list(_vars[tgt]['refs'][IVARG_ROLE]) elif tgt in self._hcons: tgtnids = list(self.labelset(self.hcon(tgt)[2])) elif 'LBL' in _vars[tgt]['refs']: tgtnids = list(_vars[tgt]['refs']['LBL']) else: tgtnids = [] # connections are bidirectional edges.extend((nid, t) for t in tgtnids if nid != t) edges.extend((t, nid) for t in tgtnids if nid != t) g = {nid: set() for nid in nids} for x, y in edges: g[x].add(y) connected_nids = _bfs(g) if connected_nids == nids: return True elif connected_nids.difference(nids): raise XmrsError('Possibly bogus nodeids: {}'.format(', '.join( connected_nids.difference(nids)))) return False
def validate(self): """ Check that the Xmrs is well-formed. The Xmrs is analyzed and a list of problems is compiled. If any problems exist, an :exc:`XmrsError` is raised with the list joined as the error message. A well-formed Xmrs has the following properties: * All predications have an intrinsic variable * Every intrinsic variable belongs one predication and maybe one quantifier * Every predication has no more than one quantifier * All predications have a label * The graph of predications form a net (i.e. are connected). Connectivity can be established with variable arguments, QEQs, or label-equality. * The lo-handle for each QEQ must exist as the label of a predication """ errors = [] ivs, bvs = {}, {} _vars = self._vars _hcons = self._hcons labels = defaultdict(set) # ep_args = {} for ep in self.eps(): nid, lbl, args, is_q = (ep.nodeid, ep.label, ep.args, ep.is_quantifier()) if lbl is None: errors.append('EP ({}) is missing a label.'.format(nid)) labels[lbl].add(nid) iv = args.get(IVARG_ROLE) if iv is None: errors.append( 'EP {nid} is missing an intrinsic variable.'.format(nid)) if is_q: if iv in bvs: errors.append('{} is the bound variable for more than ' 'one quantifier.'.format(iv)) bvs[iv] = nid else: if iv in ivs: errors.append('{} is the intrinsic variable for more ' 'than one EP.'.format(iv)) ivs[iv] = nid # ep_args[nid] = args for hc in _hcons.values(): if hc[2] not in labels: errors.append('Lo variable of HCONS ({} {} {}) is not the ' 'label of any EP.'.format(*hc)) if not self.is_connected(): errors.append('Xmrs structure is not connected.') if errors: raise XmrsError('\n'.join(errors))
def add_icons(self, icons): """ Incorporate the individual constraints given by *icons*. """ _vars, _icons = self._vars, self._icons for ic in icons: try: if not isinstance(ic, IndividualConstraint): ic = IndividualConstraint(*ic) except TypeError: raise XmrsError('Invalid ICONS data: {}'.format(repr(ic))) left = ic.left right = ic.right if left not in _icons: _icons[left] = [] _icons[left].append(ic) # the following should also ensure left and right are in _vars if 'icrefs' not in _vars[right]: _vars[right]['icrefs'] = [] _vars[right]['icrefs'].append(ic) _vars[left] # just to instantiate if not done yet
def __init__(self, type, data): # class methods below use __new__ to instantiate data, so # don't do it here if type not in (Lnk.CHARSPAN, Lnk.CHARTSPAN, Lnk.TOKENS, Lnk.EDGE): raise XmrsError('Invalid Lnk type: {}'.format(type))