+def descr2properties(descr, height, width):
+
+ if type(descr) == list:
+ return [ descr2properties(d, height, width) for d in descr ]
+
+ d = descr.split('<img>', 1)
+ d = d[-1] if len(d) > 1 else ''
+ d = d.strip().split(' ')[:height * width]
+
+ seen = {}
+ if len(d) != height * width: return []
+ for k, x in enumerate(d):
+ if x != color_names[0]:
+ if x in color_tokens:
+ if x in seen: return []
+ else:
+ return []
+ seen[x] = (color_id[x], k // width, k % width)
+
+ square_c = torch.tensor( [ x[0] for x in seen.values() ] )
+ square_i = torch.tensor( [ x[1] for x in seen.values() ] )
+ square_j = torch.tensor( [ x[2] for x in seen.values() ] )
+
+ s = all_properties(height, width, len(seen), square_i, square_j, square_c)
+
+ return s
+
+######################################################################
+
+def nb_missing_properties(descr, height, width):
+ if type(descr) == list:
+ return [ nb_missing_properties(d, height, width) for d in descr ]
+
+ d = descr.split('<img>', 1)
+ if len(d) == 0: return 0
+ d = d[0].strip().split('<sep>')
+ d = [ x.strip() for x in d ]
+
+ requested_properties = set(d)
+ all_properties = set(descr2properties(descr, height, width))
+ missing_properties = requested_properties - all_properties
+
+ return (len(requested_properties), len(all_properties), len(missing_properties))
+
+######################################################################
+