[hltdi-l3] push by onlysk...@gmail.com - L3Lite: variables and constraints for group selection and assignment o... on 2014-04-30 06:56 GMT

0 views
Skip to first unread message

hltd...@googlecode.com

unread,
Apr 30, 2014, 2:57:06 AM4/30/14
to hltdi-...@googlegroups.com
Revision: ae6a8f15bf6e
Branch: default
Author: Michael Gasser <gas...@cs.indiana.edu>
Date: Wed Apr 30 06:56:30 2014 UTC
Log: L3Lite: variables and constraints for group selection and
assignment of sentence nodes to group nodes
http://code.google.com/p/hltdi-l3/source/detail?r=ae6a8f15bf6e

Modified:
/l3lite/constraint.py
/l3lite/cs.py
/l3lite/sentence.py
/l3lite/variable.py
/lite.py

=======================================
--- /l3lite/constraint.py Sun Apr 27 18:07:59 2014 UTC
+++ /l3lite/constraint.py Wed Apr 30 06:56:30 2014 UTC
@@ -59,12 +59,12 @@
if record:
for var in variables:
if isinstance(var, DetVar):
- if problem:
- if var not in problem.detvarsD:
- problem.detvarsD[var] = []
- problem.detvarsD[var].append(self)
- else:
- var.constraints.append(self)
+ continue
+# if problem:
+# if var not in problem.vrs:
+# problem.vrs[var] = []
+# problem.vrs[var].append(self)
+ var.constraints.append(self)
self.name = ''

def __repr__(self):
@@ -1559,14 +1559,18 @@
selvar)
self.constraints = []
for sel, main in zip(selvars, mainvars):
- self.constraints.append(UnionSelection(main, sel, seqvars,
weight=1, maxset=None))
+ if not sel.get_upper():
+# print('Not creating UnionSelection constraint with empty
selvar')
+ self.constraints.append(None)
+ else:
+ self.constraints.append(UnionSelection(main, sel, seqvars,
weight=1, maxset=None))

def fails(self, dstore=None):
"""Fail if any of the UnionSelection constraints over the selvars
and mainvars indexed by the
lower bound of selvar fail."""
for index in self.selvar.get_lower(dstore=dstore):
constraint = self.constraints[index]
- if constraint.fails(dstore=dstore):
+ if constraint and constraint.fails(dstore=dstore):
return True
return False

@@ -1574,7 +1578,7 @@
"""Is entailed if all of the constraints indexed by the upper
bound of selvar are entailed."""
for index in self.selvar.get_upper(dstore=dstore):
constraint = self.constraints[index]
- if not constraint.is_entailed(dstore=dstore):
+ if constraint and not constraint.is_entailed(dstore=dstore):
return False
return True

@@ -1586,6 +1590,8 @@
selupper = selvar.get_upper(dstore=dstore)
sellower = selvar.get_lower(dstore=dstore)
for index, constraint in enumerate(self.constraints):
+ if not constraint:
+ continue
if index in sellower:
state, changed = constraint.infer(dstore=dstore)
# If any variable changed as a result this, return it
=======================================
--- /l3lite/cs.py Sun Apr 27 18:07:59 2014 UTC
+++ /l3lite/cs.py Wed Apr 30 06:56:30 2014 UTC
@@ -54,6 +54,7 @@
return "Solver {}".format(self.id)

def fixed_point(self, awaken):
+ print("Fixed point? len awaken: {}".format(len(awaken)))
if len(awaken) == 0:
# No more constraints are awake
if self.dstore.is_determined():
@@ -67,15 +68,24 @@
return False

def run(self, verbosity=0, tracevar=[]):
+ s = "Running {} with {} undetermined variables, {} constraints"
+ print(s.format(self, len(self.dstore.ess_undet),
len(self.constraints)))
awaken = set(self.constraints)
+ it = 0
while not self.fixed_point(awaken):
+ print("\nRunning iteration {}".format(it))
awaken = self.run_constraints(awaken, verbosity=verbosity,
tracevar=tracevar)
+ it += 1

