lib/rdf/n3/algebra/log/includes.rb in rdf-n3-3.1.1 vs lib/rdf/n3/algebra/log/includes.rb in rdf-n3-3.1.2
- old
+ new
@@ -5,9 +5,66 @@
# Formula A includes formula B if there exists some substitution which when applied to B creates a formula B' such that for every statement in B' is also in A, every variable universally (or existentially) quantified in B' is quantified in the same way in A.
#
# Variable substitution is applied recursively to nested compound terms such as formulae, lists and sets.
#
# (Understood natively by cwm when in in the antecedent of a rule. You can use this to peer inside nested formulae.)
- class Includes < SPARQL::Algebra::Operator::Binary
+ class Includes < RDF::N3::Algebra::ResourceOperator
NAME = :logIncludes
+ URI = RDF::N3::Log.includes
+
+ ##
+ # Both subject and object must be formulae.
+ #
+ # @param [RDF::Term] resource
+ # @param [:subject, :object] position
+ # @return [RDF::Term]
+ # @see RDF::N3::ResourceOperator#evaluate
+ def resolve(resource, position:)
+ resource if resource.formula?
+ end
+
+ # Both subject and object are inputs.
+ def input_operand
+ RDF::N3::List.new(values: operands)
+ end
+
+ ##
+ # Creates a repository constructed by substituting variables and in that subject with known IRIs and queries object against that repository. Either retuns a single solution, or no solutions.
+ #
+ # @note this does allow object to have variables not in the subject, if they could have been substituted away.
+ #
+ # @param [RDF::N3::Algebra::Formula] subject
+ # a formula
+ # @param [RDF::N3::Algebra::Formula] object
+ # a formula
+ # @return [RDF::Literal::Boolean]
+ def apply(subject, object)
+ subject_var_map = subject.variables.values.inject({}) {|memo, v| memo.merge(v => RDF::URI(v.name))}
+ object_vars = object.variables.keys
+ log_debug(NAME, "subject var map") {SXP::Generator.string(subject_var_map.to_sxp_bin)}
+ log_debug(NAME, "object vars") {SXP::Generator.string(object_vars.to_sxp_bin)}
+ # create a queryable from subject, replacing variables with IRIs for thsoe variables.
+ queryable = RDF::Repository.new do |r|
+ log_depth do
+ subject.each do |stmt|
+ parts = stmt.to_quad.map do |part|
+ part.is_a?(RDF::Query::Variable) ? subject_var_map.fetch(part) : part
+ end
+ r << RDF::Statement.from(parts)
+ end
+ end
+ end
+
+ # Query object against subject
+ solns = log_depth {queryable.query(object, **@options)}
+ log_info("(#{NAME} solutions)") {SXP::Generator.string solns.to_sxp_bin}
+
+ if !solns.empty? && (object_vars - solns.variable_names).empty?
+ # Return solution
+ solns.first
+ else
+ # Return false,
+ RDF::Literal::FALSE
+ end
+ end
end
end