Index: branches/1614_GeneralizedQAP/HeuristicLab.Algorithms.GRASP/3.3/HeuristicLab.Algorithms.GRASP-3.3.csproj
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Algorithms.GRASP/3.3/HeuristicLab.Algorithms.GRASP-3.3.csproj	(revision 15688)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Algorithms.GRASP/3.3/HeuristicLab.Algorithms.GRASP-3.3.csproj	(revision 15698)
@@ -108,5 +108,4 @@
       <Project>{14ab8d24-25bc-400c-a846-4627aa945192}</Project>
       <Name>HeuristicLab.Optimization-3.3</Name>
-      <Private>False</Private>
     </ProjectReference>
   </ItemGroup>
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/CPLEX/CplexSolver.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/CPLEX/CplexSolver.cs	(revision 15688)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/CPLEX/CplexSolver.cs	(revision 15698)
@@ -28,4 +28,5 @@
 using HeuristicLab.Encodings.IntegerVectorEncoding;
 using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using ILOG.CPLEX;
@@ -49,12 +50,22 @@
     }
 
+    [Storable]
+    private ValueParameter<DateTimeValue> lastUpdateTimeParameter;
+    public IValueParameter<DateTimeValue> LastUpdateTimeParameter {
+      get { return lastUpdateTimeParameter; }
+    }
+
     [StorableConstructor]
     protected CplexSolver(bool deserializing) : base(deserializing) { }
     protected CplexSolver(CplexSolver original, Cloner cloner)
     : base(original, cloner) {
+      lastUpdateTimeParameter = cloner.Clone(original.lastUpdateTimeParameter);
     }
     public CplexSolver() {
       Problem = new GQAP();
-      ((MultiAnalyzer)Analyzer).AddOperator(new QualityPerClockAnalyzer());
+      Parameters.Add(lastUpdateTimeParameter = new ValueParameter<DateTimeValue>("LastUpdateTime", "") { Hidden = true });
+      var qpc = new QualityPerClockAnalyzer();
+      qpc.LastUpdateTimeParameter.ActualName = LastUpdateTimeParameter.Name;
+      ((MultiAnalyzer)Analyzer).AddOperator(qpc);
     }
 
@@ -69,4 +80,5 @@
         opl.AddDataSource(dataSource);
         opl.Generate();
+        LastUpdateTimeParameter.Value = new DateTimeValue(DateTime.UtcNow);
         cplex.Solve();
         cplex.End();
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj	(revision 15688)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj	(revision 15698)
@@ -142,4 +142,6 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Infrastructure\SingleObjectiveSolutionScope.cs" />
+    <Compile Include="RandomSearch\RandomSearchContext.cs" />
+    <Compile Include="RandomSearch\RandomSearch.cs" />
   </ItemGroup>
   <ItemGroup>
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPBinarySolver.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPBinarySolver.cs	(revision 15688)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPBinarySolver.cs	(revision 15698)
@@ -21,5 +21,7 @@
 
 using System;
+using System.Linq;
 using System.Threading;