def run_constraints(self, constraints, verbosity=0, tracevar=[]):
awaken = set()
+ all_changed = set()
for constraint in constraints:
+# print(" Running {}".format(constraint))
state, changed_vars = constraint.run(dstore=self.dstore,
verbosity=verbosity, tracevar=tracevar)
+ all_changed.update(changed_vars)
if state == Constraint.entailed:
+# print(" Entailed")
# Constraint is entailed; add it to the list of those.
self.entailed.append(constraint)
# Delete it from awaken if it's already there
@@ -90,16 +100,17 @@
var.determined(dstore=self.dstore,
verbosity=verbosity)
except VarError:
if verbosity:
- print("{} CAN'T BE DETERMINED, SO {} MUST
FAIL".format(var, propagator))
+ print("{} CAN'T BE DETERMINED, SO {} MUST
FAIL".format(var, constraint))
state = Constraint.failed
break

if state == Constraint.failed:
+ print("FAILED {}!".format(constraint))
# constraint fails; remove it from the entailed or awaken
lists if it's there
if constraint in self.entailed:
self.entailed.remove(constraint)
if constraint in awaken:
- awaken.remove(propagator)
+ awaken.remove(constraint)
# # penalize the CSpace
# self.penalty += constraint.weight
# and remember that it failed
@@ -114,13 +125,16 @@

# If the constraint succeeds, add the constraints of its
variables to awaken
if state not in [Constraint.failed]:
+# print(" Awakening, # changed vars
{}".format(len(changed_vars)))
for var in changed_vars:
- update_cons = {p for p in var.constraints if p not in
self.entailed and p not in self.failed}
+ # Add constraints for changed var to awaken unless
those constraints are already entailed
+ # or failed
+ update_cons = {c for c in var.constraints if c not in
self.entailed and c not in self.failed}
+# print(" Awakening {} constraints for
{}".format(len(update_cons), var))
if var == tracevar and verbosity:
print('Adding {} constraints for changed variable
{}'.format(len(update_cons), tracevar))
- # Add constraints for changed var to awaken unless
those constraints are already entailed
- # or failed
awaken.update(update_cons)
# print('update cons {}'.format(update_cons))
+ print('# changed vars {}'.format(len(all_changed)))
return awaken

=======================================
--- /l3lite/sentence.py Sun Apr 27 18:07:59 2014 UTC
+++ /l3lite/sentence.py Wed Apr 30 06:56:30 2014 UTC
@@ -30,6 +30,10 @@
# -- Group matching. GInst, GNode, and SNode classes.
# 2014.04.22
# -- Solution class.
+# 2014.04.26-7
+# -- Translation class and realization.
+# 2014.04.28
+# -- Variables for sentence analysis.

import itertools
# ui.py loads language, etc.
@@ -49,24 +53,24 @@
self.set_id()
# A string representing the raw sentence
self.raw = raw
-# # A list of strings tokenized words (or morphemes)
-# self.tokens = tokens or []
-# # A list of analyses pairs (root, features) for particular tokens
-# self.analyses = analyses or []
# Source language: a language object
self.language = language
# Target language: a language object
self.target = target
# A list of SNode objects, one for each token
self.nodes = nodes or []
- # A list of candidate groups found during lexicalization
+ # A list of candidate groups (realized as GInst objects) found
during lexicalization
self.groups = groups or []
+ # GNodes in GInsts
+ self.gnodes = []
# A list of constraints to run
self.constraints = []
# Root domain store for variables
self.dstore = DStore(name="S{}".format(self.id))
# A dict of sentence-level variables
self.variables = {}
+ # Solver to find solutions
+ self.solver = Solver(self.constraints, self.dstore)
# Solutions found during parsing
self.solutions = []

@@ -87,8 +91,11 @@
self.lexicalize()
if not self.groups:
print("No groups found for {}".format(self))
+ return False
else:
self.create_variables()
+ self.create_constraints()
+ return True

def tokenize(self):
"""Segment the sentence string into tokens, analyze them
morphologically,
@@ -158,7 +165,6 @@
# Create a GInst object and GNodes for each surviving group
self.groups = [GInst(group, self, head_i, snodes, index) for
index, (head_i, snodes, group) in enumerate(groups)]
# Assign sentence-level indices to each GNode; store gnodes in list
- self.gnodes = []
sent_index = 0
for group in self.groups:
for gnode in group.nodes:
@@ -168,6 +174,15 @@
# Number of GNodes
self.ngnodes = sent_index

+ ## Create IVars and (set) Vars with sentence DS as root DS
+
+ def ivar(self, name, domain):
+ self.variables[name] = IVar(name, domain, rootDS=self.dstore)
+
+ def svar(self, name, lower, upper, lower_card=0, upper_card=MAX):
+ self.variables[name] = Var(name, lower, upper, lower_card,
upper_card,
+ rootDS=self.dstore)
+
def create_variables(self):
# All abstract (category) and instance (word or lexeme) gnodes
catnodes = set()
@@ -184,21 +199,153 @@
gn = self.gnodes[gn_index]
merged_snodes.update(gn.snode_indices)

- self.variables['groups'] = Var('groups', set(),
set(range(len(self.groups))),
- # At least 1, at most all groups
- 1, len(self.groups))
- self.variables['gnodes'] = Var('gnodes', set(),
set(range(self.ngnodes)),
- # At least size of smallest group,
at most all
- min([len(g.nodes) for g in
self.groups]),
- self.ngnodes)
+ self.svar('groups', set(), set(range(len(self.groups))),
+ # At least 1, at most all groups
+ 1, len(self.groups))
+ self.svar('gnodes', set(), set(range(self.ngnodes)),
+ # At least size of smallest group, at most all
+ min([len(g.nodes) for g in self.groups]),
+ self.ngnodes)
self.variables['snodes'] = DetVar('snodes',
set(range(len(self.nodes))))
- self.variables['catgnodes'] = Var('catgnodes', set(), catnodes)
+ # Category (abstract) nodes
+ self.svar('catgnodes', set(), catnodes)
# Instance gnodes that are merged with catnodes
- self.variables['merged_gnodes'] = Var('merged_gnodes', set(),
instnodes,
- 0, len(catnodes))
+ self.svar('merged_gnodes', set(), instnodes, 0, len(catnodes))
# Snodes that involve merger of gnodes (that have two associated
gnodes)
- self.variables['merged_snodes'] = Var('merged_snodes', set(),
merged_snodes,
- 0, len(catnodes))
+ self.svar('merged_snodes', set(), merged_snodes, 0, len(catnodes))
+ # Position pairs
+ pos_pairs = set()
+ for group in self.groups:
+ pos_pairs.update(group.pos_pairs())
+ self.svar('gnode_pos', set(), pos_pairs)
+ ## Create variables for SNodes, GInsts, and GNodes
+ for snode in self.nodes:
+ snode.create_variables()
+ for ginst in self.groups:
+ ginst.create_variables()
+ for gnode in self.gnodes:
+ gnode.create_variables()
+
+ def create_constraints(self):
+ # Relation among abstract, concrete, and all gnodes for each snode
+ for snode in self.nodes:
+ self.constraints.extend(Union([snode.variables['gnodes'],
+ snode.variables['cgnodes'],
+
snode.variables['agnodes']]).constraints)
+ # Constraints involved groups with category (abstract) nodes
+ for group in self.groups:
+ if group.nanodes > 0:
+ # Only do this for groups with abstract nodes
+ # For each group, the set of snodes is the union of the
concrete and abstract nodes
+
self.constraints.extend(Union([group.variables['gnodes_pos'],
+
group.variables['agnodes_pos'],
+
group.variables['cgnodes_pos']]).constraints)
+ # For each group, the set of groups merged with it +
itself is the union of the
+ # set of groups merged with it and the set consisting of
its index
+
self.constraints.extend(Union([group.variables['merged_groups_incl'],
+
group.variables['merged_groups_excl'],
+
DetVar('g{}'.format(group.index), {group.index})]).constraints)
+ # The set of merged gnodes for the group is the union of
the merged nodes for all
+ # abstract gnodes in the group
+
self.constraints.append(UnionSelection(group.variables['merged_gnodes'],
+
group.variables['agnodes'],
+
[gn.variables['merge_cgn'] for gn in self.gnodes]))
+ # The set of groups merged with the group is the union of
groups associated with the
+ # gnodes that are merged with the group's abstract nodes
+
self.constraints.append(UnionSelection(group.variables['merged_groups_excl'],
+
group.variables['merged_gnodes'],
+
[DetIVar("gn{}->g".format(gn.sent_index), gn.ginst.index) for gn in
self.gnodes]))
+ # The tree under this group consists of the union of the
snodes associated with this group
+ # and those merged with it
+
self.constraints.append(UnionSelection(group.variables['tree'],
+
group.variables['merged_groups_incl'],
+
[g.variables['gnodes_pos'] for g in self.groups]))
+ for gnode in group.nodes:
+ if gnode.cat:
+ # The gnodes that this abstract merges with must
be in the set of selected gnodes
+
self.constraints.extend(Inclusion([gnode.variables['merge_cgn'],
+
self.variables['gnodes']]).constraints)
+ # The set of category (abstract) nodes used is the union of the
category nodes of the groups used
+ self.constraints.append(UnionSelection(self.variables['catgnodes'],
+ self.variables['groups'],
+ [g.variables['agnodes'] for
g in self.groups]))
+ # The set of merged gnodes used is the union of the merged nodes
of the selected category nodes
+
self.constraints.append(UnionSelection(self.variables['merged_gnodes'],
+ self.variables['catgnodes'],
+ [gn.variables['merge_cgn']
for gn in self.gnodes]))
+ # The set of merged gnodes used is the union of the merged gnodes
of all merging snodes
+
self.constraints.append(UnionSelection(self.variables['merged_gnodes'],
+
self.variables['merged_snodes'],
+ [sn.variables['mgnodes']
for sn in self.nodes]))
+ # The set of category gnodes used is the union of the category
nodes associated with all merged snodes
+ self.constraints.append(UnionSelection(self.variables['catgnodes'],
+
self.variables['merged_snodes'],
+ [sn.variables['agnodes']
for sn in self.nodes]))
+ # The set of category gnodes used is the union of the category
nodes associated with all merged gnodes
+ self.constraints.append(UnionSelection(self.variables['catgnodes'],
+
self.variables['merged_gnodes'],
+ [gn.variables['merge_agn']
for gn in self.gnodes]))
+ # The set of merged snodes used is the union of the snodes
associated with all category nodes used
+
self.constraints.append(UnionSelection(self.variables['merged_snodes'],
+ self.variables['catgnodes'],
+ [gn.variables['merge_cw']
for gn in self.gnodes]))
+ # The set of merged snodes used is the union of the snodes
associated with all merged gnodes
+
self.constraints.append(UnionSelection(self.variables['merged_snodes'],
+
self.variables['merged_gnodes'],
+ [gn.variables['merge_aw']
for gn in self.gnodes]))
+ # The set of merged gnodes must be a subset of the set of used
gnodes
+ self.constraints.extend(Inclusion([self.variables['merged_gnodes'],
+
self.variables['gnodes']]).constraints)
+ # All snodes must have distinct category nodes
+ self.constraints.extend(Disjoint([sn.variables['agnodes'] for sn
in self.nodes]).constraints)
+ # All concrete gnodes must have distinct category nodes
+ self.constraints.extend(Disjoint([gn.variables['merge_agn'] for gn
in self.gnodes]).constraints)
+ # All position constraints for snodes
+
self.constraints.append(PrecedenceSelection(self.variables['gnode_pos'],
+
[gn.variables['snodes'] for gn in self.gnodes]))
+ # Position constraint pairs are the group position pairs for all
groups used
+ self.constraints.append(UnionSelection(self.variables['gnode_pos'],
+ self.variables['groups'],
+
[DetVar("g{}pos".format(g.index), g.pos_pairs()) for g in self.groups]))
+ # Union selection on gnodes for each snode:
+ # the union of the snode indices associated with the gnodes of an
snode is the snode's index
+ gn2s = [gn.variables['snodes'] for gn in self.gnodes]
+ s2gn = [s.variables['gnodes'] for s in self.nodes]
+ for snode in self.nodes:
+
self.constraints.append(UnionSelection(DetVar("sn{}".format(snode.index),
{snode.index}),
+
snode.variables['gnodes'],
+ gn2s))
+ # Union of all gnodes used for snodes is all gnodes used
+ self.constraints.append(UnionSelection(self.variables['gnodes'],
+ self.variables['snodes'],
+ s2gn))
+ # Union of all gnodes for groups used is all gnodes used
+ self.constraints.append(UnionSelection(self.variables['gnodes'],
+ self.variables['groups'],
+ [g.variables['gnodes'] for
g in self.groups]))
+ # Union of all snodes for gnodes used is all snodes
+ self.constraints.append(UnionSelection(self.variables['snodes'],
+ self.variables['gnodes'],
+ [gn.variables['snodes'] for
gn in self.gnodes]))
+ # Complex union selection by groups on positions of all concrete
gnodes in each selected group
+
self.constraints.append(ComplexUnionSelection(selvar=self.variables['groups'],
+
selvars=[g.variables['cgnodes_pos'] for g in self.groups],
+
seqvars=[s.variables['cgnodes'] for s in self.nodes],
+
mainvars=[g.variables['cgnodes'] for g in self.groups]))
+ # Complex union selection by groups on positions of all category
gnodes in each selected group
+
self.constraints.append(ComplexUnionSelection(selvar=self.variables['groups'],
+
selvars=[g.variables['agnodes_pos'] for g in self.groups],
+
seqvars=[s.variables['agnodes'] for s in self.nodes],
+
mainvars=[g.variables['agnodes'] for g in self.groups]))
+ # Set convexity (projectivity) within each group tree
+
self.constraints.append(ComplexSetConvexity(self.variables['groups'],
+ [g.variables['tree']
for g in self.groups]))
+
+
+ def run(self):
+ """Run constraint satisfaction on constraints, for now without
search if
+ no solution is found."""
+ self.solver.run()

def make_solution(self, ginsts, s2gnodes, g2snodes):
self.solutions.append(Solution(self, ginsts, s2gnodes, g2snodes,
@@ -229,8 +376,32 @@
"""Print name."""
return "*{}:{}".format(self.token, self.index)

+ ## Create IVars and (set) Vars with sentence DS as root DS
+
+ def ivar(self, key, name, domain):
+ self.variables[key] = IVar(name, domain,
rootDS=self.sentence.dstore)
+
+ def svar(self, key, name, lower, upper, lower_card=0, upper_card=MAX):
+ self.variables[key] = Var(name, lower, upper, lower_card,
upper_card,
+ rootDS=self.sentence.dstore)
+
def create_variables(self):
- pass
+ # GNodes associated with this SNode: 0, 1, or 2
+ self.svar('gnodes', "w{}->gn".format(self.index), set(),
+ set(range(self.sentence.ngnodes)),
+ 0, 2)
+ # Concrete GNodes associated with this SNode: 0 or 1
+ self.svar('cgnodes', "w{}->cgn".format(self.index), set(),
+ set(range(self.sentence.ngnodes)),
+ 0, 1)
+ # Abstract GNodes associated with this SNode: 0 or 1
+ self.svar('agnodes', "w{}->agn".format(self.index), set(),
+ set(range(self.sentence.ngnodes)),
+ 0, 1)
+ # Merged concrete GNodes associated with this SNode: 0 or 1
+ self.svar('mgnodes', "w{}->mgn".format(self.index), set(),
+ set(range(self.sentence.ngnodes)),
+ 0, 1)

def get_cats(self):
"""The set of categories for the node's token, or None."""
@@ -307,13 +478,85 @@
self.variables = {}
# List of target language groups
self.translations = []
+ self.ngnodes = len(self.nodes)
+ # Number of abstract nodes
+ self.nanodes = len([n for n in self.nodes if n.cat])
+ # Number of concrete nodes
+ self.ncgnodes = self.ngnodes - self.nanodes

def __repr__(self):
return '<<{}:{}>>'.format(self.group.name, self.group.id)

- def create_variables(self):
- pass
+ def pos_pairs(self):
+ """Return position constraint pairs for gnodes in the group."""
+ gnode_pos = [gn.sent_index for gn in self.nodes]
+ return set(itertools.combinations(gnode_pos, 2))

+ ## Create IVars and (set) Vars with sentence DS as root DS
+
+ def ivar(self, key, name, domain):
+ self.variables[key] = IVar(name, domain,
rootDS=self.sentence.dstore)
+
+ def svar(self, key, name, lower, upper, lower_card=0, upper_card=MAX):
+ self.variables[key] = Var(name, lower, upper, lower_card,
upper_card,
+ rootDS=self.sentence.dstore)
+
+ def create_variables(self):
+# ngnodes = len(self.nodes)
+# ncgnodes = len([n for n in self.nodes if not n.cat])
+ ngroups = len(self.sentence.groups)
+ nsnodes = len(self.sentence.nodes)
+# nanodes = ngnodes - ncgnodes
+ # GNode indices for this GInst (determined)
+ self.variables['gnodes'] =
DetVar('g{}->gnodes'.format(self.index), {gn.sent_index for gn in
self.nodes})
+ # Abstract GNode indices for GInst (determined)
+ if self.nanodes:
+ self.variables['agnodes'] =
DetVar('g{}->agnodes'.format(self.index), {gn.sent_index for gn in
self.nodes if gn.cat})
+ # Concrete GNode indices for GInst (determined)
+ self.variables['cgnodes'] =
DetVar('g{}->cgnodes'.format(self.index), {gn.sent_index for gn in
self.nodes if not gn.cat})
+ else:
+ self.variables['agnodes'] = EMPTY
+ self.variables['cgnodes'] = self.variables['gnodes']
+ # SNode positions of GNodes for this GInst
+ self.svar('gnodes_pos', 'g{}->gnodes_pos'.format(self.index),
+ set(), set(range(nsnodes)), self.ngnodes, self.ngnodes)
+ # SNode positions of abstract GNodes for this GInst
+ if self.nanodes == 0:
+ # No abstract nodes
+ self.variables['agnodes_pos'] = EMPTY
+ # SNode positions of concrete GNodes for this GInst
+ self.variables['cgnodes_pos'] = self.variables['gnodes_pos']
+ else:
+ # Position for each abstract node in the group
+ self.svar('agnodes_pos', 'g{}->agnodes_pos'.format(self.index),
+ set(), set(range(nsnodes)), self.nanodes,
self.nanodes)
+ # Position for each concrete node in the group
+ self.svar('cgnodes_pos', 'g{}->cgnodes_pos'.format(self.index),
+ set(), set(range(nsnodes)), self.ncgnodes,
self.ncgnodes)
+ # Other GInsts merged with this one, excluding and including itself
+ if self.nanodes == 0:
+ # No abstract nodes, so this is a determined variable with one
value (its own index)
+ self.variables['merged_groups_incl'] =
DetVar('g{}->mgroups_in'.format(self.index), {self.index})
+ self.variables['merged_groups_excl'] = EMPTY
+ self.variables['merged_gnodes'] = EMPTY
+ else:
+
self.svar('merged_groups_incl', 'g{}->mgroups_in'.format(self.index),
+ {self.index}, set(range(ngroups)), 1, self.nanodes+1)
+
self.svar('merged_groups_excl', 'g{}->mgroups_ex'.format(self.index),
+ set(), set(range(ngroups)) - {self.index}, 0,
self.nanodes)
+ # Set of all gnodes that are merged with abstract gnodes in
this group
+ # upper bound is all gnodes not in this group
+ self.svar('merged_gnodes', 'g{}->mgnodes'.format(self.index),
+ set(), set(range(len(self.sentence.gnodes))) -
{gn.sent_index for gn in self.nodes})
+ # Trees under GInst head (including self)
+ if self.nanodes == 0:
+ # No abstract gnodes, so same as gnodes
+ self.variables['tree'] = self.variables['gnodes_pos']
+ else:
+ self.svar('tree', 'g{}->tree'.format(self.index),
+ # at least as long as the number of self's nodes
+ set(), set(range(nsnodes)), self.ngnodes, nsnodes)
+
def set_translations(self):
"""Find the translations of the group in the target language."""
translations = self.group.get_translations(self.target.abbrev,
False)
@@ -353,24 +596,7 @@
token = tokens[targ_index]
feats = features[targ_index] if features else None
gnodes.append((gnode, token, feats, agrs, targ_index))
- # Copy this information??
-# gnode.translations.append((token, feats, agrs,
targ_index))
self.translations.append((tgroup, gnodes, tnodes))
- # Assign corresponding translations to gnodes
-# for gn_index, gnode in enumerate(self.nodes):
-# for tgroup, alignment, tnodes in self.translations:
-# # Align gnodes with target tokens and features
-# tokens = tgroup.tokens
-# features = tgroup.features
-# targ_index = alignment['alg'][gn_index]
-# agrs = alignment['agr'][gn_index] if 'agr' in alignment
else None
-# if targ_index < 0:
-# # This means there's no target language token
-# continue
-# token = tokens[targ_index]
-# feats = features[targ_index] if features else None
-# gnode.translations.append((token, feats, agrs,
targ_index))
-

