Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OKB/HeuristicLab.Services.OKB/3.3/RunnerService.cs @ 4480

Last change on this file since 4480 was 4381, checked in by swagner, 14 years ago

Worked on OKB data model and services (#1174).

File size: 13.1 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Data.Linq;
25using System.Linq;
26using System.ServiceModel;
27using System.Web.Security;
28using HeuristicLab.Services.OKB.DataAccess;
29
30namespace HeuristicLab.Services.OKB {
31  /// <summary>
32  /// Implementation of the <see cref="IRunnerService"/>.
33  /// </summary>
34  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
35  public class RunnerService : IRunnerService, IDisposable {
36    /// <summary>
37    /// Obtain a "starter kit" of information, containing:
38    /// <list>
39    /// <item>algorithm classes including algorithms</item>
40    /// <item>problem classes including problems</item>
41    /// <item>projects</item>
42    /// </list>
43    /// </summary>
44    public StarterKit GetStarterKit(string platformName) {
45      Platform platform;
46      using (OKBDataContext okb = new OKBDataContext()) {
47        try {
48          platform = okb.Platforms.Single(p => p.Name == platformName);
49        }
50        catch (InvalidOperationException) {
51          throw new FaultException(String.Format(
52            "Invalid platform name \"{0}\" available platforms are: \"{1}\"",
53            platformName,
54            string.Join("\", \"", okb.Platforms.Select(p => p.Name).ToArray())));
55        }
56      }
57      using (OKBDataContext okb = new OKBDataContext()) {
58        DataLoadOptions dlo = new DataLoadOptions();
59        dlo.LoadWith<AlgorithmClass>(ac => ac.Algorithms);
60        dlo.AssociateWith<AlgorithmClass>(ac => ac.Algorithms.Where(a => a.Platform == platform));
61        dlo.LoadWith<ProblemClass>(p => p.Problems);
62        dlo.AssociateWith<ProblemClass>(pc => pc.Problems.Where(p => p.Platform == platform));
63        okb.LoadOptions = dlo;
64        var StarterKit = new StarterKit() {
65          AlgorithmClasses = okb.AlgorithmClasses.ToList(),
66          ProblemClasses = okb.ProblemClasses.ToList()
67        };
68        return StarterKit;
69      }
70    }
71
72    /// <summary>
73    /// Augument the given algorithm and problem entities with information
74    /// to conduct an experiment. This will add algorithm parameters and results and
75    /// problem characteristic values and solution representation as well as data
76    /// necessary for deserialization.
77    /// </summary>
78    public ExperimentKit PrepareExperiment(Algorithm algorithm, Problem problem) {
79      OKBDataContext okb = new OKBDataContext();
80      try {
81        DataLoadOptions dlo = new DataLoadOptions();
82        dlo.LoadWith<Problem>(p => p.SolutionRepresentation);
83        dlo.LoadWith<AlgorithmParameter>(p => p.DataType);
84        dlo.LoadWith<ProblemParameter>(p => p.DataType);
85        dlo.LoadWith<Result>(r => r.DataType);
86        okb.LoadOptions = dlo;
87        algorithm = okb.Algorithms.Single(a => a.Id == algorithm.Id);
88        problem = okb.Problems.Single(p => p.Id == problem.Id);
89        algorithm.AlgorithmParameters.Load();
90        algorithm.Results.Load();
91        problem.ProblemCharacteristicIntValues.Load();
92        problem.ProblemCharacteristicFloatValues.Load();
93        problem.ProblemCharacteristicStringValues.Load();
94        problem.ProblemParameters.Load();
95        return new ExperimentKit() {
96          Algorithm = algorithm,
97          Problem = problem
98        };
99      }
100      catch (Exception x) {
101        throw new FaultException("Excaption caught: " + x.ToString());
102      }
103    }
104
105    /// <summary>
106    /// Adds the a new <see cref="Experiment"/>
107    ///   <see cref="Run"/>.
108    /// The <see cref="Experiment"/> is created if necessary as well as
109    /// all <see cref="Parameter"/>s and <see cref="Result"/>s. If an
110    /// identical experiment has been conducted before the new run is
111    /// linked to this previous experiment instead.
112    /// </summary>
113    /// <param name="algorithm">The algorithm.</param>
114    /// <param name="problem">The problem.</param>
115    /// <param name="project">The project.</param>
116    public void AddRun(Algorithm algorithm, Problem problem) {
117      try {
118        using (OKBDataContext okb = new OKBDataContext()) {
119          Experiment experiment = GetOrCreateExperiment(algorithm, problem, currentUser, okb);
120          Run run = new Run() {
121            Experiment = experiment,
122            UserId = currentUser.Id,
123            ClientId = currentClient.Id,
124            FinishedDate = DateTime.Now,
125            ResultValues = algorithm.ResultValues
126          };
127          okb.Runs.InsertOnSubmit(run);
128          okb.SubmitChanges();
129        }
130      }
131      catch (Exception x) {
132        throw new FaultException("Could not add run: " + x.ToString());
133      }
134    }
135
136    private Experiment GetOrCreateExperiment(Algorithm algorithm, Problem problem, User user, OKBDataContext okb) {
137      MatchResults(algorithm.Results, okb);
138      EnsureParametersExist(algorithm.Parameters, okb);
139      var experimentQuery = CreateExperimentQuery(algorithm, problem, okb);
140      if (experimentQuery.Count() > 0) {
141        Experiment experiment = experimentQuery.First();
142        return experiment;
143      } else {
144        Experiment experiment = new Experiment() {
145          AlgorithmId = algorithm.Id,
146          ProblemId = problem.Id,
147          ParameterValues = algorithm.ParameterValues
148        };
149        okb.Experiments.InsertOnSubmit(experiment);
150        return experiment;
151      }
152    }
153
154    private void MatchResults(IQueryable<Result> results, OKBDataContext okb) {
155      foreach (var result in results.Where(r => r.Name != null)) {
156        result.Id = okb.Results.Single(r => r.Name == result.Name).Id;
157        var value = result.ResultValue;
158        if (value != null) {
159          result.ResultValue = (IResultValue)Activator.CreateInstance(value.GetType());
160          result.ResultValue.Result = result;
161          result.ResultValue.Value = value.Value;
162        }
163      }
164    }
165
166    private void EnsureParametersExist(IQueryable<Parameter> parameters, OKBDataContext okb) {
167      foreach (var param in parameters.Where(p => p.DataType != null && p.DataType.ClrName != null)) {
168        DataType dataType = GetOrCreateDataType(okb, param.DataType.ClrName);
169        param.DataType = new DataType() { Id = dataType.Id };
170      }
171      okb.SubmitChanges();
172      var namedParams = parameters.Where(p => p.Name != null);
173      var newParams = namedParams.Except(okb.Parameters, new NameComprarer());
174      foreach (var p in newParams) {
175        okb.Parameters.InsertOnSubmit(new Parameter() {
176          Name = p.Name,
177          DataTypeId = p.DataTypeId,
178        });
179      }
180      okb.SubmitChanges();
181      foreach (var np in namedParams) {
182        np.Id = okb.Parameters.Single(p => p.Name == np.Name).Id;
183        var value = np.ParameterValue;
184        if (value != null) {
185          OperatorParameterValue opVal = value as OperatorParameterValue;
186          np.ParameterValue = (IParameterValue)Activator.CreateInstance(value.GetType());
187          np.ParameterValue.Parameter = np;
188          np.ParameterValue.Value = value.Value;
189          if (opVal != null) {
190            OperatorParameterValue newVal = np.ParameterValue as OperatorParameterValue;
191            DataType dataType = GetOrCreateDataType(okb, opVal.DataType.ClrName);
192            newVal.DataType = new DataType() { Id = dataType.Id };
193          }
194        }
195      }
196    }
197
198    private DataType GetOrCreateDataType(OKBDataContext okb, string clrName) {
199      DataType dataType = okb.DataTypes.SingleOrDefault(dt => dt.ClrName == clrName);
200      if (dataType == null) {
201        dataType = new DataType() {
202          ClrName = clrName,
203          SqlName = "BLOB",
204        };
205        okb.DataTypes.InsertOnSubmit(dataType);
206        okb.SubmitChanges();
207      }
208      return dataType;
209    }
210
211    private IQueryable<Experiment> CreateExperimentQuery(Algorithm algorithm, Problem problem, OKBDataContext okb) {
212      var experimentQuery =
213        from x in okb.Experiments
214        where x.Algorithm == algorithm
215        where x.Problem == problem
216        select x;
217      foreach (IntParameterValue ipv in algorithm.IntParameterValues) {
218        experimentQuery = experimentQuery
219          .Where(x => x.IntParameterValues.Any(p =>
220            p.ParameterId == ipv.ParameterId && p.Value == ipv.Value));
221      }
222      foreach (FloatParameterValue fpv in algorithm.FloatParameterValues) {
223        experimentQuery = experimentQuery
224          .Where(x => x.FloatParameterValues.Any(p =>
225            p.ParameterId == fpv.ParameterId && p.Value == fpv.Value));
226      }
227      foreach (CharParameterValue cpv in algorithm.CharParameterValues) {
228        experimentQuery = experimentQuery
229          .Where(x => x.CharParameterValues.Any(p =>
230            p.ParameterId == cpv.ParameterId && p.Value == cpv.Value));
231      }
232      foreach (OperatorParameterValue opv in algorithm.OperatorParameterValues) {
233        experimentQuery = experimentQuery
234          .Where(x => x.OperatorParameterValues.Any(p =>
235            p.ParameterId == opv.ParameterId && p.DataTypeId == opv.DataTypeId));
236      }
237      return experimentQuery;
238    }
239
240    /// <summary>
241    /// Determines whether this instance is connected.
242    /// </summary>
243    /// <returns>
244    ///   <c>true</c> if this instance is connected; otherwise, <c>false</c>.
245    /// </returns>
246    public bool IsConnected() {
247      return currentUser != null;
248    }
249
250    User currentUser = null;
251    Client currentClient = null;
252
253    /// <summary>
254    /// Logs the specified username in. In case the user or client
255    /// does not exist yet, they are created on the server. This
256    /// method is currently not used for authentication but merely
257    /// for auditing.
258    /// </summary>
259    /// <param name="username">The username.</param>
260    /// <param name="clientname">The clientname.</param>
261    /// <returns>
262    ///   <c>true</c> if the login was successful; <c>false</c> otherwise.
263    /// </returns>
264    public bool Login(string clientname) {
265      MembershipUser user = Membership.GetUser();
266
267      if (user == null ||
268          string.IsNullOrEmpty(clientname) ||
269          ServiceSecurityContext.Current.IsAnonymous) {
270        return false;
271      }
272      using (OKBDataContext okb = new OKBDataContext()) {
273        currentUser = okb.Users.SingleOrDefault(u => u.Id == (Guid)user.ProviderUserKey);
274        currentClient = okb.Clients.SingleOrDefault(c => c.Name == clientname);
275        if (currentUser == null) {
276          currentUser = new User() { Name = user.UserName, Id = (Guid)user.ProviderUserKey };
277          okb.Users.InsertOnSubmit(currentUser);
278          okb.SubmitChanges();
279        }
280        if (currentClient == null) {
281          currentClient = new Client() { Name = clientname, Id = Guid.NewGuid() };
282          okb.Clients.InsertOnSubmit(currentClient);
283          okb.SubmitChanges();
284        }
285        return true;
286      }
287    }
288
289    /// <summary>
290    /// Logout out and closes the connection.
291    /// </summary>
292    public void Logout() {
293      currentUser = null;
294      currentClient = null;
295    }
296
297    /// <summary>
298    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
299    /// </summary>
300    public void Dispose() {
301      Logout();
302    }
303  }
304
305  /// <summary>
306  /// Compares two parameters by name.
307  /// </summary>
308  internal class NameComprarer : IEqualityComparer<Parameter> {
309
310    /// <summary>
311    /// Determines whether the specified objects are equal.
312    /// </summary>
313    /// <param name="x">The first object of type <paramref name="T"/> to compare.</param>
314    /// <param name="y">The second object of type <paramref name="T"/> to compare.</param>
315    /// <returns>
316    /// true if the specified objects are equal; otherwise, false.
317    /// </returns>
318    public bool Equals(Parameter x, Parameter y) {
319      return x.Name == y.Name;
320    }
321
322    /// <summary>
323    /// Returns a hash code for this instance.
324    /// </summary>
325    /// <param name="obj">The obj.</param>
326    /// <returns>
327    /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
328    /// </returns>
329    /// <exception cref="T:System.ArgumentNullException">
330    /// The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.
331    /// </exception>
332    public int GetHashCode(Parameter obj) {
333      return obj.Name.GetHashCode();
334    }
335  }
336}
Note: See TracBrowser for help on using the repository browser.