summaryrefslogtreecommitdiff
path: root/validation/validation_application.rb
blob: a43a2a6b77a4e9d40e87137ca1781dcf9fbd25a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256

[ 'rubygems', 'sinatra', 'sinatra/url_for', 'active_record', 'ar-extensions', 'opentox-ruby-api-wrapper' ].each do |lib|
  require lib
end

require 'validation/validation_service.rb'
require 'lib/merge.rb'

get '/crossvalidation/?' do
  LOGGER.info "list all crossvalidations"
  content_type "text/uri-list"
  params.each{ |k,v| halt 400,"no crossvalidation-attribute: "+k.to_s unless Validation::Crossvalidation.column_names.include?(k.gsub(/_like$/,""))  }
  Validation::Crossvalidation.find(:all, :conditions => params).collect{ |d| url_for("/crossvalidation/", :full) + d.id.to_s }.join("\n")
end

post '/crossvalidation/loo/?' do
  halt 500, "not yet implemented"
end

get '/crossvalidation/loo/?' do
  halt 400, "GET operation not supported, use POST for performing a loo-crossvalidation, see "+url_for("/crossvalidation", :full)+" for crossvalidation results"
end

get '/crossvalidation/:id' do
  LOGGER.info "get crossvalidation with id "+params[:id].to_s
  begin
    crossvalidation = Validation::Crossvalidation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Crossvalidation '#{params[:id]}' not found."
  end
  
  case request.env['HTTP_ACCEPT'].to_s
  when "application/rdf+xml"
    content_type "application/rdf+xml"
    result = crossvalidation.to_rdf
  when /application\/x-yaml|\*\/\*|/ # matches 'text/x-yaml', '*/*', ''
    content_type "application/x-yaml"
    result = crossvalidation.to_yaml
  else
    halt 400, "MIME type '"+request.env['HTTP_ACCEPT'].to_s+"' not supported."
  end
  result
end

delete '/crossvalidation/:id/?' do
  LOGGER.info "delete crossvalidation with id "+params[:id].to_s
  content_type "text/plain"
  begin
    crossvalidation = Validation::Crossvalidation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Crossvalidation '#{params[:id]}' not found."
  end
  Validation::Crossvalidation.delete(params[:id])
end

get '/crossvalidation/:id/validations' do
  LOGGER.info "get all validations for crossvalidation with id "+params[:id].to_s
  begin
    crossvalidation = Validation::Crossvalidation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Crossvalidation '#{params[:id]}' not found."
  end
  content_type "text/uri-list"
  Validation::Validation.find( :all, :conditions => { :crossvalidation_id => params[:id] } ).collect{ |v| v.validation_uri.to_s }.join("\n")+"\n"
end


get '/crossvalidation/:id/statistics' do
  LOGGER.info "get merged validation-result for crossvalidation with id "+params[:id].to_s
  begin
    crossvalidation = Validation::Crossvalidation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Crossvalidation '#{params[:id]}' not found."
  end
  
  Lib::MergeObjects.register_merge_attributes( Validation::Validation,
    Lib::VAL_MERGE_AVG,Lib::VAL_MERGE_SUM,Lib::VAL_MERGE_GENERAL-[:validation_uri]) unless 
      Lib::MergeObjects.merge_attributes_registered?(Validation::Validation)
  
  v = Lib::MergeObjects.merge_array_objects( Validation::Validation.find( :all, :conditions => { :crossvalidation_id => params[:id] } ) )
  v.validation_uri = nil
  v.created_at = nil
  v.id = nil
  content_type "application/x-yaml"
  v.to_yaml
end


post '/crossvalidation/?' do
  content_type "text/uri-list"
  task_uri = OpenTox::Task.as_task do
    LOGGER.info "creating crossvalidation "+params.inspect
    halt 400, "dataset_uri missing" unless params[:dataset_uri]
    halt 400, "algorithm_uri missing" unless params[:algorithm_uri]
    halt 400, "prediction_feature missing" unless params[:prediction_feature]
    halt 400, "illegal param-value num_folds: '"+params[:num_folds].to_s+"', must be integer >1" unless params[:num_folds]==nil or 
      params[:num_folds].to_i>1
    
    cv_params = { :dataset_uri => params[:dataset_uri],  
                  :algorithm_uri => params[:algorithm_uri] }
    [ :num_folds, :random_seed, :stratified ].each{ |sym| cv_params[sym] = params[sym] if params[sym] }
    cv = Validation::Crossvalidation.new cv_params
    cv.create_cv_datasets( params[:prediction_feature] )
    cv.perform_cv( params[:algorithm_params])
    content_type "text/uri-list"
    cv.crossvalidation_uri
  end
  halt 202,task_uri
end

get '/training_test_split' do
  halt 400, "GET operation not supported, use POST to perform a training_test_split, see "+url_for("/", :full)+" for validation results"
end

get '/?' do
  LOGGER.info "list all validations"
  content_type "text/uri-list"
  params.each{ |k,v| halt 400,"no validation-attribute: "+k.to_s unless Validation::Validation.column_names.include?(k.gsub(/_like$/,""))  }
  Validation::Validation.find(:all, :conditions => params).collect{ |d| url_for("/", :full) + d.id.to_s }.join("\n")
end