class GNode:

@@ -379,6 +605,7 @@
def __init__(self, ginst, index, snodes):
self.ginst = ginst
self.index = index
+ self.sentence = ginst.sentence
self.snode_indices = [s[0] for s in snodes]
self.snode_anal = [s[1] for s in snodes]
# Whether this is the head of the group
@@ -393,14 +620,47 @@
self.features = groupfeats[index]
else:
self.features = None
+ self.variables = {}
# List of target-language token and features associated with this
gnode
# self.translations = []

def __repr__(self):
return "{}|{}".format(self.ginst, self.token)

+ ## Create IVars and (set) Vars with sentence DS as root DS
+
+ def ivar(self, key, name, domain):
+ self.variables[key] = IVar(name, domain,
rootDS=self.sentence.dstore)
+
+ def svar(self, key, name, lower, upper, lower_card=0, upper_card=MAX):
+ self.variables[key] = Var(name, lower, upper, lower_card,
upper_card,
+ rootDS=self.sentence.dstore)
+
def create_variables(self):
- pass
+ nsnodes = len(self.sentence.nodes)
+ # SNode index for this GNode
+ self.ivar('snodes', "gn{}->w".format(self.sent_index),
set(self.snode_indices))
+ if self.cat:
+ # Concrete nodes merged with this abstract node
+ self.svar('merge_cgn', 'gn{}_cgmerge'.format(self.sent_index),
+ set(), {gn.sent_index for gn in self.sentence.gnodes
if not gn.cat},
+ 0, 1)
+ self.svar('merge_cw', 'gn{}_cwmerge'.format(self.sent_index),
+ set(), set(range(nsnodes)),
+ 0, 1)
+ self.variables['merge_agn'] = EMPTY
+ self.variables['merge_aw'] = EMPTY
+ else:
+ # Abstract nodes merged with this concrete node
+ self.svar('merge_agn', 'gn{}_agmerge'.format(self.sent_index),
+ # indices of all abstract nodes
+ set(), {gn.sent_index for gn in self.sentence.gnodes
if gn.cat},
+ 0, 1)
+ self.svar('merge_aw', 'gn{}_awmerge'.format(self.sent_index),
+ set(), set(range(nsnodes)),
+ 0, 1)
+ self.variables['merge_cgn'] = EMPTY
+ self.variables['merge_cw'] = EMPTY

