def eq_comm(u, v, eq=None): """ Goal for commutative equality >>> from kanren import run, var, fact >>> from kanren.assoccomm import eq_comm as eq >>> from kanren.assoccomm import commutative, associative >>> fact(commutative, 'add') # declare that 'add' is commutative >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> run(0, x, eq(('add', 1, 2, 3), ('add', 2, x, 1))) (3,) """ eq = eq or eq_comm vtail = var() if isvar(u) and isvar(v): return (core.eq, u, v) uop, uargs = op_args(u) vop, vargs = op_args(v) if not uop and not vop: return (core.eq, u, v) if vop and not uop: uop, uargs = vop, vargs v, u = u, v return (conde, ((core.eq, u, v), ), ((commutative, uop), (buildo, uop, vtail, v), (permuteq, uargs, vtail, eq)))
def test_nullo_itero(): x, y, z = var(), var(), var() q_lv, a_lv = var(), var() assert run(0, q_lv, conso(1, q_lv, [1]), nullo(q_lv)) assert run(0, q_lv, nullo(q_lv), conso(1, q_lv, [1])) assert not run(0, q_lv, nullo(q_lv, [], ())) assert run(0, [a_lv, q_lv], nullo(q_lv, a_lv, default_ConsNull=tuple)) == ([(), ()], ) assert run(0, [a_lv, q_lv], nullo(a_lv, [], q_lv)) == ([[], []], ) assert ([], ) == run(0, q_lv, nullo(q_lv, [])) assert ([], ) == run(0, q_lv, nullo([], q_lv)) assert (None, ) == run(0, q_lv, nullo(None, q_lv)) assert (tuple(), ) == run(0, q_lv, nullo(tuple(), q_lv)) assert (q_lv, ) == run(0, q_lv, nullo(tuple(), tuple())) assert ([], ) == run(0, q_lv, nullo(var(), q_lv)) assert ([], ) == run(0, q_lv, nullo(q_lv, var())) assert ([], ) == run(0, q_lv, nullo(q_lv, q_lv)) assert isvar(run(0, y, nullo([]))[0]) assert isvar(run(0, y, nullo(None))[0]) assert run(0, y, nullo(y))[0] == [] assert run(0, y, conso(var(), y, [1]), nullo(y))[0] == [] assert run(0, y, conso(var(), y, (1, )), nullo(y))[0] == () assert run(1, y, conso(1, x, y), itero(y))[0] == [1] assert run(1, y, conso(1, x, y), conso(2, z, x), itero(y))[0] == [1, 2] # Make sure that the remaining results end in logic variables res_2 = run(2, y, conso(1, x, y), conso(2, z, x), itero(y))[1] assert res_2[:2] == [1, 2] assert isvar(res_2[-1])
def lvar_ignore_ne(x, y): if (isvar(x) and isvar(y)) or (isinstance(x, type) and isinstance(y, type) and issubclass(x, Var) and issubclass(y, Var)): return False else: return ne(x, y)
def goal(substitution): newx, newy = reify((x, y), substitution) def apply_constrain(oldvar, newvar): if hasrange(oldvar): newvar = RangedVar.new_from_intersection(oldvar, newvar) if newvar: yield temp_assoc(substitution, oldvar, newvar) else: yield temp_assoc(substitution, oldvar, newvar) if isvar(newx): if isvar(newy): raise EarlyGoalError('two vars in comparison') elif isinstance(newy, Number): oldvar = newx newvar = RangedVar(RealRange([(newy, np.inf)])) yield from apply_constrain(oldvar, newvar) else: raise EarlyGoalError('Invalid constant type') elif isinstance(newx, Number): if isvar(newy): oldvar = newy newvar = RangedVar(RealRange([(-np.inf, newx)])) yield from apply_constrain(oldvar, newvar) elif isinstance(newy, Number): if newx > newy: yield substitution else: raise EarlyGoalError('Invalid constant type') else: raise EarlyGoalError('Invalid constant type')
def _(obj, printer): try: shape_str = str(obj.shape.as_list()) except (ValueError, AttributeError): shape_str = "Unknown" prefix = f'Tensor({getattr(obj.op, "type", obj.op)}):{obj.value_index},\tdtype={getattr(obj.dtype, "name", obj.dtype)},\tshape={shape_str},\t"{obj.name}"' _tf_dprint(prefix, printer) if isvar(obj.op): return elif isvar(obj.op.inputs): with printer.indented("| "): _tf_dprint(f"{obj.op.inputs}", printer) elif len(obj.op.inputs) > 0: with printer.indented("| "): if obj not in printer.printed_subgraphs: printer.printed_subgraphs.add(obj) _tf_dprint(obj.op, printer) else: _tf_dprint("...", printer) elif obj.op.type == "Const": with printer.indented("| "): if isinstance(obj, tf.Tensor): numpy_val = obj.eval(session=tf.compat.v1.Session(graph=obj.graph)) elif isvar(obj.op.node_def): _tf_dprint(f"{obj.op.node_def}", printer) return else: numpy_val = obj.op.node_def.attr["value"] _tf_dprint( np.array2string(numpy_val, threshold=20, prefix=printer.indentation), printer )
def test_meta_dtype_inference(): one_int_mt = mt(1) res = mt.add.output_meta_types({'x': one_int_mt}) assert res[0][0] == TFlowMetaTensor assert res[0][1] == tf.int32 one_flt_mt = mt(1.0) res = mt.add.output_meta_types({'y': one_flt_mt}) assert res[0][0] == TFlowMetaTensor assert res[0][1] == tf.float32 res = mt.add.output_meta_types({'T': tf.int32}) assert res[0][0] == TFlowMetaTensor assert res[0][1] == tf.int32 add_mt = TFlowMetaOperator(mt.add.op_def, TFlowMetaNodeDef('Add', 'my_add', {'T': 1})) res = add_mt.output_meta_types() assert res[0][0] == TFlowMetaTensor assert res[0][1] == tf.float32 with pytest.raises(AssertionError): # These integer types conflict with the NodeDef type in our operator, # `add_mt`. add_mt(1, 2) res = mt.cast.output_meta_types({'dtype': 'blah'}) assert res[0][0] == TFlowMetaTensor assert isvar(res[0][1]) res = mt.placeholder.output_meta_types({'dtype': 'blah'}) assert isvar(res[0][1])
def reify(self): if self.obj and not isinstance(self.obj, Var): return self.obj if isvar(self.inputs): return self op_inputs, op_inputs_unreified = meta_reify_iter(self.inputs) node_attr = getattr(self.node_def, "attr", None) if node_attr is None or isvar(node_attr): return self operator = TFlowMetaOperator(self.op_def, self.node_def) op_attrs, op_attrs_unreified = meta_reify_iter( # Only use NodeDef attrs that appear in the OpDef's call signature. # Other NodeDef attrs, like dtype and shape, can be computed. { k: v for k, v in node_attr.items() if k in operator._apply_func_sig.parameters }) if not (op_inputs_unreified or op_attrs_unreified or isvar(self.name)): # # An operation with this name might already exist in the graph # try: existing_op = ops.get_default_graph().get_operation_by_name( self.name) except KeyError: # # There is no such `Operation`, so we attempt to create it # apply_arguments = operator.input_args(*op_inputs, name=self.name, **op_attrs) tf_out = operator._apply_func(**apply_arguments) op_tf = tf_out.op else: # # An `Operation` with this name exists, let's make sure it's # equivalent to this meta `Operation` # if self != mt(existing_op): raise MetaReificationError( f"An Operation with the name {self.name}" " already exists in the graph and is not" " equal to this meta object.") op_tf = existing_op assert op_tf is not None self._obj = op_tf return self.obj return self
def seq_apply_anyo_sub_goal(s): nonlocal i_any, null_type l_in_rf, l_out_rf = reify((l_in, l_out), s) i_car, i_cdr = var(), var() o_car, o_cdr = var(), var() conde_branches = [] if i_any or (isvar(l_in_rf) and isvar(l_out_rf)): # Consider terminating the sequences when we've had at least # one successful goal or when both sequences are logic variables. conde_branches.append([eq(l_in_rf, null_type), eq(l_in_rf, l_out_rf)]) # Extract the CAR and CDR of each argument sequence; this is how we # iterate through elements of the two sequences. cons_parts_branch = [ goaleval(conso(i_car, i_cdr, l_in_rf)), goaleval(conso(o_car, o_cdr, l_out_rf)), ] conde_branches.append(cons_parts_branch) conde_relation_branches = [] relation_branch = None if not skip_cars: relation_branch = [ # This case tries the relation continues on. relation(i_car, o_car), # In this conde clause, we can tell future calls to # seq_apply_anyo that we've had at least one successful # application of the relation (otherwise, this clause # would fail due to the above goal). _seq_apply_anyo(relation, i_cdr, o_cdr, True, null_type), ] conde_relation_branches.append(relation_branch) base_branch = [ # This is the "base" case; it is used when, for example, # the given relation isn't satisfied. eq(i_car, o_car), _seq_apply_anyo(relation, i_cdr, o_cdr, i_any, null_type), ] conde_relation_branches.append(base_branch) cons_parts_branch.append(conde(*conde_relation_branches)) g = conde(*conde_branches) g = goaleval(g) yield from g(s)
def buildo(op, args, obj): if not isvar(obj): if not isvar(args): args = etuplize(args, shallow=True) oop, oargs = operator(obj), arguments(obj) return lallgreedy(eq(op, oop), eq(args, oargs)) elif isvar(args) or isvar(op): return conso(op, args, obj) else: return eq(obj, term(op, args))
def base_arguments(self): # TODO: In keeping with our desire to return logic variables in cases # where params aren't given/inferred, we could return something like # `cons(var(), var())` here (although that wouldn't be necessarily # imply that the result is a proper list/tuple). if isvar(self.op) or (not isvar(self.op.inputs) and len(self.op.inputs) == 0): raise NotImplementedError(f"{self} does not have base arguments.") return self.op.inputs
def base_operator(self): if getattr(self, "_operator", None): return self._operator if isvar(self.op) or (not isvar(self.op.inputs) and len(self.op.inputs) == 0): raise NotImplementedError(f"{self} does not have a base_operator.") self._operator = TFlowMetaOperator(self.op.op_def, self.op.node_def) return self._operator
def test_nullo_itero(): assert isvar(run(0, y, nullo([]))[0]) assert isvar(run(0, y, nullo(None))[0]) assert run(0, y, nullo(y))[0] is None assert run(0, y, (conso, var(), y, [1]), nullo(y))[0] == [] assert run(0, y, (conso, var(), y, (1, )), nullo(y))[0] == () assert run(1, y, conso(1, x, y), itero(y))[0] == [1] assert run(1, y, conso(1, x, y), conso(2, z, x), itero(y))[0] == [1, 2] # Make sure that the remaining results end in logic variables res_2 = run(2, y, conso(1, x, y), conso(2, z, x), itero(y))[1] assert res_2[:2] == [1, 2] assert isvar(res_2[-1])
def test_nullo_itero(): assert isvar(run(0, y, nullo([]))[0]) assert isvar(run(0, y, nullo(None))[0]) assert run(0, y, nullo(y))[0] is None assert run(0, y, (conso, var(), y, [1]), nullo(y))[0] == [] assert run(0, y, (conso, var(), y, (1,)), nullo(y))[0] == () assert run(1, y, conso(1, x, y), itero(y))[0] == [1] assert run(1, y, conso(1, x, y), conso(2, z, x), itero(y))[0] == [1, 2] # Make sure that the remaining results end in logic variables res_2 = run(2, y, conso(1, x, y), conso(2, z, x), itero(y))[1] assert res_2[:2] == [1, 2] assert isvar(res_2[-1])
def __init__(self, op, inputs, outputs=None, obj=None): self.op = metatize(op) if not isvar(inputs): self.inputs = tuple(metatize(i) for i in inputs) else: self.inputs = inputs if outputs is not None and not isvar(outputs): self._outputs = tuple(metatize(o) for o in outputs) else: self._outputs = outputs super().__init__(obj=obj)
def eq_assoccomm(u, v): """ Associative/Commutative eq Works like logic.core.eq but supports associative/commutative expr trees tree-format: (op, *args) example: (add, 1, 2, 3) State that operations are associative or commutative with relations >>> from kanren.assoccomm import eq_assoccomm as eq >>> from kanren.assoccomm import commutative, associative >>> from kanren import fact, run, var >>> fact(commutative, 'add') # declare that 'add' is commutative >>> fact(associative, 'add') # declare that 'add' is associative >>> x = var() >>> e1 = ('add', 1, 2, 3) >>> e2 = ('add', 1, x) >>> run(0, x, eq(e1, e2)) (('add', 2, 3), ('add', 3, 2)) """ uop, uargs = op_args(u) vop, vargs = op_args(v) if uop and not vop and not isvar(v): return fail if vop and not uop and not isvar(u): return fail if uop and vop and uop != vop: return fail if uop and not (uop, ) in associative.facts: return (eq, u, v) if vop and not (vop, ) in associative.facts: return (eq, u, v) if uop and vop: u, v = (u, v) if len(uargs) >= len(vargs) else (v, u) n = min(map(len, (uargs, vargs))) # length of shorter tail else: n = None if vop and not uop: u, v = v, u w = var() # TODO: Is greedy correct? return (lallgreedy, (eq_assoc, u, w, eq_assoccomm, n), (eq_comm, v, w, eq_assoccomm))
def op_args_to_operation_inputs(self, apply_arguments): """Map an `OpDef`'s "apply function" arguments to `Operation` inputs and a meta `NodeDef`.""" if isvar(self.op_def): return None op_def_tf = self.op_def.obj op_inputs = tuple( apply_arguments.get(i.name) for i in op_def_tf.input_arg if i.name in apply_arguments) # TODO: Include inferred attr values (e.g. dtypes). if "node_attrs" not in meta._lvar_defaults_enabled: node_attr = { a.name: apply_arguments.get(a.name, a) for a in op_def_tf.attr } else: node_attr = var() if "names" not in meta._lvar_defaults_enabled: op_name = apply_arguments.get("name", op_def_tf.name) or op_def_tf.name else: op_name = var() node_def = TFlowMetaNodeDef(op_def_tf.name, op_name, node_attr) return op_inputs, node_def
def meta_reify_iter(rands): """Recursively reify an iterable object and return a boolean indicating the presence of un-reifiable objects, if any.""" any_unreified = False reified_rands = [] _rands = rands if isinstance(_rands, Mapping): _rands = _rands.items() for s in _rands: if isinstance(s, MetaSymbol): rrand = s.reify() reified_rands.append(rrand) any_unreified |= isinstance(rrand, MetaSymbol) any_unreified |= isvar(rrand) elif MetaSymbol.is_meta(s): reified_rands.append(s) any_unreified |= True elif isinstance(s, (list, tuple)): _reified_rands, _any_unreified = meta_reify_iter(s) reified_rands.append(type(s)(_reified_rands)) any_unreified |= _any_unreified else: reified_rands.append(s) return type(rands)(reified_rands), any_unreified
def evalo(program: ast.AST, value: Var, replace_var: str = None): replace_var = replace_var or DEFAULT_REPLACE_VAR if value.token != replace_var: raise RuntimeError("Value {} should have token {}".format( value, replace_var)) program = strip_ast(program) program = replace_ast_name_with_lvar(program, replace_var=replace_var) goals, env = eval_programo(program, [], value) res = run(1, value, goals) r = res[0] logger.info("Final result: {}".format(ast_dump_if_possible(res))) if isvar(r): logger.info("No results found for {}: {}".format(value, r)) return r logger.info("Found {} to be {}".format(ast_dump_if_possible(value), ast_dump_if_possible(r))) # TODO: This only works on the last assign if isinstance(r, ast.Name): evaluated_value = literal_lookup(r.id, env) logger.info("Found evaluated value {}".format( ast_dump_if_possible(evaluated_value))) return evaluated_value
def as_tuple(self): tail = self.tail if isinstance(tail, LCons): tail = self.tail.as_tuple() elif isvar(tail): raise EarlyGoalError() return (self.head, ) + tail
def __call__(self, *args): """ Returns an evaluated (callable) goal, which returns a list of substitutions which match args against a fact in the knowledge base. *args: the goal to evaluate. This consists of vars and values to match facts against. """ def goal(substitution): args2 = reify(args, substitution) subsets = [ self.index[key] for key in enumerate(args) if key in self.index ] if subsets: # we are able to reduce the pool early facts = intersection(*sorted(subsets, key=len)) else: facts = self.facts for fact in facts: unified = unify(fact, args2, substitution) if unified != False: yield merge(unified, substitution) for x in args: if isvar(x): return goal return self.op(*args)
def test_meta_operation(): t1_tf = tf.convert_to_tensor([[1, 2, 3], [4, 5, 6]]) t2_tf = tf.convert_to_tensor([[7, 8, 9], [10, 11, 12]]) test_out_tf = tf.concat([t1_tf, t2_tf], 0) # Just make sure it doesn't raise and exception mt.ConcatV2.op_def.validate_objs() assert mt.ConcatV2.op_def.reify() == test_out_tf.op.op_def # TODO: Without explicit conversion, each element within these arrays gets # converted to a `Tensor` by `metatize`. That doesn't seem very # reasonable. Likewise, the `0` gets converted, but it probably shouldn't be. test_op = TFlowMetaOp(mt.Concat.op_def, var(), [[t1_tf, t2_tf], 0]) assert isvar(test_op.name) # Make sure we converted lists to tuples assert isinstance(test_op.inputs, tuple) assert isinstance(test_op.inputs[0], tuple) test_op = TFlowMetaOp( mt.Concat.op_def, var(), [[t1_tf, t2_tf], 0], # This tensor isn't actually consistent with the # OpDef we're using (i.e. Concat != ConcatV2)! outputs=[test_out_tf]) # NodeDef is a logic variable, so this shouldn't actually reify. assert MetaSymbol.is_meta(test_op.reify()) assert isinstance(test_op.outputs, tuple) assert MetaSymbol.is_meta(test_op.outputs[0])
def permuteq(a, b, eq2=eq): """ Equality under permutation For example (1, 2, 2) equates to (2, 1, 2) under permutation >>> from kanren import var, run, permuteq >>> x = var() >>> run(0, x, permuteq(x, (1, 2))) ((1, 2), (2, 1)) >>> run(0, x, permuteq((2, 1, x), (2, 1, 2))) (2,) """ if isinstance(a, tuple) and isinstance(b, tuple): if len(a) != len(b): return fail elif collections.Counter(a) == collections.Counter(b): return success else: c, d = list(a), list(b) for x in list(c): # TODO: This is quadratic in the number items in the sequence. # Need something like a multiset. Maybe use # collections.Counter? try: d.remove(x) c.remove(x) except ValueError: pass c, d = tuple(c), tuple(d) if len(c) == 1: return (eq2, c[0], d[0]) return condeseq( ((eq2, x, d[0]), (permuteq, c[0:i] + c[i + 1:], d[1:], eq2)) for i, x in enumerate(c) ) if isvar(a) and isvar(b): raise EarlyGoalError() if isvar(a) or isvar(b): if isinstance(b, tuple): c, d = a, b elif isinstance(a, tuple): c, d = b, a return (condeseq, ([eq(c, perm)] for perm in unique(permutations(d, len(d)))))
def permuteq(a, b, eq2=eq): """ Equality under permutation For example (1, 2, 2) equates to (2, 1, 2) under permutation >>> from mykanren import var, run, permuteq >>> x = var() >>> run(0, x, permuteq(x, (1, 2))) ((1, 2), (2, 1)) >>> run(0, x, permuteq((2, 1, x), (2, 1, 2))) (2,) """ if isinstance(a, tuple) and isinstance(b, tuple): if len(a) != len(b): return fail elif collections.Counter(a) == collections.Counter(b): return success else: c, d = list(a), list(b) for x in list(c): # TODO: This is quadratic in the number items in the sequence. # Need something like a multiset. Maybe use # collections.Counter? try: d.remove(x) c.remove(x) except ValueError: pass c, d = tuple(c), tuple(d) if len(c) == 1: return (eq2, c[0], d[0]) return condeseq( ((eq2, x, d[0]), (permuteq, c[0:i] + c[i + 1:], d[1:], eq2)) for i, x in enumerate(c) ) if isvar(a) and isvar(b): raise EarlyGoalError() if isvar(a) or isvar(b): if isinstance(b, tuple): c, d = a, b elif isinstance(a, tuple): c, d = b, a return (condeseq, ([eq(c, perm)] for perm in unique(permutations(d, len(d)))))
def op_args(x): """ Break apart x into an operation and tuple of args """ if isvar(x): return None, None try: return operator(x), arguments(x) except NotImplementedError: return None, None
def funco(inputs, out): if isvar(inputs): raise EarlyGoalError() else: if isinstance(inputs, (tuple, list)): return (eq, func(*inputs), out) else: return (eq, func(inputs), out)
def test_eq_length(): q_lv = var() res = run(0, q_lv, eq_length([1, 2, 3], q_lv)) assert len(res) == 1 and len(res[0]) == 3 and all(isvar(q) for q in res[0]) res = run(0, q_lv, eq_length(q_lv, [1, 2, 3])) assert len(res) == 1 and len(res[0]) == 3 and all(isvar(q) for q in res[0]) res = run(0, q_lv, eq_length(cons(1, q_lv), [1, 2, 3])) assert len(res) == 1 and len(res[0]) == 2 and all(isvar(q) for q in res[0]) v_lv = var() res = run(3, (q_lv, v_lv), eq_length(q_lv, v_lv, default_ConsNull=tuple)) assert len(res) == 3 and all( isinstance(a, tuple) and len(a) == len(b) and (len(a) == 0 or a != b) and all(isvar(r) for r in a) for a, b in res)
def ground_order_key(S, x): if isvar(x): return 2 elif isground(x, S): return -1 elif issubclass(type(x), ConsPair): return 1 else: return 0
def frozen_attr(self): if getattr(self, "_frozen_attr", None) is not None: return self._frozen_attr if isvar(self.attr): self._frozen_attr = self.attr else: self._frozen_attr = frozenset(self.attr.items()) return self._frozen_attr
def __init__(self, dims, obj=None): super().__init__(obj=obj) self.dims = dims if self.dims is not None and not isvar(self.dims): # TODO: Just like the comment in `TFlowMetaTensor.inputs`, # `self.dims` should be something like `cons(var(), ...)` and not a # straight logic variable. self.dims = tuple( tensor_shape.as_dimension(d).value for d in self.dims)
def test_map_anyo_misc(): q_lv = var("q") res = run(0, q_lv, map_anyo(eq, [1, 2, 3], [1, 2, 3])) # TODO: Remove duplicate results assert len(res) == 7 res = run(0, q_lv, map_anyo(eq, [1, 2, 3], [1, 3, 3])) assert len(res) == 0 def one_to_threeo(x, y): return conde([eq(x, 1), eq(y, 3)]) res = run(0, q_lv, map_anyo(one_to_threeo, [1, 2, 4, 1, 4, 1, 1], q_lv)) assert res[0] == [3, 2, 4, 3, 4, 3, 3] assert (len( run(4, q_lv, map_anyo(math_reduceo, [etuple(mul, 2, var("x"))], q_lv))) == 0) test_res = run(4, q_lv, map_anyo(math_reduceo, [etuple(add, 2, 2), 1], q_lv)) assert test_res == ([etuple(mul, 2, 2), 1], ) test_res = run(4, q_lv, map_anyo(math_reduceo, [1, etuple(add, 2, 2)], q_lv)) assert test_res == ([1, etuple(mul, 2, 2)], ) test_res = run(4, q_lv, map_anyo(math_reduceo, q_lv, var("z"))) assert all(isinstance(r, list) for r in test_res) test_res = run(4, q_lv, map_anyo(math_reduceo, q_lv, var("z"), tuple)) assert all(isinstance(r, tuple) for r in test_res) x, y, z = var(), var(), var() def test_bin(a, b): return conde([eq(a, 1), eq(b, 2)]) res = run(10, (x, y), map_anyo(test_bin, x, y, null_type=tuple)) exp_res_form = ( ((1, ), (2, )), ((x, 1), (x, 2)), ((1, 1), (2, 2)), ((x, y, 1), (x, y, 2)), ((1, x), (2, x)), ((x, 1, 1), (x, 2, 2)), ((1, 1, 1), (2, 2, 2)), ((x, y, z, 1), (x, y, z, 2)), ((1, x, 1), (2, x, 2)), ((x, 1, y), (x, 2, y)), ) for a, b in zip(res, exp_res_form): s = unify(a, b) assert s is not False assert all(isvar(i) for i in reify((x, y, z), s))
def infer_output_types(o): """Get dtypes for specific outputs using known dtype info and API inputs.""" # Get the explicit type from a `NodeDef` attribute. type_name = o.type_attr # Existing dtype value dtype = type_map[type_name] # New value _dtype = None # The information could be in the `NodeDef` if isinstance(getattr(self.node_def, "attr", None), dict): _dtype = self.node_def.attr.get(type_name) # It could also be in the inputs (i.e. when called via the API # route) # TODO: If it's in the inputs, we should just create the # corresponding `NodeDef`. if inputs and type_name in inputs: _dtype = inputs.get(type_name) if _dtype is None: _dtype = var() if not isvar(_dtype): try: _dtype = tf.dtypes.as_dtype(_dtype).base_dtype except TypeError: _dtype = var() # Make sure dtypes derived from `NodeDef` info and API inputs are # consistent. if dtype is None or isvar(dtype): # Newly inferred dtype is at least as informative as the # current one dtype = _dtype type_map[type_name] = dtype elif _dtype is None or isvar(_dtype): # Newly inferred dtype is less informative pass else: assert dtype == _dtype return (TFlowMetaTensor, dtype)
def test_metatize(): vec_tt = tt.vector('vec') vec_m = metatize(vec_tt) assert vec_m.base == type(vec_tt) test_list = [1, 2, 3] metatize_test_list = metatize(test_list) assert isinstance(metatize_test_list, list) assert all(isinstance(m, MetaSymbol) for m in metatize_test_list) test_iter = iter([1, 2, 3]) metatize_test_iter = metatize(test_iter) assert isinstance(metatize_test_iter, Iterator) assert all(isinstance(m, MetaSymbol) for m in metatize_test_iter) test_out = metatize(var()) assert isvar(test_out) with variables(vec_tt): test_out = metatize(vec_tt) assert test_out == vec_tt assert isvar(test_out) test_out = metatize(np.r_[1, 2, 3]) assert isinstance(test_out, MetaSymbol) class TestClass(object): pass with pytest.raises(Exception): metatize(TestClass()) class TestOp(tt.gof.Op): pass test_out = metatize(TestOp) assert issubclass(test_out, MetaOp) test_op_tt = TestOp() test_obj = test_out(obj=test_op_tt) assert isinstance(test_obj, MetaSymbol) assert test_obj.obj == test_op_tt assert test_obj.base == TestOp
def funco(inputs, out): if isvar(inputs): raise EarlyGoalError() else: if isinstance(inputs, (tuple, list)): if any(map(isvar, inputs)): raise EarlyGoalError() return (eq, func(*inputs), out) else: return (eq, func(inputs), out)
def seteq(a, b, eq2=eq): """ Set Equality For example (1, 2, 3) set equates to (2, 1, 3) >>> from logpy import var, run, seteq >>> x = var() >>> run(0, x, seteq(x, (1, 2))) ((1, 2), (2, 1)) >>> run(0, x, seteq((2, 1, x), (3, 1, 2))) (3,) """ ts = lambda x: tuple(set(x)) if not isvar(a) and not isvar(b): return permuteq(ts(a), ts(b), eq2) elif not isvar(a): return permuteq(ts(a), b, eq2) else: # not isvar(b) return permuteq(a, ts(b), eq2)
def permuteq(a, b, eq2=eq): """ Equality under permutation For example (1, 2, 2) equates to (2, 1, 2) under permutation >>> from logpy import var, run, permuteq >>> x = var() >>> run(0, x, permuteq(x, (1, 2))) ((1, 2), (2, 1)) >>> run(0, x, permuteq((2, 1, x), (2, 1, 2))) (2,) """ if isinstance(a, tuple) and isinstance(b, tuple): if len(a) != len(b): return fail elif set(a) == set(b) and len(set(a)) == len(a): return success else: c, d = a, b try: c, d = tuple(sorted(c)), tuple(sorted(d)) except: pass if len(c) == 1: return (eq2, c[0], d[0]) return condeseq( ((eq2, c[i], d[0]), (permuteq, c[0:i] + c[i + 1:], d[1:], eq2)) for i in range(len(c)) ) if isvar(a) and isvar(b): raise EarlyGoalError() if isvar(a) or isvar(b): if isinstance(b, tuple): c, d = a, b elif isinstance(a, tuple): c, d = b, a return (condeseq, ([eq(c, perm)] for perm in unique(permutations(d, len(d)))))
def goal(x, y, z): if not isvar(x) and not isvar(y): return eq(op(x, y), z) if not isvar(y) and not isvar(z) and revop: return eq(x, revop(z, y)) if not isvar(x) and not isvar(z) and revop: return eq(y, revop(z, x)) raise EarlyGoalError()
def buildo(op, args, obj): """ obj is composed of op on args Example: in add(1,2,3) ``add`` is the op and (1,2,3) are the args Checks op_regsitry for functions to define op/arg relationships """ if not isvar(obj): oop, oargs = op_args(obj) # TODO: Is greedy correct? return lallgreedy((eq, op, oop), (eq, args, oargs)) else: try: return eq(obj, build(op, args)) except TypeError: raise EarlyGoalError() raise EarlyGoalError()
def membero(x, coll): """ Goal such that x is an item of coll """ if not isvar(coll): return (lany, ) + tuple((eq, x, item) for item in coll) raise EarlyGoalError()
def lefto(q, p, lst): if isvar(lst): raise EarlyGoalError() return membero((q, p), zip(lst, lst[1:]))
def _nullo(s): _s = reify(l, s) if isvar(_s): yield unify(_s, None, s) elif is_null(_s): yield s
def gt(x, y): """ x > y """ if not isvar(x) and not isvar(y): return eq(x > y, True) else: raise EarlyGoalError()
def primo(x): """ x is a prime number """ if isvar(x): return condeseq([(eq, x, p)] for p in map(sg.prime, it.count(1))) else: return success if sg.isprime(x) else fail