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