class TNode:

@@ -440,7 +700,8 @@
self.index = index
# A list of pairs for each snode: (gnodes, features)
self.snodes = []
- # List of Translation objects
+ # List of Translation objects; multiple translations are possible
+ # for a given solution because of multiple translations for groups
self.translations = []

def __repr__(self):
@@ -461,6 +722,7 @@
for translation in translations:
t = Translation(self, translation, index)
t.initialize()
+ t.realize()
self.translations.append(t)
index += 1

@@ -555,6 +817,8 @@
self.constraints = []
# Translation needs a solver to figure out positions of words
self.solver = Solver(self.constraints, self.dstore)
+ # Final output
+ self.output = None

def __repr__(self):
return "{}[{}] ->".format(self.solution, self.index)
@@ -661,3 +925,16 @@
self.constraints.append(SetPrecedence([self.variables[first],
self.variables[second]]))
self.constraints.extend(Disjoint(self.variables).constraints)

+ def realize(self):
+ """Run constraint satisfaction on the order and disjunction
constraints,
+ and convert variable values to sentence positions."""
+ # Run constraint satisfaction on the constraints until all
variables are
+ # determined or nothing happes to the constraints
+ self.solver.run()
+ if self.solver.status == Solver.succeeded:
+ # No more awake constraints and no undetermined variables; get
positions from
+ # variable values
+ positions = [list(v.get_value(dstore=self.dstore))[0] for v in
self.variables]
+ node_pos = list(zip([n[0] for n in self.nodes], positions))
+ node_pos.sort(key=lambda x: x[1])
+ self.output = [n[0] for n in node_pos]
=======================================
--- /l3lite/variable.py Sun Apr 27 18:07:59 2014 UTC
+++ /l3lite/variable.py Wed Apr 30 06:56:30 2014 UTC
@@ -57,13 +57,13 @@
"""Are all variables in dstore determined that need to be
determined?"""
if essential:
if self.ess_undet:
+ print('{} has {} undetermined variables'.format(self,
len(self.ess_undet)))
return False
else:
- print('{} has {} undetermined variables'.format(self,
len(self.ess_undet)))
+ return True
elif self.undetermined:
+ print('{} has {} undetermined variables'.format(self,
len(self.undetermined)))
return False
- else:
- print('{} has {} undetermined variables'.format(self,
len(self.undetermined)))
return True

