mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-03 21:09:11 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			236 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
 | 
						||
/*++
 | 
						||
Copyright (c) 2015 Microsoft Corporation
 | 
						||
 | 
						||
--*/
 | 
						||
 | 
						||
using System;
 | 
						||
using System.Collections.Generic;
 | 
						||
using System.Diagnostics;
 | 
						||
using System.Linq;
 | 
						||
using System.IO;
 | 
						||
 | 
						||
using Microsoft.Z3;
 | 
						||
using Microsoft.SolverFoundation.Common;
 | 
						||
using Microsoft.SolverFoundation.Services;
 | 
						||
using Microsoft.SolverFoundation.Plugin;
 | 
						||
 | 
						||
namespace Microsoft.SolverFoundation.Plugin.Z3
 | 
						||
{
 | 
						||
    /// <summary>
 | 
						||
    /// The class is implementation of the MSF mixed linear programming solver 
 | 
						||
    /// using the Microsoft Z3 solver as the backend.
 | 
						||
    /// </summary>
 | 
						||
    public class Z3MILPSolver : LinearModel, ILinearSolver, ILinearSolution, IReportProvider
 | 
						||
    {
 | 
						||
        #region Private members
 | 
						||
 | 
						||
        private LinearResult _result;       
 | 
						||
        private LinearSolutionQuality _solutionQuality;
 | 
						||
        private Z3BaseSolver _solver;
 | 
						||
 | 
						||
        #endregion Private members
 | 
						||
 | 
						||
        #region Solver construction and destruction
 | 
						||
 | 
						||
        /// <summary>Constructor that initializes the base classes</summary>
 | 
						||
        public Z3MILPSolver() : base(null) 
 | 
						||
        {
 | 
						||
            _result = LinearResult.Feasible;
 | 
						||
            _solver = new Z3BaseSolver(this);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>Constructor that initializes the base classes</summary>
 | 
						||
        public Z3MILPSolver(ISolverEnvironment context) : this() { }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Shutdown can be called when when the solver is not active, i.e. 
 | 
						||
        /// when it is done with Solve() or it has gracefully returns from Solve()
 | 
						||
        /// after an abort.
 | 
						||
        /// </summary>
 | 
						||
        public void Shutdown() { _solver.DestructSolver(true); }
 | 
						||
 | 
						||
        #endregion Solver construction and destruction
 | 
						||
 | 
						||
        #region Obtaining information about the solution
 | 
						||
 | 
						||
        public ILinearSolverReport GetReport(LinearSolverReportType reportType)
 | 
						||
        {
 | 
						||
            // We don't support sensitivity report
 | 
						||
            return null;
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion Obtaining information about the solution
 | 
						||
 | 
						||
        #region Construction of the problem
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Get corresponding Z3 formula of a MSF row.
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="rid">The MSF row id</param>
 | 
						||
        private ArithExpr MkGoalRow(int rid)
 | 
						||
        {
 | 
						||
            // Start with the 0 term
 | 
						||
            List<ArithExpr> row = new List<ArithExpr>();
 | 
						||
 | 
						||
            // Now, add all the entries of this row
 | 
						||
            foreach (LinearEntry entry in GetRowEntries(rid))
 | 
						||
            {
 | 
						||
                // Get the variable and constant in the row
 | 
						||
                ArithExpr e = _solver.GetVariable(entry.Index);                
 | 
						||
                if (!entry.Value.IsOne)
 | 
						||
                {
 | 
						||
                    e = _solver.Context.MkMul(_solver.GetNumeral(entry.Value, e.Sort), e);
 | 
						||
                }
 | 
						||
                row.Add(e);
 | 
						||
            }
 | 
						||
            switch (row.Count)
 | 
						||
            {
 | 
						||
                case 0: return _solver.GetNumeral(new Rational());
 | 
						||
                case 1: return row[0];
 | 
						||
                default: return _solver.Context.MkAdd(row.ToArray());
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Adds a MSF row to the Z3 assertions.
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="rid">The MSF row id</param>
 | 
						||
        private void AddRow(int rid)
 | 
						||
        {
 | 
						||
            // Start with the 0 term
 | 
						||
            ArithExpr row = MkGoalRow(rid);
 | 
						||
            _solver.AssertArith(rid, row);
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// Set results based on internal solver status
 | 
						||
        /// </summary>
 | 
						||
        private void SetResult(Z3Result status)
 | 
						||
        {
 | 
						||
            switch (status)
 | 
						||
            {
 | 
						||
                case Z3Result.Optimal:
 | 
						||
                    _result = LinearResult.Optimal;
 | 
						||
                    _solutionQuality = LinearSolutionQuality.Exact;
 | 
						||
                    break;
 | 
						||
                case Z3Result.LocalOptimal:
 | 
						||
                    _result = LinearResult.Feasible;
 | 
						||
                    _solutionQuality = LinearSolutionQuality.Approximate;
 | 
						||
                    break;
 | 
						||
                case Z3Result.Feasible:
 | 
						||
                    _result = LinearResult.Feasible;
 | 
						||
                    _solutionQuality = LinearSolutionQuality.Exact;
 | 
						||
                    break;
 | 
						||
                case Z3Result.Infeasible:
 | 
						||
                    _result = LinearResult.InfeasiblePrimal;
 | 
						||
                    _solutionQuality = LinearSolutionQuality.None;
 | 
						||
                    break;
 | 
						||
                case Z3Result.Interrupted:
 | 
						||
                    _result = LinearResult.Interrupted;
 | 
						||
                    _solutionQuality = LinearSolutionQuality.None;
 | 
						||
                    break;
 | 
						||
                default:
 | 
						||
                    Debug.Assert(false, "Unrecognized Z3 Result");
 | 
						||
                    break;
 | 
						||
            } 
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion Construction of the problem
 | 
						||
 | 
						||
        #region Solving the problem            
 | 
						||
        
 | 
						||
        /// <summary>
 | 
						||
        /// Starts solving the problem using the Z3 solver.
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="parameters">Parameters to the solver</param>
 | 
						||
        /// <returns>The solution to the problem</returns>
 | 
						||
        public ILinearSolution Solve(ISolverParameters parameters)
 | 
						||
        {
 | 
						||
            // Get the Z3 parameters
 | 
						||
            var z3Params = parameters as Z3BaseParams;
 | 
						||
            Debug.Assert(z3Params != null, "Parameters should be an instance of Z3BaseParams.");
 | 
						||
            
 | 
						||
            _solver.Solve(z3Params, Goals, AddRow, MkGoalRow, SetResult);
 | 
						||
 | 
						||
            return this;
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion Solving the problem
 | 
						||
 | 
						||
        #region ILinearSolution Members
 | 
						||
 | 
						||
        public Rational GetSolutionValue(int goalIndex)
 | 
						||
        {
 | 
						||
            var goal = Goals.ElementAt(goalIndex);
 | 
						||
            Debug.Assert(goal != null, "Goal should be an element of the goal list.");
 | 
						||
            return GetValue(goal.Index);
 | 
						||
        }
 | 
						||
 | 
						||
        public void GetSolvedGoal(int goalIndex, out object key, out int vid, out bool minimize, out bool optimal)
 | 
						||
        {
 | 
						||
            var goal = Goals.ElementAt(goalIndex);
 | 
						||
            Debug.Assert(goal != null, "Goal should be an element of the goal list.");
 | 
						||
            key = goal.Key;
 | 
						||
            vid = goal.Index;
 | 
						||
            minimize = goal.Minimize;
 | 
						||
            optimal = _result == LinearResult.Optimal;
 | 
						||
        }
 | 
						||
 | 
						||
        // LpResult is LP relaxation assignment.
 | 
						||
        
 | 
						||
        public LinearResult LpResult
 | 
						||
        {
 | 
						||
            get { return _result; }
 | 
						||
        }
 | 
						||
 | 
						||
        public Rational MipBestBound
 | 
						||
        {
 | 
						||
            get
 | 
						||
            {
 | 
						||
                Debug.Assert(GoalCount > 0, "MipBestBound is only applicable for optimization instances.");
 | 
						||
                return GetSolutionValue(0);
 | 
						||
            }
 | 
						||
        }
 | 
						||
 | 
						||
        public LinearResult MipResult
 | 
						||
        {
 | 
						||
            get { return _result; }
 | 
						||
        }
 | 
						||
 | 
						||
        public LinearResult Result
 | 
						||
        {
 | 
						||
            get { return _result; }
 | 
						||
        }
 | 
						||
 | 
						||
        public LinearSolutionQuality SolutionQuality
 | 
						||
        {
 | 
						||
            get { return _solutionQuality; }
 | 
						||
        }
 | 
						||
 | 
						||
        public int SolvedGoalCount
 | 
						||
        {
 | 
						||
            get { return GoalCount; }
 | 
						||
        }
 | 
						||
 | 
						||
        #endregion
 | 
						||
 | 
						||
        public Report GetReport(SolverContext context, Solution solution, SolutionMapping solutionMapping)
 | 
						||
        {
 | 
						||
            LinearSolutionMapping lpSolutionMapping = solutionMapping as LinearSolutionMapping;
 | 
						||
            if (lpSolutionMapping == null && solutionMapping != null)
 | 
						||
                throw new ArgumentException("solutionMapping is not a LinearSolutionMapping", "solutionMapping");
 | 
						||
            return new Z3LinearSolverReport(context, this, solution, lpSolutionMapping);
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /// <summary>
 | 
						||
    /// Class implementing the LinearReport.
 | 
						||
    /// </summary>
 | 
						||
    public class Z3LinearSolverReport : LinearReport
 | 
						||
    {
 | 
						||
        public Z3LinearSolverReport(SolverContext context, ISolver solver, Solution solution, LinearSolutionMapping solutionMapping)
 | 
						||
          : base(context, solver, solution, solutionMapping) {
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 |