/// <summary>
        ///     Creates a cancellable task that runs Gurobi on the given instance.
        /// </summary>
        /// <param name="instance">Instance to run on.</param>
        /// <param name="cancellationToken">
        ///     Token that is regurlarly checked for cancellation.
        ///     If cancellation is detected, the task will be stopped.
        /// </param>
        /// <returns>
        ///     A task that returns the run's runtime, gap, feasibility and completion status onto return.
        /// </returns>
        public Task <GurobiResult> Run(InstanceSeedFile instance, CancellationToken cancellationToken)
        {
            // Check if the runner has already been disposed.
            if (this._hasAlreadyBeenDisposed)
            {
                throw new ObjectDisposedException("GurobiRunner", "Called Run on a disposed GurobiRunner.");
            }

            // Continue if it hasn't.
            var solveTask = Task.Run(
                () =>
            {
                // Prepare Gurobi model: Use configured _environment and the given instance,
                // then add a callback for cancellation.
                var instanceFile = new FileInfo(instance.Path);
                if (!File.Exists(instanceFile.FullName))
                {
                    throw new Exception(string.Format("Instance {0} not found!", instance.Path));
                }

                LoggingHelper.WriteLine(VerbosityLevel.Debug, $"Setting MIPGap to {this._runnerConfiguration.TerminationMipGap}");
                this._environment.MIPGap = this._runnerConfiguration.TerminationMipGap;
                LoggingHelper.WriteLine(VerbosityLevel.Debug, $"Current Seed: {instance.Seed}");
                this._environment.Seed      = instance.Seed;
                this._environment.TimeLimit = this._runnerConfiguration.CpuTimeout.TotalSeconds;

                var fileName = Path.GetFileNameWithoutExtension(instance.Path);
                if (!Directory.Exists("GurobiLog"))
                {
                    Directory.CreateDirectory("GurobiLog");
                }

                this._environment.LogFile = $"GurobiLog/GurobiRunner_{DateTime.Now:yy-MM-dd_HH-mm-ss-ffff}_" + fileName + ".log";

                var model = new GRBModel(this._environment, instance.Path)
                {
                    ModelName = instanceFile.Name
                };
                var mstfileName = instance.Path.Substring(0, instance.Path.Length - instanceFile.Extension.Length) + ".mst";
                if (File.Exists(mstfileName))
                {
                    model.Read(mstfileName);
                }

                model.SetCallback(new GurobiCallback(cancellationToken));

                // Optimize. This step may be aborted in the callback.
                model.Optimize();
                var result = this.CreateGurobiResult(model);
                // Before returning, dispose of Gurobi model.
                model.Dispose();
                return(result);
            },
                cancellationToken);

            return(solveTask);
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a task that runs Gurobi on the given instance.
        /// </summary>
        /// <param name="instance">
        /// Instance to run on.
        /// </param>
        /// <param name="cancellationToken">
        /// The cancellation token given to the task. NOTE: In this implementation, we ignore this cancellation token, since Gurobi uses its own cancellation token in the callback.
        /// </param>
        /// <returns>
        /// A task that returns the run's runtime, gap, feasibility and completion status onto return.
        /// </returns>
        public Task <GurobiResult> Run(InstanceSeedFile instance, CancellationToken cancellationToken)
        {
            // Check if the runner has already been disposed.
            if (this._hasAlreadyBeenDisposed)
            {
                throw new ObjectDisposedException("GurobiRunner", "Called Run on a disposed GurobiRunner.");
            }

            // Continue if it hasn't.
            // ReSharper disable once MethodSupportsCancellation
            var solveTask = Task.Run(
                () =>
            {
                this._recordTimer = null;
                try
                {
                    // Prepare Gurobi model: Use configured _environment and the given instance,
                    // then add a cancellation token source and the Gurobi callback for cancellation.
                    var instanceFile = new FileInfo(instance.Path);
                    if (!File.Exists(instanceFile.FullName))
                    {
                        throw new FileNotFoundException($"Instance {instanceFile.FullName} not found!");
                    }

                    LoggingHelper.WriteLine(VerbosityLevel.Debug, $"Setting MIPGap to {this._runnerConfiguration.TerminationMipGap}");
                    this._environment.MIPGap = this._runnerConfiguration.TerminationMipGap;
                    LoggingHelper.WriteLine(VerbosityLevel.Debug, $"Current Seed: {instance.Seed}");
                    this._environment.Seed      = instance.Seed;
                    this._environment.TimeLimit = this._runnerConfiguration.CpuTimeout.TotalSeconds;

                    if (!Directory.Exists("GurobiLog"))
                    {
                        Directory.CreateDirectory("GurobiLog");
                    }

                    var instanceFileNameWithoutExtension = GurobiUtils.GetFileNameWithoutGurobiExtension(instanceFile);

                    this._environment.LogFile = "GurobiLog" + Path.DirectorySeparatorChar
                                                + $"GurobiRunner_{DateTime.Now:yy-MM-dd_HH-mm-ss-ffff}_"
                                                + instanceFileNameWithoutExtension + $"_{Guid.NewGuid()}.log";

                    var model = new GRBModel(this._environment, instanceFile.FullName)
                    {
                        ModelName = instanceFileNameWithoutExtension
                    };

                    if (GurobiRunner.TryToGetMstFile(instanceFile.DirectoryName, instanceFileNameWithoutExtension, out var mstFileFullName))
                    {
                        model.Read(mstFileFullName);
                    }

                    this._startTimeStamp        = DateTime.Now;
                    this._targetAlgorithmStatus = TargetAlgorithmStatus.Running;

                    this._innerCancellationTokenSource = new CancellationTokenSource(this._runnerConfiguration.CpuTimeout);

                    this._grbCallback = new GurobiCallback(
                        this._innerCancellationTokenSource.Token,
                        this._tunerConfiguration.EnableDataRecording,
                        this._startTimeStamp);
                    model.SetCallback(this._grbCallback);

                    if (this._tunerConfiguration.EnableDataRecording)
                    {
                        this._lastRuntimeFeatures = null;
                        this.SetGurobiInstanceFeatures(model);

                        // Start record timer.
                        var autoResetEvent = new AutoResetEvent(false);
                        this._recordTimer  = new Timer(
                            (timerCallback) =>
                        {
                            var currentTimeStamp = DateTime.Now;
                            if (currentTimeStamp - this._startTimeStamp < this._runnerConfiguration.CpuTimeout)
                            {
                                // Write current line to data log.
                                var currentAdapterData = this.CreateCurrentAdapterDataRecord(currentTimeStamp);
                                this.OnNewDataRecord?.Invoke(this, currentAdapterData);
                            }
                        },
                            autoResetEvent,
                            TimeSpan.FromSeconds(0),
                            this._tunerConfiguration.DataRecordUpdateInterval);
                    }

                    // Optimize. This step may be aborted in the callback.
                    model.Optimize();

                    if (this._targetAlgorithmStatus != TargetAlgorithmStatus.CancelledByGrayBox)
                    {
                        this._recordTimer?.Dispose();
                        this._targetAlgorithmStatus = this.GetIsRunInterrupted(model)
                                                                  ? TargetAlgorithmStatus.CancelledByTimeout
                                                                  : TargetAlgorithmStatus.Finished;
                    }

                    var finalTimeStamp = DateTime.Now;
                    var result         = this.CreateGurobiResult(finalTimeStamp, model);

                    if (this._tunerConfiguration.EnableDataRecording)
                    {
                        // Write last line to data log.
                        var lastAdapterData = this.CreateFinalAdapterDataRecord(finalTimeStamp, model, result);
                        this.OnNewDataRecord?.Invoke(this, lastAdapterData);
                    }

                    // Before returning, dispose of Gurobi model.
                    model.Dispose();

                    return(result);
                }
                finally
                {
                    this._recordTimer?.Dispose();
                }
            });

            return(solveTask);
        }