get '/:id' do
  LOGGER.info "get validation with id "+params[:id].to_s+" '"+request.env['HTTP_ACCEPT'].to_s+"'"
  begin
    validation = Validation::Validation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Validation '#{params[:id]}' not found."
  end

  case request.env['HTTP_ACCEPT'].to_s
  when "application/rdf+xml"
    content_type "application/rdf+xml"
    result = validation.to_rdf
  when /application\/x-yaml|\*\/\*|^$/ # matches 'application/x-yaml', '*/*', ''
    content_type "application/x-yaml"
    result = validation.to_yaml
  else
    halt 400, "MIME type '"+request.env['HTTP_ACCEPT'].to_s+"' not supported, valid Accept-Headers are \"application/rdf+xml\" and \"application/x-yaml\"."
  end
  result
end

post '/?' do
  content_type "text/uri-list"
  task_uri = OpenTox::Task.as_task do |task|
    LOGGER.info "creating validation "+params.inspect
    if params[:model_uri] and params[:test_dataset_uri] and !params[:training_dataset_uri] and !params[:algorithm_uri]
      v = Validation::Validation.new :model_uri => params[:model_uri], 
                       :test_dataset_uri => params[:test_dataset_uri],
                       :test_target_dataset_uri => params[:test_target_dataset_uri],
                       :prediction_feature => params[:prediction_feature]
      v.validate_model
    elsif params[:algorithm_uri] and params[:training_dataset_uri] and params[:test_dataset_uri] and params[:prediction_feature] and !params[:model_uri]
     v = Validation::Validation.new :algorithm_uri => params[:algorithm_uri],
                        :training_dataset_uri => params[:training_dataset_uri], 
                        :test_dataset_uri => params[:test_dataset_uri],
                        :test_target_dataset_uri => params[:test_target_dataset_uri],
                        :prediction_feature => params[:prediction_feature]
     v.validate_algorithm( params[:algorithm_params]) 
    else
      halt 400, "illegal parameter combination for validation, use either\n"+
        "* model_uri, test_dataset_uri\n"+ 
        "* algorithm_uri, training_dataset_uri, test_dataset_uri, prediction_feature\n"+
        "params given: "+params.inspect
    end
    content_type "text/uri-list"
    v.validation_uri
  end
  halt 202,task_uri
end

post '/training_test_split' do
  content_type "text/uri-list"
  task_uri = OpenTox::Task.as_task do
    LOGGER.info "creating training test split "+params.inspect
    halt 400, "dataset_uri missing" unless params[:dataset_uri]
    halt 400, "algorithm_uri missing" unless params[:algorithm_uri]
    halt 400, "prediction_feature missing" unless params[:prediction_feature]
    
    params.merge!(Validation::Util.train_test_dataset_split(params[:dataset_uri], params[:prediction_feature], params[:split_ratio], params[:random_seed]))
    v = Validation::Validation.new :training_dataset_uri => params[:training_dataset_uri], 
                     :test_dataset_uri => params[:test_dataset_uri],
                     :test_target_dataset_uri => params[:dataset_uri],
                     :prediction_feature => params[:prediction_feature],
                     :algorithm_uri => params[:algorithm_uri]
    v.validate_algorithm( params[:algorithm_params])
    content_type "text/uri-list"
    v.validation_uri
  end
  halt 202,task_uri
end


post '/plain_training_test_split' do
    LOGGER.info "creating pure training test split "+params.inspect
    halt 400, "dataset_uri missing" unless params[:dataset_uri]
    
    result = Validation::Util.train_test_dataset_split(params[:dataset_uri], params[:prediction_feature], params[:split_ratio], params[:random_seed])
    content_type "text/uri-list"
    result[:training_dataset_uri]+"\n"+result[:test_dataset_uri]+"\n"
end

post '/validate_datasets' do
  content_type "text/uri-list"
  task_uri = OpenTox::Task.as_task do
    LOGGER.info "validating values "+params.inspect
    halt 400, "test_dataset_uri missing" unless params[:test_dataset_uri]
    halt 400, "prediction_datset_uri missing" unless params[:prediction_dataset_uri]
    
    if params[:model_uri]
      v = Validation::Validation.new params
      v.compute_validation_stats_with_model()
    else
      halt 400, "please specify 'model_uri' or 'prediction_feature'" unless params[:prediction_feature]
      halt 400, "please specify 'model_uri' or 'predicted_feature'" unless params[:predicted_feature]
      halt 400, "please specify 'model_uri' or set either 'classification' or 'regression' flag" unless 
            params[:classification] or params[:regression]
      
      predicted_feature = params.delete("predicted_feature")
      clazz = params.delete("classification")!=nil
      regr = params.delete("regression")!=nil
      v = Validation::Validation.new params            
      v.compute_validation_stats((clazz and !regr),predicted_feature)
    end
    content_type "text/uri-list"
    v.validation_uri
  end
  halt 202,task_uri
end

get '/:id/:attribute' do
  LOGGER.info "access validation attribute "+params.inspect
  begin
    validation = Validation::Validation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Validation '#{params[:id]}' not found."
  end
  begin
    raise unless validation.attribute_loaded?(params[:attribute])
  rescue
    halt 400, "Not a validation attribute: "+params[:attribute].to_s
  end
  content_type "text/plain"
  return validation.send(params[:attribute])
end

delete '/:id' do
  LOGGER.info "delete validation with id "+params[:id].to_s
  begin
    validation = Validation::Validation.find(params[:id])
  rescue ActiveRecord::RecordNotFound => ex
    halt 404, "Validation '#{params[:id]}' not found."
  end
  content_type "text/plain"
  Validation::Validation.delete(params[:id])
end