class SD_Ideal
This class represents a SymbolicData database object. The constructor takes a complete URI or a name SUBJ (the latter of which will be prefixed with the 'ideal' value from the sd.ini)
Any triple of the form (SUBJ, PRED, OBJ) will yield a field PRED* for the SD_Ideal object with the value OBJ, where PRED* is the ending piece of PRED URI as defined by the function _uri_to_name()
A SPARQL endpoint is needed. As a future improvement, it could be nice to directly parse an RDF in a convienient serialization.
Attributes
the ideal basis
Public Class Methods
sd is a SymbolicData object, the name can be a complete URI or shortened name as defined by _uri_to_name(). The latter will be prefixed with the 'ideal' value from the sd.ini. Namespaces like “sd:Wu-90” are not (yet) supported.
Appart from retrieving the information from the SPARQL endpoint, the resource data (XML files) is needed as well. While the SPARQL endpoint can be substituted by another SPARQL endpoint, the links to the resource files are 'hard-coded' into the RDF data. The possibility to use a (possibly 'hand-filled') cache will be included in the next update.
# File examples/sdjas.rb, line 258 def initialize(sd, name) @dict = {} # mimic python @_sd = sd # quick test, if the given name already is an uri if name[0,7] == 'http://' @uri = name else @uri = @_sd._parser["symbolicdata"]["ideal"] + name end @dict["hasXMLResource"] = false @dict["hasLengthsList"] = '' @dict["hasDegreeList"] = '' @dict["hasParameters"] = '' @basis = [] # we set up the query to get all predicate values # of the URI/polynomial system/ideal query = " PREFIX sd: <#{@_sd.sd}> SELECT ?p ?o WHERE { <#{@uri}> ?p ?o }" #puts "query = " + query.to_s + "\n" @_request = SPARQL.new(@_sd, query) if @_request.json['results']['bindings'].size == 0 raise ArgumentError, "No data found for <#{@uri}>.\nMaybe the name was misspelled or the SPARQL endpoint is unavailable." end #puts "@_request.json = " + str(@_request.json) # append the keys to the @dict. for t in @_request.json['results']['bindings'] uri = t['p']['value'] obj = t['o']['value'] @dict[_uri_to_name(uri)] = obj end #puts "@dict = " + str(@dict) # Next we need a resource file with the actual expressions that are # used to generate the ideal. # # There are four cases that need to be dealt with # (1) the ideal is constructed direclty # from an IntPS with related XML resource # (2) the ideal is a flat variant of another # ideal # (3) the ideal is obtained by homogenizing # another ideal # (4) the ideal is obtained by parameterizing another # ideal # Please note: While it might seem that only one of (2) and (4) # should be included, both are needed to map the actual history # of how these ideals were obtained. # case 1 if @dict.include?( 'relatedPolynomialSystem' ) link = get_value_for_URI(@_sd, @dict["relatedPolynomialSystem"], @_sd.sd+'relatedXMLResource') __addXMLResource(link) @dict["hasXMLResource"] = true #puts "relatedPolynomialSystem " + str(name) end # case 2 if @dict.include?( 'flatten' ) parent_name = @dict["flatten"] parent = SD_Ideal.new(@_sd, parent_name) @variablesCSV = @dict["hasVariables"] @variables = @variablesCSV.split(",").map{ |x| x.to_s.strip() } @basis = parent.basis #puts "flatten " + str(parent_name) + ", name = " + str(name) end # case 3 if @dict.include?( 'homogenize' ) parent_name = @dict["homogenize"] if @dict.include?( 'homogenizedWith' ) hv = @dict["homogenizedWith"] parent = SD_Ideal.new(@_sd, parent_name) @variablesCSV = parent.variablesCSV + "," + hv @variables = parent.variables @variables.append(hv) @basis = parent.jas_homogenize(hv) #puts "homogenize " + str(parent_name) + ", name = " + str(name) end end # case 4 if @dict.include?( 'parameterize' ) parent_name = @dict["parameterize"] parent = SD_Ideal.new(@_sd, parent_name) @variablesCSV = @dict["hasVariables"] @variables = @variablesCSV.split(",").map{ |x| x.to_s.strip() } @basis = parent.basis #puts "parameterize " + str(parent_name) + ", name = " + str(name) end # now we got the variables, the parameters and # the strings/expressions for the polynomials __constructJasObject() end
Public Instance Methods
Fill internal objects.
# File examples/sdjas.rb, line 373 def __addXMLResource(link) #xml = requests.get(link).text #puts "link_xml = " + str(link) #url = link[0:23] path = link[23,link.length-23] # hack for lost domain #puts "url = " + str(url) #url = @_sd.url[:-5] url = URI("http://" + @_sd.sdhost.to_s) #puts "url = " + str(url) xml = nil Net::HTTP.start( url.host, url.port ) do |conn| #puts "path = " + str(path) url.path = path #puts "path = " + str(url.request_uri) #conn.request("GET", path ); req = Net::HTTP::Get.new(url.request_uri) response = conn.request( req ); if not response.is_a?(Net::HTTPSuccess) puts "response = " + response.to_s + "\n" raise RuntimeError, "HTTP GET #{url} not successful" end #puts "head = " + response.code.to_s + " " + response.msg + "\n" xml = response.body(); end puts _uri_to_name(link).to_s + " = " + xml.to_s #xmlTree = parseString(xml) xmlTree = REXML::Document.new(xml) #puts "xmlTree = " + str(xmlTree) # Code snipped borrowed from Albert Heinle if xmlTree.elements.to_a("*/vars").empty? # Check, if vars are there raise ArgumentError, "The given XMLString does not contain variables for the IntPS System" end if xmlTree.elements.to_a("*/basis").empty? # Check, if we have a basis raise ArgumentError, "The given XMLString does not contain a basis for the IntPS System" end # -------------------- Input Check finished -------------------- # From here, we can assume that the input is given correct @variablesCSV = xmlTree.elements.to_a("*/vars")[0].text #puts "@variablesCSV = " + @variablesCSV.to_s @variables = @variablesCSV.split(",").map{|x| x.to_s.strip() } #polynomials = xmlTree.elements.to_a("*/basis")[0] @basis = xmlTree.elements.to_a("*/basis/poly").map{ |poly| poly.text.to_s.strip() } #puts "@basis = " + @basis.to_s end
Construct the ideal as a Jas object.
# File examples/sdjas.rb, line 424 def __constructJasObject() #require "jas" # set up the polynomial ring (Jas syntax) if @dict.include?('hasParameters') and @dict['hasParameters'] != '' #K = 'K.<%s> = PolynomialRing(ZZ)' % @hasParameters #R = K + '; R.<%s> = PolynomialRing(K)' % @hasVariables kk = PolyRing.new(ZZ(), @dict['hasParameters'].to_s ) rr = PolyRing.new(kk, @dict['hasVariables'].to_s ) gens = '%s,%s' % [@dict['hasParameters'], @dict['hasVariables']] else #R = 'R.<%s> = PolynomialRing(ZZ)' % (@hasVariables) rr = PolyRing.new(ZZ(), @dict['hasVariables'].to_s ) gens = '%s' % @dict['hasVariables'] end # execute remaining JAS semantic constructs #exec(preparse(R)) ##rr = rr + "; " + gens + " = rr.gens();" #puts "rr = " + str(rr) rv = "one," + gens + " = rr.gens();" #puts "rv = " + str(rv) myb = binding #pr = eval(rr.to_s, myb) pr = eval(rv.to_s, myb) # safe here since rr did evaluate @jasRing = rr; #puts "pr = " + str(pr) # avoid XSS: check if polynomials are clean vs = GenPolynomialTokenizer.expressionVariables(gens.to_s) vs = vs.sort #puts "vs = " + str(vs) vsb = [] @basis.each{ |s| vsb += GenPolynomialTokenizer.expressionVariables(s.to_s) } vsb = vsb.sort.uniq #puts "vsb = " + str(vsb) if vs != vsb raise SyntaxError, "invalid variables: expected " + vs.to_s + ", got " + vsb.to_s end # construct polynomials in the constructed ring from # the polynomial expressions @jasBasis = [] for ps in @basis #puts "ps = " + str(ps) ps = ps.to_s ps = ps.gsub('^', '**') #exec(preparse("symbdata_ideal = %s" % ps)) pol = eval("symbdata_poly = %s" % ps, myb) #puts "pol = " + str(pol) @jasBasis.push(pol) end #puts "jasBasis = " + str(@jasBasis) end
Return the ideal as a Jas object.
# File examples/sdjas.rb, line 365 def get_ideal() #return ideal(@sageBasis) return @jasRing.ideal("",@jasBasis) end
This is the implementation of the predicate “sd:hasDegreeList”. The degree list is the sorted list of the degree of the generator of the ideal.
Along with the output, there will also be generated a field FROM_JAS_hasDegreeList which can be used to later access the data without recalculating. The main reason for this is that the SymbolicData properties are converted into field, not getter functions. So to have some symmetry, the Jas calculations will end up in fields as well.
# File examples/sdjas.rb, line 514 def jas_hasDegreeList() begin ll = @jasBasis.map{|x| x.degree() }.sort @FROM_JAS_hasDegreeList = ll.map{|x| x.to_s}.join(",") rescue @FROM_JAS_hasDegreeList = '' end return @FROM_JAS_hasDegreeList end
This is the implementation of the predicate “sd:hasLengthsList”. The lengths lists is the sorted list of the number of monomials of the generator of the ideal.
Along with the output, there will also be generated a field FROM_JAS_hasLengthsList which can be used to later access the data without recalculating. The main reason for this is that the SymbolicData properties are converted into field, not getter functions. So to have some symmetry, the Jas calculations will end up in fields as well.
# File examples/sdjas.rb, line 492 def jas_hasLengthsList() begin ll = @jasBasis.map{|x| x.size() }.sort @FROM_JAS_hasLengthsList = ll.map{|x| x.to_s}.join(",") rescue @FROM_JAS_hasLengthsList = '' end return @FROM_JAS_hasLengthsList end
This is the implementation of the predicate “sd:hasVariables”. This is actually not needed.
# File examples/sdjas.rb, line 528 def jas_hasVariables() #K = [] #DL = map(lambda m : K.extend(map(lambda l : str(l), m.variables())), @sageBasis) kk = @jasRing.ring.vars #return sorted(list(set(kk))).join(",") return kk.sort().uniq().join(",") end
Homogenize a basis, which here means actually nothing more than homogenizing every element of the basis.
# File examples/sdjas.rb, line 540 def jas_homogenize(hv) homBasis = @jasBasis.map{ |x| x.homogenize(hv) } return homBasis end