def clone(self, constraint=None, name='', project=False, verbosity=0):
@@ -98,8 +98,8 @@
weight=1):
self.name = name
self.problem = problem
- if problem:
- self.problem.add_variable(self)
+# if problem:
+# self.problem.add_variable(self)
self.constraints = [constraint] if constraint else []
self.essential = essential
self.value = None
@@ -331,7 +331,7 @@
self.set_value(value, dstore=dstore)
self.set_lower_card(val_card, dstore=dstore)
self.set_upper_card(val_card, dstore=dstore)
- if self in dstore.undetermined:
+ if dstore and self in dstore.undetermined:
self.det_update(dstore)
if orig_upper != value or orig_lower != value:
return True
@@ -368,14 +368,14 @@
self.set_value(lower, dstore=dstore)
self.set_lower_card(val_len, dstore=dstore)
self.set_upper_card(val_len, dstore=dstore)
- if self in dstore.undetermined:
+ if dstore and self in dstore.undetermined:
self.det_update(dstore)
elif len(new_upper) == lower_card:
val_len = lower_card
self.set_lower(new_upper, dstore=dstore)
self.set_value(new_upper, dstore=dstore)
self.set_upper_card(val_len, dstore=dstore)
- if self in dstore.undetermined:
+ if dstore and self in dstore.undetermined:
self.det_update(dstore)
return True
return False
@@ -422,7 +422,7 @@
if det:
if new_lower == upper and upper_card ==
self.lower_card(dstore=dstore):
self.set_value(upper, dstore=dstore)
- if self in dstore.undetermined:
+ if dstore and self in dstore.undetermined:
self.det_update(dstore)
return True
return False
@@ -441,7 +441,7 @@
# Determine
self.set_lower(upper, dstore=dstore)
self.set_value(upper, dstore=dstore)
- if self in dstore.undetermined:
+ if dstore and self in dstore.undetermined:
self.det_update(dstore)
return True
return False
@@ -460,7 +460,7 @@
# Determine
self.set_upper(lower, dstore=dstore)
self.set_value(lower, dstore=dstore)
- if self in dstore.undetermined:
+ if dstore and self in dstore.undetermined:
self.det_update(dstore)
return True
return False
=======================================
--- /lite.py Sun Apr 27 18:07:59 2014 UTC
+++ /lite.py Wed Apr 30 06:56:30 2014 UTC
@@ -47,8 +47,9 @@
amh, orm = l3lite.Language.load('amh', 'orm')
ss = l3lite.Sentence(raw="አሳ በልቶ አያውቅም", language=amh, target=orm)
ss.initialize()
- ss.make_solution(ss.groups, [{0, 1}, {2, 3}, {4}], [0, 0, 1, 1, 2])
- return ss.solutions[0]
+# ss.make_solution(ss.groups, [{0, 1}, {2, 3}, {4}], [0, 0, 1, 1, 2])
+# return ss.solutions[0]
+ return ss

