diff options
-rw-r--r-- | Rakefile | 2 | ||||
-rw-r--r-- | lib/algorithm.rb | 154 | ||||
-rw-r--r-- | lib/authorization.rb | 14 | ||||
-rw-r--r-- | lib/dataset.rb | 2 | ||||
-rw-r--r-- | lib/feature.rb | 7 | ||||
-rw-r--r-- | lib/helper.rb | 10 | ||||
-rw-r--r-- | lib/overwrite.rb | 1 | ||||
-rw-r--r-- | lib/parser.rb | 47 | ||||
-rw-r--r-- | lib/rest_client_wrapper.rb | 2 | ||||
-rw-r--r-- | lib/serializer.rb | 18 | ||||
-rw-r--r-- | lib/validation.rb | 87 |
11 files changed, 246 insertions, 98 deletions
@@ -53,7 +53,7 @@ begin #valiation-gem gem.add_dependency "haml", ">=3" # validation-gems - gem.add_dependency "ruby-plot", "=0.0.2" + gem.add_dependency "ruby-plot", "~>0.4.0" ['jeweler'].each { |dep| gem.add_development_dependency dep } gem.files = FileList["[A-Z]*", "{bin,generators,lib,test}/**/*", 'lib/jeweler/templates/.gitignore'] end diff --git a/lib/algorithm.rb b/lib/algorithm.rb index abf10d4..5b41cbf 100644 --- a/lib/algorithm.rb +++ b/lib/algorithm.rb @@ -164,65 +164,127 @@ module OpenTox # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features` # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required # @return [Hash] Hash with keys `:prediction, :confidence` - def self.local_svm_regression(neighbors,params ) - sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values between query and neighbors - conf = sims.inject{|sum,x| sum + x } + def self.local_svm_regression(neighbors, params) + take_logs=true + neighbors.each do |n| + if (! n[:activity].nil?) && (n[:activity].to_f < 0.0) + take_logs = false + end + end acts = neighbors.collect do |n| act = n[:activity] - Math.log10(act.to_f) + take_logs ? Math.log10(act.to_f) : act.to_f end # activities of neighbors for supervised learning - neighbor_matches = neighbors.collect{ |n| n[:features] } # as in classification: URIs of matches - gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel - if neighbor_matches.size == 0 - raise "No neighbors found" - else - # gram matrix - (0..(neighbor_matches.length-1)).each do |i| - gram_matrix[i] = [] unless gram_matrix[i] - # upper triangle - ((i+1)..(neighbor_matches.length-1)).each do |j| - sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])") - gram_matrix[i][j] = Algorithm.gauss(sim) - gram_matrix[j] = [] unless gram_matrix[j] - gram_matrix[j][i] = gram_matrix[i][j] # lower triangle - end - gram_matrix[i][i] = 1.0 - end + sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors + begin + prediction = local_svm(neighbors, acts, sims, "nu-svr", params) + prediction = (take_logs ? 10**(prediction.to_f) : prediction.to_f) + LOGGER.debug "Prediction is: '" + prediction.to_s + "'." + rescue Exception => e + LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}" + end - #LOGGER.debug gram_matrix.to_yaml - @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests - @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed - LOGGER.debug "Setting R data ..." - # set data - @r.gram_matrix = gram_matrix.flatten - @r.n = neighbor_matches.size - @r.y = acts - @r.sims = sims + conf = sims.inject{|sum,x| sum + x } + confidence = conf/neighbors.size if neighbors.size > 0 + {:prediction => prediction, :confidence => confidence} + + end - LOGGER.debug "Preparing R data ..." - # prepare data - @r.eval "y<-as.vector(y)" - @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))" - @r.eval "sims<-as.vector(sims)" - - # model + support vectors - LOGGER.debug "Creating SVM model ..." - @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"nu-svr\", nu=0.8)" - @r.eval "sv<-as.vector(SVindex(model))" - @r.eval "sims<-sims[sv]" - @r.eval "sims<-as.kernelMatrix(matrix(sims,1))" - LOGGER.debug "Predicting ..." - @r.eval "p<-predict(model,sims)[1,1]" - prediction = 10**(@r.p.to_f) + # Local support vector classification from neighbors + # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features` + # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required + # @return [Hash] Hash with keys `:prediction, :confidence` + def self.local_svm_classification(neighbors, params) + acts = neighbors.collect do |n| + act = n[:activity] + end # activities of neighbors for supervised learning + acts_f = acts.collect {|v| v == true ? 1.0 : 0.0} + sims = neighbors.collect{ |n| Algorithm.gauss(n[:similarity]) } # similarity values btwn q and nbors + begin + prediction = local_svm (neighbors, acts_f, sims, "C-bsvc", params) LOGGER.debug "Prediction is: '" + prediction.to_s + "'." - @r.quit # free R + rescue Exception => e + LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}" end + + conf = sims.inject{|sum,x| sum + x } confidence = conf/neighbors.size if neighbors.size > 0 {:prediction => prediction, :confidence => confidence} end + + # Local support vector prediction from neighbors. + # Not to be called directly (use local_svm_regression or local_svm_classification. + # @param [Array] neighbors, each neighbor is a hash with keys `:similarity, :activity, :features` + # @param [Array] acts, activities for neighbors. + # @param [Array] sims, similarities for neighbors. + # @param [String] type, one of "nu-svr" (regression) or "C-bsvc" (classification). + # @param [Hash] params Keys `:similarity_algorithm,:p_values` are required + # @return [Numeric] A prediction value. + def self.local_svm(neighbors, acts, sims, type, params) + neighbor_matches = neighbors.collect{ |n| n[:features] } # URIs of matches + gram_matrix = [] # square matrix of similarities between neighbors; implements weighted tanimoto kernel + if neighbor_matches.size == 0 + raise "No neighbors found." + else + # gram matrix + (0..(neighbor_matches.length-1)).each do |i| + gram_matrix[i] = [] unless gram_matrix[i] + # upper triangle + ((i+1)..(neighbor_matches.length-1)).each do |j| + sim = eval("#{params[:similarity_algorithm]}(neighbor_matches[i], neighbor_matches[j], params[:p_values])") + gram_matrix[i][j] = Algorithm.gauss(sim) + gram_matrix[j] = [] unless gram_matrix[j] + gram_matrix[j][i] = gram_matrix[i][j] # lower triangle + end + gram_matrix[i][i] = 1.0 + end + + #LOGGER.debug gram_matrix.to_yaml + @r = RinRuby.new(false,false) # global R instance leads to Socket errors after a large number of requests + @r.eval "library('kernlab')" # this requires R package "kernlab" to be installed + LOGGER.debug "Setting R data ..." + # set data + @r.gram_matrix = gram_matrix.flatten + @r.n = neighbor_matches.size + @r.y = acts + @r.sims = sims + + begin + LOGGER.debug "Preparing R data ..." + # prepare data + @r.eval "y<-as.vector(y)" + @r.eval "gram_matrix<-as.kernelMatrix(matrix(gram_matrix,n,n))" + @r.eval "sims<-as.vector(sims)" + + # model + support vectors + LOGGER.debug "Creating SVM model ..." + @r.eval "model<-ksvm(gram_matrix, y, kernel=matrix, type=\"#{type}\", nu=0.5)" + @r.eval "sv<-as.vector(SVindex(model))" + @r.eval "sims<-sims[sv]" + @r.eval "sims<-as.kernelMatrix(matrix(sims,1))" + LOGGER.debug "Predicting ..." + if type == "nu-svr" + @r.eval "p<-predict(model,sims)[1,1]" + elsif type == "C-bsvc" + @r.eval "p<-predict(model,sims)" + end + if type == "nu-svr" + prediction = @r.p + elsif type == "C-bsvc" + prediction = (@r.p.to_f == 1.0 ? true : false) + end + @r.quit # free R + rescue Exception => e + LOGGER.debug "#{e.class}: #{e.message} #{e.backtrace}" + end + + end + prediction + end + end module Substructure diff --git a/lib/authorization.rb b/lib/authorization.rb index d9f900b..288733a 100644 --- a/lib/authorization.rb +++ b/lib/authorization.rb @@ -227,7 +227,9 @@ module OpenTox begin resource = RestClient::Resource.new("#{AA_SERVER}/opensso/identity/search") grps = resource.post(:admin => subjectid, :attributes_names => "objecttype", :attributes_values_objecttype => "group") - grps.split("\n").collect{|x| x.sub("string=","")} + grps = grps.split("\n").collect{|x| x.sub("string=","")} + grps.delete_if{|g|g=="MemberManagement"||g=="Webmasters"} + grps rescue [] end @@ -286,10 +288,12 @@ module OpenTox # @return [Boolean] def self.delete_policies_from_uri(uri, subjectid) policies = list_uri_policies(uri, subjectid) - policies.each do |policy| - ret = delete_policy(policy, subjectid) - LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}" - end + if policies + policies.each do |policy| + ret = delete_policy(policy, subjectid) + LOGGER.debug "OpenTox::Authorization delete policy: #{policy} - with result: #{ret}" + end + end return true end diff --git a/lib/dataset.rb b/lib/dataset.rb index 0a2f770..2b5759e 100644 --- a/lib/dataset.rb +++ b/lib/dataset.rb @@ -293,7 +293,7 @@ module OpenTox else compounds.each do |c| features.each do |f| - unless @data_entries[c][f] + if @data_entries[c]==nil or @data_entries[c][f]==nil dataset.add(c,f,nil) else @data_entries[c][f].each do |v| diff --git a/lib/feature.rb b/lib/feature.rb index eb0b869..2f1ab6c 100644 --- a/lib/feature.rb +++ b/lib/feature.rb @@ -16,12 +16,7 @@ module OpenTox feature end - # provides domain (possible target values) of classification feature - # @return [Array] list with possible target values - def domain - return [true, false] - end - + # provides feature type, possible types are "regression" or "classification" # @return [String] feature type, unknown if OT.isA property is unknown/ not set def feature_type diff --git a/lib/helper.rb b/lib/helper.rb index af92419..3a6126a 100644 --- a/lib/helper.rb +++ b/lib/helper.rb @@ -44,14 +44,8 @@ helpers do def uri_available?(urlStr) url = URI.parse(urlStr) - unless @subjectid - Net::HTTP.start(url.host, url.port) do |http| - return http.head(url.request_uri).code == "200" - end - else - Net::HTTP.start(url.host, url.port) do |http| - return http.post(url.request_uri, "subjectid=#{@subjectid}").code == "202" - end + Net::HTTP.start(url.host, url.port) do |http| + return http.head("#{url.request_uri}?subjectid=#{CGI.escape @subjectid}").code == "200" end end diff --git a/lib/overwrite.rb b/lib/overwrite.rb index fffcb14..df4e1b7 100644 --- a/lib/overwrite.rb +++ b/lib/overwrite.rb @@ -8,6 +8,7 @@ before { $url_provider = self # stupid internet explorer does not ask for text/html, add this manually request.env['HTTP_ACCEPT'] += ";text/html" if request.env["HTTP_USER_AGENT"]=~/MSIE/ + request.env['HTTP_ACCEPT']=request.params["media"] if request.params["media"] } # Error handling diff --git a/lib/parser.rb b/lib/parser.rb index dc5f675..7bdee95 100644 --- a/lib/parser.rb +++ b/lib/parser.rb @@ -163,6 +163,7 @@ module OpenTox data = {} feature_values = {} feature = {} + feature_accept_values = {} other_statements = {} `rapper -i rdfxml -o ntriples #{file.path} 2>/dev/null`.each_line do |line| triple = line.chomp.split(' ',3) @@ -182,6 +183,9 @@ module OpenTox if triple[2]=~/#{OT.Compound}/i and !data[triple[0]] data[triple[0]] = {:compound => triple[0], :values => []} end + when /#{OT.acceptValue}/i # acceptValue in ambit datasets is only provided in dataset/<id> no in dataset/<id>/features + feature_accept_values[triple[0]] = [] unless feature_accept_values[triple[0]] + feature_accept_values[triple[0]] << triple[2] else end end @@ -192,20 +196,25 @@ module OpenTox @dataset.add_compound(entry[:compound]) else entry[:values].each do |value_id| - split = feature_values[value_id].split(/\^\^/) - case split[-1] - when XSD.double, XSD.float - value = split.first.to_f - when XSD.boolean - value = split.first=~/(?i)true/ ? true : false - else - value = split.first + if feature_values[value_id] + split = feature_values[value_id].split(/\^\^/) + case split[-1] + when XSD.double, XSD.float + value = split.first.to_f + when XSD.boolean + value = split.first=~/(?i)true/ ? true : false + else + value = split.first + end end @dataset.add entry[:compound],feature[value_id],value end end end load_features subjectid + feature_accept_values.each do |feature, values| + @dataset.features[feature][OT.acceptValue] = values + end @dataset.metadata = load_metadata(subjectid) @dataset end @@ -348,27 +357,23 @@ module OpenTox when OT.NominalFeature case value.to_s when TRUE_REGEXP - #@dataset.add(compound.uri, feature, true ) - val=true + val = true when FALSE_REGEXP - #@dataset.add(compound.uri, feature, false ) - val=false + val = false end when OT.NumericFeature - #@dataset.add compound.uri, feature, value.to_f val = value.to_f when OT.StringFeature - #@dataset.add compound.uri, feature, value.to_s val = value.to_s @activity_errors << smiles+", "+row.join(", ") end - if val!=nil - @dataset.add(compound.uri, feature, val) - if type!=OT.NumericFeature - @dataset.features[feature][OT.acceptValue] = [] unless @dataset.features[feature][OT.acceptValue] - @dataset.features[feature][OT.acceptValue] << val.to_s unless @dataset.features[feature][OT.acceptValue].include?(val.to_s) - end - end + if val!=nil + @dataset.add(compound.uri, feature, val) + if type!=OT.NumericFeature + @dataset.features[feature][OT.acceptValue] = [] unless @dataset.features[feature][OT.acceptValue] + @dataset.features[feature][OT.acceptValue] << val.to_s unless @dataset.features[feature][OT.acceptValue].include?(val.to_s) + end + end end end diff --git a/lib/rest_client_wrapper.rb b/lib/rest_client_wrapper.rb index dac24dc..747a353 100644 --- a/lib/rest_client_wrapper.rb +++ b/lib/rest_client_wrapper.rb @@ -98,6 +98,8 @@ module OpenTox rescue RestClient::RequestTimeout => ex received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload} + rescue Errno::ETIMEDOUT => ex + received_error ex.message, 408, nil, {:rest_uri => uri, :headers => headers, :payload => payload} rescue Errno::ECONNREFUSED => ex received_error ex.message, 500, nil, {:rest_uri => uri, :headers => headers, :payload => payload} rescue RestClient::ExceptionWithResponse => ex diff --git a/lib/serializer.rb b/lib/serializer.rb index 644a09f..e4cb541 100644 --- a/lib/serializer.rb +++ b/lib/serializer.rb @@ -26,6 +26,8 @@ module OpenTox OT.Algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } , OT.Parameter => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } , OT.Task => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } , + OTA.PatternMiningSupervised => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } , + #classes for validation OT.Validation => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } , OT.ClassificationStatistics => { RDF["type"] => [{ "type" => "uri", "value" => OWL['Class'] }] } , @@ -40,10 +42,10 @@ module OpenTox OT.compound => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , OT.feature => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , OT.dataEntry => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , - OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , OT.values => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , OT.algorithm => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , OT.parameters => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , + #object props for validation# OT.model => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , OT.trainingDataset => { RDF["type"] => [{ "type" => "uri", "value" => OWL.ObjectProperty }] } , @@ -73,6 +75,8 @@ module OpenTox OT.hasStatus => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } , OT.resultURI => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } , OT.percentageCompleted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } , + OT.acceptValue => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } , + # annotation props for validation OT.numUnpredicted => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } , OT.crossvalidationFold => { RDF["type"] => [{ "type" => "uri", "value" => OWL.AnnotationProperty }] } , @@ -256,7 +260,8 @@ module OpenTox def add_metadata(uri,metadata) id = 0 metadata.each do |u,v| - if v.is_a? Array and u == OT.parameters + #if v.is_a? Array and (u == OT.parameters or u == RDF.type) + if v.is_a? Array and u == OT.parameters#or u == RDF.type) @object[uri][u] = [] unless @object[uri][u] v.each do |value| id+=1 @@ -267,7 +272,13 @@ module OpenTox @object[genid][name] = [{"type" => type(entry), "value" => entry }] end end - else # v.is_a? String + elsif v.is_a? Array and u == RDF.type + @object[uri] = {} unless @object[uri] + v.each do |value| + @object[uri][u] = [] unless @object[uri][u] + @object[uri][u] << {"type" => type(value), "value" => value } + end + elsif v.is_a? String @object[uri] = {} unless @object[uri] @object[uri][u] = [{"type" => type(v), "value" => v }] end @@ -309,6 +320,7 @@ module OpenTox OT.value => v } @object[feature][RDF["type"]] << { "type" => "uri", "value" => featuretype(value) } + #@object[feature][RDF["type"]] = { "type" => "uri", "value" => featuretype(value) } end # Serializers diff --git a/lib/validation.rb b/lib/validation.rb index 8fa95bb..d7a337c 100644 --- a/lib/validation.rb +++ b/lib/validation.rb @@ -12,6 +12,18 @@ module OpenTox val end + # returns a filtered list of validation uris + # @param [Hash,optional] params, validation-params to filter the uris (could be model, training_dataset, ..) + # @return [Array] + def self.list( params={} ) + filter_string = "" + params.each do |k,v| + filter_string = "?" if filter_string.length==0 + filter_string += k.to_s+"="+v + end + (OpenTox::RestClientWrapper.get(CONFIG[:services]["opentox-validation"]+filter_string).split("\n")) + end + # creates a training test split validation, waits until it finishes, may take some time # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,split_ratio(0.67),random_seed(1)) # @param [String,optional] subjectid @@ -34,7 +46,6 @@ module OpenTox @report.uri end - # creates a validation object from crossvaldiation statistics, raise error if not found # (as crossvaldiation statistics are returned as an average valdidation over all folds) # @param [String] crossvalidation uri @@ -54,7 +65,7 @@ module OpenTox def summary if @metadata[OT.classificationStatistics] res = { - :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted], + :nr_predictions => @metadata[OT.numInstances].to_i - @metadata[OT.numUnpredicted].to_i, :correct_predictions => @metadata[OT.classificationStatistics][OT.percentCorrect], :weighted_area_under_roc => @metadata[OT.classificationStatistics][OT.weightedAreaUnderRoc], } @@ -72,7 +83,7 @@ module OpenTox res elsif @metadata[OT.regressionStatistics] { - :nr_predictions => @metadata[OT.numInstances] - @metadata[OT.numUnpredicted], + :nr_predictions => @metadata[OT.numInstances].to_i - @metadata[OT.numUnpredicted].to_i, :r_square => @metadata[OT.regressionStatistics][OT.rSquare], :root_mean_squared_error => @metadata[OT.regressionStatistics][OT.rootMeanSquaredError], :mean_absolute_error => @metadata[OT.regressionStatistics][OT.meanAbsoluteError], @@ -95,6 +106,18 @@ module OpenTox cv.load_metadata( subjectid ) cv end + + # returns a filtered list of crossvalidation uris + # @param [Hash,optional] params, crossvalidation-params to filter the uris (could be algorithm, dataset, ..) + # @return [Array] + def self.list( params={} ) + filter_string = "" + params.each do |k,v| + filter_string = "?" if filter_string.length==0 + filter_string += k.to_s+"="+v + end + (OpenTox::RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"],"crossvalidation")+filter_string).split("\n")) + end # creates a crossvalidations, waits until it finishes, may take some time # @param [Hash] params (required:algorithm_uri,dataset_uri,prediction_feature, optional:algorithm_params,num_folds(10),random_seed(1),stratified(false)) @@ -138,9 +161,10 @@ module OpenTox # @param [String,optional] subjectid # @return [OpenTox::ValidationReport] def self.find( uri, subjectid=nil ) - # PENDING load report data? OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid}) - ValidationReport.new(uri) + rep = ValidationReport.new(uri) + rep.load_metadata( subjectid ) + rep end # finds ValidationReport for a particular validation @@ -174,9 +198,10 @@ module OpenTox # @param [String,optional] subjectid # @return [OpenTox::CrossvalidationReport] def self.find( uri, subjectid=nil ) - # PENDING load report data? OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid}) - CrossvalidationReport.new(uri) + rep = CrossvalidationReport.new(uri) + rep.load_metadata( subjectid ) + rep end # finds CrossvalidationReport for a particular crossvalidation @@ -201,6 +226,54 @@ module OpenTox end end + + class AlgorithmComparisonReport + include OpenTox + + # finds AlgorithmComparisonReport via uri, raises error if not found + # @param [String] uri + # @param [String,optional] subjectid + # @return [OpenTox::CrossvalidationReport] + def self.find( uri, subjectid=nil ) + OpenTox::RestClientWrapper.get(uri,{:subjectid => subjectid}) + rep = AlgorithmComparisonReport.new(uri) + rep.load_metadata( subjectid ) + rep + end + + # finds AlgorithmComparisonReport for a particular crossvalidation + # @param [String] crossvalidation uri + # @param [String,optional] subjectid + # @return [OpenTox::AlgorithmComparisonReport] nil if no report found + def self.find_for_crossvalidation( crossvalidation_uri, subjectid=nil ) + uris = RestClientWrapper.get(File.join(CONFIG[:services]["opentox-validation"], + "/report/algorithm_comparison?crossvalidation="+crossvalidation_uri), {:subjectid => subjectid}).chomp.split("\n") + uris.size==0 ? nil : AlgorithmComparisonReport.new(uris[-1]) + end + + # creates a crossvalidation report via crossvalidation + # @param [Hash] crossvalidation uri_hash, see example + # @param [String,optional] subjectid + # @param [OpenTox::Task,optional] waiting_task (can be a OpenTox::Subtask as well), progress is updated accordingly + # @return [OpenTox::AlgorithmComparisonReport] + # example for hash: + # { :lazar-bbrc => [ http://host/validation/crossvalidation/x1, http://host/validation/crossvalidation/x2 ], + # :lazar-last => [ http://host/validation/crossvalidation/xy, http://host/validation/crossvalidation/xy ] } + def self.create( crossvalidation_uri_hash, subjectid=nil, waiting_task=nil ) + identifier = [] + validation_uris = [] + crossvalidation_uri_hash.each do |id, uris| + uris.each do |uri| + identifier << id + validation_uris << uri + end + end + uri = RestClientWrapper.post(File.join(CONFIG[:services]["opentox-validation"],"/report/algorithm_comparison"), + { :validation_uris => validation_uris.join(","), :identifier => identifier.join(","), :subjectid => subjectid }, {}, waiting_task ) + AlgorithmComparisonReport.new(uri) + end + end + class QMRFReport include OpenTox |