/// <summary>Adds a specific inequality constraint. /// </summary> /// <param name="inequalityConstraintFunction">The inequality constraint function, i.e. a argument x will be accepted iff c(x) < <paramref name="tolerance"/> component-wise.</param> /// <param name="constraintFunctionDimension"> The dimensionality of the constraint function.</param> /// <param name="tolerance">An array of at least <paramref name="constraintFunctionDimension"/> elements that represents the tolerance in each constraint dimension; or <c>null</c> for zero tolerances.</param> /// <returns>A value indicating whether the inequality constraint has been added.</returns> public NLoptResultCode AddInequalityConstraint(NLoptVectorInequalityConstraintFunction inequalityConstraintFunction, int constraintFunctionDimension, double[] tolerance) { if (m_NLopPtr == IntPtr.Zero) { throw new ObjectDisposedException("NLoptPtr"); } return(nlopt_add_inequality_mconstraint(m_NLopPtr, constraintFunctionDimension, inequalityConstraintFunction, IntPtr.Zero, tolerance)); }
/// <summary>Creates a new <see cref="NLoptConstraint"/> object. /// </summary> /// <param name="linearInequalityConstraint">The specific constraints in its <see cref="MultiDimRegion.LinearInequality"/> representation.</param> /// <returns>A specific <see cref="NLoptConstraint"/> object with respect to the specified optimization algorithm.</returns> /// <exception cref="InvalidOperationException">Thrown, if the optimization algorithm does not support this kind of constraints.</exception> public NLoptConstraint Create(MultiDimRegion.LinearInequality linearInequalityConstraint) { if (linearInequalityConstraint == null) { throw new ArgumentNullException(nameof(linearInequalityConstraint)); } if (nloptMultiDimOptimizer.Configuration.NonlinearConstraintRequirement.HasFlag(NLoptNonlinearConstraintRequirement.SupportsInequalityConstraints) == false) { throw new InvalidOperationException("The NLopt algorithm does not support linear inequality constraints"); } var entriesOfA = new List <double>(); var entriesOfb = new List <double>(); int r = linearInequalityConstraint.GetRegionConstraints(entriesOfA, entriesOfb); // condition A^t * x >= b should be written as c(x) = b - A^t * x var A = entriesOfA.ToArray(); // matrix A is of type d[dimension] x r, provided column-by-column var b = entriesOfb.ToArray(); NLoptVectorInequalityConstraintFunction c = (m, result, n, x, grad, data) => // todo: bug in nlopt(?) - argument x has wrong dimension { BLAS.Level2.dgemv(n, m, -1.0, A, x, 0.0, result, BLAS.MatrixTransposeState.Transpose); VectorUnit.Basics.Add(r, result, b); if (grad != null) { /* it holds \partial c_i / \partial x_j = A[j,i] which should be stored in grad[i * n + j], i = 0,...,m-1, j = 0,...,n-1 */ for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { grad[i * n + j] = A[j + i * n]; // can be improved } } } }; var tolerance = Enumerable.Repeat(MachineConsts.Epsilon, r).ToArray(); return(new NLoptConstraint(this, linearInequalityConstraint.Dimension, "Linear Inequality constraint", nloptPtr => { var code = nloptPtr.AddInequalityConstraint(c, r, tolerance); if (code != NLoptResultCode.Success) { throw new InvalidOperationException(String.Format("Constraint can not be set to NLopt algorithm {0}; error code: {1}.", nloptPtr.ToString(), code)); } }, infoOutputPackage => { } )); }
private static extern NLoptResultCode nlopt_add_inequality_mconstraint(IntPtr opt, int m, [MarshalAs(UnmanagedType.FunctionPtr)] NLoptVectorInequalityConstraintFunction constraintFunction, IntPtr data, double[] tolerance);
/// <summary>Creates a new <see cref="NLoptConstraint"/> object. /// </summary> /// <param name="polynomialConstraint">The specific constraints in its <see cref="MultiDimRegion.Polynomial"/> representation.</param> /// <returns>A specific <see cref="NLoptConstraint"/> object with respect to the specified optimization algorithm.</returns> /// <exception cref="InvalidOperationException">Thrown, if the optimization algorithm does not support this kind of constraints.</exception> public NLoptConstraint Create(MultiDimRegion.Polynomial polynomialConstraint) { if (polynomialConstraint == null) { throw new ArgumentNullException(nameof(polynomialConstraint)); } if (nloptMultiDimOptimizer.Configuration.NonlinearConstraintRequirement.HasFlag(NLoptNonlinearConstraintRequirement.SupportsInequalityConstraints) == false) { throw new InvalidOperationException("The NLopt algorithm does not support linear inequality for polynomial constraints"); } /* we split the constraint to at most two NLopt constraints c_1(x) <= \epsilon and c_2(x) <= \epsilon, where * c_1(x) = P(x) - upper bound, * c_2(x) = lower bound - P(x), * where P(x) is the polynomial representation of the constraint. * * We use the NLopt vector constraint representation to combine both constraint, because the evaluation is almost identically. */ if ((Double.IsNegativeInfinity(polynomialConstraint.LowerBound) == false) && (Double.IsPositiveInfinity(polynomialConstraint.UpperBound) == false)) { NLoptVectorInequalityConstraintFunction c = (m, result, n, x, grad, data) => { double polynomialValue = 0.0; foreach (var term in polynomialConstraint.Terms) { double temp = 0.0; foreach (var monomial in term.Item2) { temp += DoMath.Pow(x[monomial.ArgumentIndex], monomial.Power); } polynomialValue += term.Item1 * temp; } if (grad != null) { for (int j = 0; j < n; j++) { grad[j] = 0.0; } foreach (var term in polynomialConstraint.Terms) { foreach (var monomial in term.Item2) { grad[monomial.ArgumentIndex] -= term.Item1 * monomial.Power * DoMath.Pow(x[monomial.ArgumentIndex], monomial.Power - 1); } } } result[0] = polynomialValue - polynomialConstraint.UpperBound; result[1] = polynomialConstraint.LowerBound - polynomialValue; }; var tolerance = new[] { MachineConsts.Epsilon, MachineConsts.Epsilon }; return(new NLoptConstraint(this, polynomialConstraint.Dimension, "Polynomial constraint", nloptPtr => { var code = nloptPtr.AddInequalityConstraint(c, 2, tolerance); if (code != NLoptResultCode.Success) { throw new InvalidOperationException(String.Format("Constraint can not be set to NLopt algorithm {0}; error code: {1}.", nloptPtr.ToString(), code)); } } )); } else if (Double.IsNegativeInfinity(polynomialConstraint.LowerBound) == false) { return(CreateSingle(polynomialConstraint, polynomialConstraint.LowerBound, sign: 1)); } else { return(CreateSingle(polynomialConstraint, polynomialConstraint.UpperBound, sign: -1)); } }