def order():
constraints = [(0,1), (1,2), (1,3), (3,2)]
@@ -145,104 +146,7 @@
e, s = l3lite.Language("English", 'eng'),
l3lite.Language("español", 'spa')
return u, e, s

-##def t1():
-## # broke the window
-## g0_nodes = {0, 1, 2}
-## # the boy
-## g1_nodes = {3, 4}
-## # the window
-## g2_nodes = {5, 6}
-## # broke
-## g3_nodes = {7}
-## # .
-## g4_nodes = {8}
-## # the window broke
-## g5_nodes = {9, 10, 11}
-## # the boy broke the window .
-## w = {0, 1, 2, 3, 4, 5}
-## g = {0, 1, 2, 3, 4, 5}
-## w2gnodes = [l3lite.IVar('the0', {1, 3, 5, 9}), # {3}
-## l3lite.DetIVar('boy', 4),
-## l3lite.IVar('broke', {0, 7, 11}), # {0, 7}
-## l3lite.IVar('the3', {1, 3, 5, 9}), # {1, 5}
-## l3lite.IVar('window', {2, 6, 10}), # {2, 6}
-## l3lite.DetIVar('.', 8)]
-## groups = l3lite.Var('groups', set(), g, 2, 6)
-## gdetvars = [l3lite.DetVar('g0', {0, 1, 2}),
-## l3lite.DetVar('g1', {3, 4}),
-## l3lite.DetVar('g2', {5, 6}),
-## l3lite.DetVar('g3', {7}),
-## l3lite.DetVar('g4', {8}),
-## l3lite.DetVar('g5', {9, 10, 11})]
-## nodes = l3lite.DetVar('nodes', w)
-## ## Union selection on the gnodes of all words
-## # Union of all group nodes used
-## gnodeU = l3lite.Var('gnodeU', set(),
-## {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 6, 6)
-## w_usel = l3lite.UnionSelection(gnodeU, nodes, w2gnodes)
-## ## Union selection on the gnodes of all groups
-## g_usel = l3lite.UnionSelection(gnodeU, groups, gdetvars)
-## ## Position constraints
-## # Positions (word indices) of gnodes
-## # Group 0
-## gno0 = l3lite.DetIVar('gno0', 2) #broke
-## gno1 = l3lite.IVar('gno1', {0, 3}) #the {3}
-## gno2 = l3lite.DetIVar('gno2', 4) #window
-## # Group 1
-## gno3 = l3lite.IVar('gno3', {0, 3}) #the {0}
-## gno4 = l3lite.DetIVar('gno4', 1) #boy
-## # Group 2
-## gno5 = l3lite.IVar('gno5', {0, 3}) #the {3}
-## gno6 = l3lite.DetIVar('gno6', 4) #window
-## # Group 3
-## gno7 = l3lite.DetIVar('gno7', 2) #broke
-## # Group 4
-## gno8 = l3lite.DetIVar('gno8', 5) #.
-## # Group 5 (impossible)
-## gno9 = l3lite.IVar('gno9', {0, 3}) #the
-## gno10 = l3lite.DetIVar('gno10', 4) #window
-## gno11 = l3lite.DetIVar('gno11', 2) #broke
-## # Position pair constraints
-## gposcons = l3lite.Var('gposcons', set(),
-## {(0, 1), (1, 2), (0, 2), (3, 4), (5, 6),
-## (9, 10), (10, 11), (9, 11)})
-## # Precedence selection
-## precsel = l3lite.PrecedenceSelection(gposcons,
-## [gno0, gno1, gno2, gno3, gno4,
gno5,
-## gno6, gno7, gno8, gno9, gno10,
gno11])
-## # Union selection on position pair constraints
-## gp0 = l3lite.DetVar('gp0', {(0, 1), (1, 2), (0, 2)})
-## gp1 = l3lite.DetVar('gp1', {(3, 4)})
-## gp2 = l3lite.DetVar('gp2', {(5, 6)})
-## gp3 = l3lite.DetVar('gp3', set())
-## gp4 = l3lite.DetVar('gp4', set())
-## gp5 = l3lite.DetVar('gp5', {(9, 10), (10, 11), (9, 11)})
-## gpos = [gp0, gp1, gp2, gp3, gp4, gp5]
-## gp_usel = l3lite.UnionSelection(gposcons, groups, gpos)
-## ## Projectivity
-## # Positions of gnodes in each group
-## g0snode = l3lite.Var('g0snode', set(), {0, 1, 2, 3, 4}, 3, 3) # {2,
3, 4}
-## g1snode = l3lite.Var('g1snode', set(), {0, 1, 2, 3, 4}, 2, 2) # {0,
1}
-## g2snode = l3lite.Var('g2snode', set(), {0, 1, 2, 3, 4}, 2, 2) # {3,
4}
-## g3snode = l3lite.DetIVar('g3snode', 2) # {2}
-## g4snode = l3lite.DetIVar('g4snode', 5) # {5}
-## g5snode = l3lite.Var('g5snode', set(), {0, 1, 2, 3, 4}, 3, 3) #
impossible
-## # Set convexity constraint for each of these
-## setconv = l3lite.ComplexSetConvexity(groups, [g0snode, g1snode,
g2snode,
-## g3snode, g4snode,
g5snode])
-## ## ComplexUnionSelection
-## ## mainvars: [{0, 1, 2}, {3, 4}, ...]
-## ## selvars: [g0snode, g1snode, ...]
-## ## seqvars: w2gnodes
-## ## selvar: groups
-## complexU = l3lite.ComplexUnionSelection(selvar=groups,
-## selvars=[g0snode, g1snode,
g2snode, g3snode,
-## g4snode, g5snode],
-## seqvars=w2gnodes,
-## mainvars=gdetvars)
-## return w_usel, g_usel, precsel, gp_usel, setconv, complexU
-
-def t2():
+def t1():
constraints = []
## Groups
# 0: read(0) %sbd(1) the(2) riot(3) act(4)
@@ -253,7 +157,8 @@
# 5: the(12) riot(13)
# 6: .(14)
groups = l3lite.Var('groups', set(), {0, 1, 2, 3, 4, 5, 6}, 2, 7)
- ## Group node indices
+ ### Group node indices
+ ## All GNodes
gdetvars = [l3lite.DetVar('g0', {0, 1, 2, 3, 4}), # 1 is abstract
l3lite.DetVar('g1', {5, 6}), # 6 is abstract
l3lite.DetVar('g2', {7, 8}),
@@ -261,7 +166,7 @@
l3lite.DetVar('g4', {10, 11}),
l3lite.DetVar('g5', {12, 13}),
l3lite.DetVar('g6', {14})]
- ## Concrete group node indices
+ ## Concrete GNodes
gc_detvars = [l3lite.DetVar('g0', {0, 2, 3, 4}), # 1 is abstract
l3lite.DetVar('g1', {5}), # 6 is abstract
l3lite.DetVar('g2', {7, 8}),
@@ -269,7 +174,11 @@
l3lite.DetVar('g4', {10, 11}),
l3lite.DetVar('g5', {12, 13}),
l3lite.DetVar('g6', {14})]
- ## Words
+ ## Abstract GNodes
+ ga_detvars = [l3lite.DetVar('g0', {1}),
+ l3lite.DetVar('g1', {6}),
+ l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY,
l3lite.EMPTY]
+ ## Words (SNodes)
sentence = ['the', 'boy', 'read', 'us', 'the', 'riot', 'act']
## Word positions associated with group nodes (what about unused
gnodes?)
gn0w = l3lite.DetIVar('gn0w', 2)
@@ -288,6 +197,18 @@
gn13w = l3lite.DetIVar('gn13w', 5)
gn14w = l3lite.DetIVar('gn14w', 7)
gn_w = [gn0w, gn1w, gn2w, gn3w, gn4w, gn5w, gn6w, gn7w, gn8w, gn9w,
gn10w, gn11w, gn12w, gn13w, gn14w]
+ ## Groups associated with group nodes
+ gn_g = [l3lite.DetIVar('gn0_g', 0),
+ l3lite.DetIVar('gn1_g', 0),
+ l3lite.DetIVar('gn2_g', 0),
+ l3lite.DetIVar('gn3_g', 0),
+ l3lite.DetIVar('gn4_g', 0),
+ l3lite.DetIVar('gn5_g', 1), l3lite.DetIVar('gn6_g', 1),
+ l3lite.DetIVar('gn7_g', 2), l3lite.DetIVar('gn8_g', 2),
+ l3lite.DetIVar('gn9_g', 3),
+ l3lite.DetIVar('gn10_g', 4), l3lite.DetIVar('gn11_g', 4),
+ l3lite.DetIVar('gn12_g', 5), l3lite.DetIVar('gn13_g', 5),
+ l3lite.DetIVar('gn14_g', 6)]
## Group nodes associated with words
w0gn = l3lite.IVar('w0gn', {2, 7, 10, 12}) # the
w1gn = l3lite.Var('w1gn', set(), {1, 8}, 1, 2) # boy
@@ -298,6 +219,10 @@
w6gn = l3lite.Var('w6gn', set(), {4, 6, 11}, 1, 2) # act
w7gn = l3lite.DetIVar('w7gn', 14)
w2gnodes = [w0gn, w1gn, w2gn, w3gn, w4gn, w5gn, w6gn, w7gn]
+ # Union selection on gnodes for each snode
+ constraints.append(l3lite.UnionSelection(l3lite.DetVar('one', {1}),
w1gn, gn_w))
+ constraints.append(l3lite.UnionSelection(l3lite.DetVar('three', {3}),
w3gn, gn_w))
+ ### Word (SNode) ->
## Concrete group nodes associated with words
w0cgn = w0gn
w1cgn = l3lite.DetIVar('w1cgn', 8)
@@ -354,7 +279,30 @@
g5cw = g5snode
g6cw = g6snode
g_cwords = [g0cw, g1cw, g2cw, g3cw, g4cw, g5cw, g6cw]
+ # Positions of abstract gnodes in each group
+ g0aw = l3lite.IVar('g0aw', {0, 1, 2, 3, 4, 5, 6})
+ g1aw = l3lite.IVar('g1aw', {0, 1, 2, 3, 4, 5, 6})
+ g_awords = [g0aw, g1aw,
+ l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY,
l3lite.EMPTY]
+ # Union constraints for group abstract and concrete gnodes
+ constraints.extend(l3lite.Union([g0snode, g0cw, g0aw]).constraints)
+ constraints.extend(l3lite.Union([g1snode, g1cw, g1aw]).constraints)
+ ## Groups merged with groups
+ g0m = l3lite.Var('g0m', set(), {2, 3}, 0, 1)
+ g1m = l3lite.Var('g1m', set(), {4, 5}, 0, 1)
+ ## Groups merged with groups, including the group itself
+ g0gm = l3lite.Var('g0gm', {0}, {0, 2, 3}, 1, 2)
+ g1gm = l3lite.Var('g1gm', {1}, {1, 4, 5}, 1, 2)
+ g2gm = l3lite.DetVar('g2gm', {2})
+ g3gm = l3lite.DetVar('g3gm', {3})
+ g4gm = l3lite.DetVar('g4gm', {4})
+ g5gm = l3lite.DetVar('g5gm', {5})
+ g6gm = l3lite.DetVar('g6gm', {6})
+ # Relation between g->m only and g->m + self
+ constraints.extend(l3lite.Union([g0gm, g0m, l3lite.DetIVar('zero',
0)]).constraints)
+ constraints.extend(l3lite.Union([g1gm, g1m, l3lite.DetIVar('one',
1)]).constraints)
## Abstract group node mergers (empty set possible if not selected)
+ # a->m
# Merge %sbd with boy or us
gan1m = l3lite.Var('gan1m', set(), {8, 9}, 0, 1)
# Merge %sth with riot or act
@@ -362,9 +310,16 @@
gan_m = [l3lite.EMPTY, gan1m, l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY,
l3lite.EMPTY, gan6m, l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY,
l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY, l3lite.EMPTY,
l3lite.EMPTY]
+ # Merged gnodes must be among selected gnodes
constraints.extend(l3lite.Inclusion([gan1m, gnodeU]).constraints)
constraints.extend(l3lite.Inclusion([gan6m, gnodeU]).constraints)
- # m-> a; Abstract nodes associated with concrete gnodes
+ # Relate merged gnodes to merged groups; selection variables should
+ # be the union of a->m variables for each group that has any
+ # Group 0, abstract gnode 1
+ constraints.append(l3lite.UnionSelection(g0m, gan1m, gn_g))
+ # Group 1, abstract gnode 6
+ constraints.append(l3lite.UnionSelection(g1m, gan6m, gn_g))
+ ## m-> a; Abstract nodes associated with concrete gnodes
gm8ga = l3lite.Var('gm8ga', set(), {1}, 0, 1)
gm9ga = l3lite.Var('gm9ga', set(), {1}, 0, 1)
gm11ga = l3lite.Var('gm11ga', set(), {6}, 0, 1)
@@ -421,18 +376,9 @@
constraints.extend(l3lite.Disjoint(w2ga_nodes).constraints)
# All concrete nodes must nodes have different abstract nodes
constraints.extend(l3lite.Disjoint(gm_ga).constraints)
- ## Relations between w->cgnode, w->gnode, w->agnode
- ## Groups merged with groups, including the group itself
- g0gm = l3lite.Var('g0gm', {0}, {0, 2, 3}, 1, 2)
- g1gm = l3lite.Var('g1gm', {1}, {1, 4, 5}, 1, 2)
- g2gm = l3lite.DetVar('g2gm', {2})
- g3gm = l3lite.DetVar('g3gm', {3})
- g4gm = l3lite.DetVar('g4gm', {4})
- g5gm = l3lite.DetVar('g5gm', {5})
- g6gm = l3lite.DetVar('g6gm', {6})
## Trees under gnode heads
- g0tree = l3lite.Var('g0tree', set(), {0, 1, 2, 3, 4, 5, 6}, 5)
- g1tree = l3lite.Var('g1tree', set(), {0, 1, 2, 3, 4, 5, 6}, 2)
+ g0tree = l3lite.Var('g0tree', set(), {0, 1, 2, 3, 4, 5, 6}, 5) # at
least 5 snodes
+ g1tree = l3lite.Var('g1tree', set(), {0, 1, 2, 3, 4, 5, 6}, 2) # at
least 2 snodes
g2tree = g2snode
g3tree = g3snode
g4tree = g4snode
@@ -441,29 +387,30 @@
gtrees = [g0tree, g1tree, g2snode, g3snode, g4snode, g5snode, g6snode]
# g1 tree is the union of g0snode and the tree under whatever group
# merges with gnode 1 (sbd)
- constraints.append(l3lite.UnionSelection(g0tree, g0gm, gtrees))
- constraints.append(l3lite.UnionSelection(g1tree, g1gm, gtrees))
+ constraints.append(l3lite.UnionSelection(g0tree, g0gm, gsnodes))
+ constraints.append(l3lite.UnionSelection(g1tree, g1gm, gsnodes))
# Relate gnode merger with group merger
# If gnode 1 merges with gnode 8, then group 0 merges with group 2;
# if gnode 1 merges with gnode 9, then group 0 merges with group 3
# Select one or the other
# UnionSelection(choice, IVar('chooser', {0, 1}), [choice1, choice2])
- g0merge_sel = l3lite.IVar('g0m_sel', {0, 1, 2})
- constraints.append(l3lite.UnionSelection(g0gm, g0merge_sel,
[l3lite.DetVar('g0g2', {0, 2}),
-
l3lite.DetVar('g0g3', {0, 3}),
-
l3lite.DetVar('g0_', {0})]))
- constraints.append(l3lite.UnionSelection(gan1m, g0merge_sel,
- [l3lite.DetVar('gan1g8', {8}),
- l3lite.DetVar('gan1g9', {9}),
- l3lite.EMPTY]))
- g1merge_sel = l3lite.IVar('g1m_sel', {0, 1, 2})
- constraints.append(l3lite.UnionSelection(g1gm, g1merge_sel,
[l3lite.DetVar('g1g4', {1, 4}),
-
l3lite.DetVar('g1g5', {1, 5}),
-
l3lite.DetVar('g1_', {1})]))
- constraints.append(l3lite.UnionSelection(gan6m, g1merge_sel,
- [l3lite.DetVar('gan6g11',
{11}),
- l3lite.DetVar('gan6g13',
{13}),
- l3lite.EMPTY]))
+## g0merge_sel = l3lite.IVar('g0m_sel', {0, 1, 2})
+## constraints.append(l3lite.UnionSelection(g0gm, g0merge_sel,
[l3lite.DetVar('g0g2', {0, 2}),
+##
l3lite.DetVar('g0g3', {0, 3}),
+##
l3lite.DetVar('g0_', {0})]))
+## constraints.append(l3lite.UnionSelection(gan1m, g0merge_sel,
+## [l3lite.DetVar('gan1g8',
{8}),
+## l3lite.DetVar('gan1g9',
{9}),
+## l3lite.EMPTY]))
+## g1merge_sel = l3lite.IVar('g1m_sel', {0, 1, 2})
+## constraints.append(l3lite.UnionSelection(g1gm, g1merge_sel,
[l3lite.DetVar('g1g4', {1, 4}),
+##
l3lite.DetVar('g1g5', {1, 5}),
+##
l3lite.DetVar('g1_', {1})]))
+## constraints.append(l3lite.UnionSelection(gan6m, g1merge_sel,
+## [l3lite.DetVar('gan6g11',
{11}),
+## l3lite.DetVar('gan6g13',
{13}),
+## l3lite.EMPTY]))
+ ### Order
# Position pair constraints
gposcons = l3lite.Var('gposcons', set(),
{(0, 1), (1, 2), (2, 3), (3, 4), (0, 2), (1, 3),
(2, 4), (0, 3), (1, 4),
@@ -487,6 +434,12 @@
selvars=g_cwords,
seqvars=w2cgnodes,
mainvars=gc_detvars))
+ # Complex union selection on positions of all abstract gnodes in each
selected group
+ constraints.append(l3lite.ComplexUnionSelection(selvar=groups,
+ selvars=g_awords,
+ seqvars=w2ga_nodes,
+ mainvars=ga_detvars))
+ ### Projectivity
# Complex set convexity
constraints.append(l3lite.ComplexSetConvexity(groups, gtrees))
return constraints
Reply all
Reply to author
Forward
0 new messages