+using HeuristicLab.Analysis;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -124,4 +126,8 @@
 
     protected override void Run(CancellationToken cancellationToken) {
+      var qpc = ((MultiAnalyzer)Analyzer).Operators.OfType<QualityPerClockAnalyzer>().FirstOrDefault();
+      if (qpc != null) {
+        qpc.LastUpdateTimeParameter.ActualName = Context.LastUpdateTimeParameter.Name;
+      }
       token = cancellationToken;
       lastUpdate = DateTime.UtcNow.AddSeconds(-1);
@@ -205,4 +211,6 @@
         localSolver.AddCallback(LSCallbackType.IterationTicked, LocalSolverOnIterationTicked);
 
+        Context.LastUpdateTimeParameter.Value = new DateTimeValue(DateTime.UtcNow);
+
         localSolver.Solve();
 
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPIntegerSolver.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPIntegerSolver.cs	(revision 15688)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/GQAPIntegerSolver.cs	(revision 15698)
@@ -21,5 +21,7 @@
 
 using System;
+using System.Linq;
 using System.Threading;
+using HeuristicLab.Analysis;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -118,4 +120,8 @@
 
     protected override void Run(CancellationToken cancellationToken) {
+      var qpc = ((MultiAnalyzer)Analyzer).Operators.OfType<QualityPerClockAnalyzer>().FirstOrDefault();
+      if (qpc != null) {
+        qpc.LastUpdateTimeParameter.ActualName = Context.LastUpdateTimeParameter.Name;
+      }
       token = cancellationToken;
       lastUpdate = DateTime.UtcNow.AddSeconds(-1);
@@ -177,4 +183,6 @@
         localSolver.AddCallback(LSCallbackType.IterationTicked, LocalSolverOnIterationTicked);
 
+        Context.LastUpdateTimeParameter.Value = new DateTimeValue(DateTime.UtcNow);
+
         localSolver.Solve();
       } finally {
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/LocalSolverContext.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/LocalSolverContext.cs	(revision 15688)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSolverNet/LocalSolverContext.cs	(revision 15698)
@@ -22,4 +22,5 @@
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Data;
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -44,4 +45,10 @@
     }
 
+    [Storable]
+    private ValueParameter<DateTimeValue> lastUpdateTimeParameter;
+    public IValueParameter<DateTimeValue> LastUpdateTimeParameter {
+      get { return lastUpdateTimeParameter; }
+    }
+
     [StorableConstructor]
     protected LocalSolverContext(bool deserializing) : base(deserializing) { }
@@ -50,24 +57,30 @@
       problem = cloner.Clone(original.problem);
       bestSolution = cloner.Clone(original.bestSolution);
+      lastUpdateTimeParameter = cloner.Clone(original.lastUpdateTimeParameter);
     }
     public LocalSolverContext() : base() {
       Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
       Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+      Parameters.Add(lastUpdateTimeParameter = new ValueParameter<DateTimeValue>("LastUpdateTime"));
     }
     public LocalSolverContext(string name) : base(name) {
       Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
       Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+      Parameters.Add(lastUpdateTimeParameter = new ValueParameter<DateTimeValue>("LastUpdateTime"));
     }
     public LocalSolverContext(string name, ParameterCollection parameters) : base(name, parameters) {
       Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
       Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+      Parameters.Add(lastUpdateTimeParameter = new ValueParameter<DateTimeValue>("LastUpdateTime"));
     }
     public LocalSolverContext(string name, string description) : base(name, description) {
       Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
       Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+      Parameters.Add(lastUpdateTimeParameter = new ValueParameter<DateTimeValue>("LastUpdateTime"));
     }
     public LocalSolverContext(string name, string description, ParameterCollection parameters) : base(name, description, parameters) {
       Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
       Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+      Parameters.Add(lastUpdateTimeParameter = new ValueParameter<DateTimeValue>("LastUpdateTime"));
     }
     
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/RandomSearch/RandomSearch.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/RandomSearch/RandomSearch.cs	(revision 15698)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/RandomSearch/RandomSearch.cs	(revision 15698)
@@ -0,0 +1,122 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.LocalSearch {
+  [Item("Random Search (GQAP)", "Random search for the GQAP.")]
+  [Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms)]
+  [StorableClass]
+  public sealed class RandomSearch : StochasticAlgorithm<LocalSearchContext, IntegerVectorEncoding> {
+
+    public override bool SupportsPause {
+      get { return true; }
+    }
+
+    public override Type ProblemType {
+      get { return typeof(GQAP); }
+    }
+
+    public new GQAP Problem {
+      get { return (GQAP)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    [StorableConstructor]
+    private RandomSearch(bool deserializing) : base(deserializing) { }
+    private RandomSearch(RandomSearch original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public RandomSearch() {
+
+      Problem = new GQAP();
+    }
+    
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomSearch(this, cloner);
+    }
+
+    protected override void Initialize(CancellationToken token) {
+      base.Initialize(token);
+
+      Context.Problem = Problem;
+      Context.BestQuality = double.NaN;
+      Context.BestSolution = null;
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      var lastUpdate = ExecutionTime;
+
+      while (!StoppingCriterion()) {
+        var assign = new IntegerVector(Problem.ProblemInstance.Demands.Length, Context.Random, 0, Problem.ProblemInstance.Capacities.Length);
+        var eval = Problem.ProblemInstance.Evaluate(assign);
+        var candidate = new GQAPSolution(assign, eval);
+        Context.EvaluatedSolutions++;
+
+        var candidateFit = Problem.ProblemInstance.ToSingleObjective(candidate.Evaluation);
+        if (Context.Incumbent == null || candidateFit < Context.Incumbent.Fitness) {
+          Context.ReplaceIncumbent(Context.ToScope(candidate, candidateFit));
+          Context.BestQuality = candidateFit;
+          Context.BestSolution = (GQAPSolution)candidate.Clone();
+        }
+
+        IResult result;
+        if (ExecutionTime - lastUpdate > TimeSpan.FromSeconds(1)) {
+          if (Results.TryGetValue("Iterations", out result))
+            ((IntValue)result.Value).Value = Context.Iterations;
+          else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+          if (Results.TryGetValue("EvaluatedSolutions", out result))
+            ((IntValue)result.Value).Value = Context.EvaluatedSolutions;
+          else Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+          lastUpdate = ExecutionTime;
+        }
+        if (Results.TryGetValue("BestQuality", out result))
+          ((DoubleValue)result.Value).Value = Context.BestQuality;
+        else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+        if (Results.TryGetValue("BestSolution", out result))
+          result.Value = Context.BestSolution;
+        else Results.Add(new Result("BestSolution", Context.BestSolution));
+
+        try {
+          Context.RunOperator(Analyzer, cancellationToken);
+        } catch (OperationCanceledException) { }
+
+        Context.Iterations++;
+        if (cancellationToken.IsCancellationRequested) break;
+      }
+
+      IResult result2;
+      if (Results.TryGetValue("Iterations", out result2))
+        ((IntValue)result2.Value).Value = Context.Iterations;
+      else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+      if (Results.TryGetValue("EvaluatedSolutions", out result2))
+        ((IntValue)result2.Value).Value = Context.EvaluatedSolutions;
+      else Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+    }
+  }
+}
Index: branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/RandomSearch/RandomSearchContext.cs
===================================================================
--- branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/RandomSearch/RandomSearchContext.cs	(revision 15698)
+++ branches/1614_GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/RandomSearch/RandomSearchContext.cs	(revision 15698)
@@ -0,0 +1,72 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.RandomSearch {
+  [Item("Random Search Context", "Context for random search algorithms.")]
+  [StorableClass]
+  public sealed class RandomSearchContext : SingleSolutionContext<ISingleObjectiveSolutionScope<GQAPSolution>> {
+    [Storable]
+    private IValueParameter<GQAP> problem;
+    public GQAP Problem {
+      get { return problem.Value; }
+      set { problem.Value = value; }
+    }
+
+    [Storable]
+    private IValueParameter<GQAPSolution> bestSolution;
+    public GQAPSolution BestSolution {
+      get { return bestSolution.Value; }
+      set { bestSolution.Value = value; }
+    }
+    
+    [StorableConstructor]
+    private RandomSearchContext(bool deserializing) : base(deserializing) { }
+    private RandomSearchContext(RandomSearchContext original, Cloner cloner)
+    : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      bestSolution = cloner.Clone(original.bestSolution);
+    }
+    public RandomSearchContext() {
+      Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
+      Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomSearchContext(this, cloner);
+    }
+
+    public ISingleObjectiveSolutionScope<GQAPSolution> ToScope(GQAPSolution code, double fitness = double.NaN) {
+      var name = Problem.Encoding.Name;
+      var scope = new SingleObjectiveSolutionScope<GQAPSolution>(code,
+        name + "Solution", fitness, Problem.Evaluator.QualityParameter.ActualName) {
+        Parent = Scope
+      };
+      scope.Variables.Add(new Variable(name, code.Assignment));
+      scope.Variables.Add(new Variable("Evaluation", code.Evaluation));
+      return scope;
+    }
+  }
+}
