diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e0b8986..e0b44c9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,78 +1,76 @@ -# This workflow creates the deployement on github. +# This workflow manages the deployement of BRIDGES: +# - NuGet Package for relevant branches (see "deploy-package" environment) +# - Pre-Release and Release for release and master branches, respectively name: Deploy -# Controls the event triggering the workflow -on: - # Gives the possibility to trigger the workflow manually. - workflow_dispatch: - inputs: - version: - description: 'Package Version: v[Major].[Minor].[Patch]' - required: true - type: string - -env: - # Path of the Project being Tested and Packaged. - PROJECT_PATH: 'BRIDGES/BRIDGES.csproj' - # Output directory for the NuGet Package - PKG_OUTPUT_DIR: ${{ github.workspace }}/output - # URL of the GitHub Package Repository - NUGET_SRC_URL: https://nuget.pkg.github.com/bridges-libraries/index.json +on: # Controls the event triggering the workflow + workflow_dispatch: # The workflow can be triggered manually. + +env: # Environment variable shared among the jobs + PKG_OUTPUT_DIR: ${{ github.workspace }}/output # Output directory for the NuGet Package - # Token automatically generated by GitHub for the workflow - GITHUB_TOKEN: ${{ github.token }} - jobs: - # Verify the inputs & Set up the workflow - verify_inputs: - - runs-on : ubuntu-latest - - # Map a step output to a job output + manage_version: + runs-on: ubuntu-latest # Specify the runner os + environment: versioning # Specify the protection rules, variables and secrets outputs: - version_number : ${{ steps.verify-version.outputs.PKG_VERSION_NUMBER }} - + pkg_version: ${{ steps.create-version.outputs.PKG_VERSION }} + pkg_release_type: ${{ steps.create-version.outputs.PKG_RELEASE_TYPE }} steps: - - name: Verify branch + # Get the repository variable and Increment the version + - name: Select and Increment version + id: create-version shell: bash run: | - if [[ ${{github.ref}} =~ .*master$ ]] - then - echo "The reference branch is 'master'" - elif [[ ${{github.ref}} =~ ^.*/release/.*$ ]] - then - echo "The reference branch is 'release'" - elif [[ ${{github.ref}} =~ .*develop$ ]] - then - echo "The reference branch is 'develop'" - else - exit 1 - fi - - name: Verify version & Get version number - id: verify-version - shell: bash - run : | - version=${{inputs.version}} - if [[ ${version} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] - then - echo "PKG_VERSION_NUMBER=${version:1}" >> $GITHUB_OUTPUT - else - echo "The package version must start with 'v'." - exit 1 + version=${{vars.VERSION}} # Get the current package version + numbers=( ${version//./ } ) # Split into array to get version numbers + if [[ ${{github.ref}} =~ .*master$ ]]; then # For master branch + ((numbers[0]++)) # Increment the major version number + version="${numbers[0]}.0.0" + echo "PKG_VERSION=$version" >> $GITHUB_OUTPUT + echo "PKG_RELEASE_TYPE=" >> $GITHUB_OUTPUT + elif [[ ${{github.ref}} =~ ^.*/release/.*$ ]]; then # For release branches + ((numbers[1]++)) # Increment the minor version number + version="${numbers[0]}.${numbers[1]}.0" + echo "PKG_VERSION=$version" >> $GITHUB_OUTPUT + echo "PKG_RELEASE_TYPE=" >> $GITHUB_OUTPUT + elif [[ ${{github.ref}} =~ .*develop$ ]]; then # For release branch + ((numbers[2]++)) # Increment the patch version number + version="${numbers[0]}.${numbers[1]}.${numbers[2]}" + echo "PKG_VERSION=$version" >> $GITHUB_OUTPUT + echo "PKG_RELEASE_TYPE=-alpha" >> $GITHUB_OUTPUT + else # For feature branches + ((numbers[2]++)) # Increment the patch version number + version="${numbers[0]}.${numbers[1]}.${numbers[2]}" + echo "PKG_VERSION=$version" >> $GITHUB_OUTPUT + echo "PKG_RELEASE_TYPE=-beta" >> $GITHUB_OUTPUT fi - - # Build the NuGet package & Publish it on GitHub Packages - deploy_package: - needs : verify_inputs - - runs-on : ubuntu-latest - + # Generate a temporary token for the Github App + - name: Generate a GitHub App token + id: generate-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.VARIABLES_GITHUB_APP_ID }} + private-key: ${{ secrets.VARIABLES_GITHUB_APP_PRIVATE_KEY }} + # Update the repository variable + - name: Update version variable + env: + VAR_NAME: 'VERSION' + VAR_VALUE: ${{ steps.create-version.outputs.PKG_VERSION }} + GH_TOKEN: ${{ steps.generate-token.outputs.token }} + run: | + gh api --method PATCH -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${{github.repository}}/actions/variables/${{env.VAR_NAME}} -f name='${{env.VAR_NAME}}' -f value='${{env.VAR_VALUE}}' + + nuget_packaging: + needs : manage_version # Specify jobs needed to run this one + runs-on : ubuntu-latest # Specify the runner os steps: # Check-out the branch - name: Check-out Branch uses: actions/checkout@v3 # Setup the .Net environment - - name: Check-out Branch + - name: Setup .Net environmnent uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x @@ -84,39 +82,44 @@ jobs: run: dotnet test --verbosity normal # Pack the project in a NuGet package - name: Create NuGet + env: + PACKAGE_ID: 'BRIDGES' run: | - if [[ ${{github.ref}} =~ .*master$ ]] - then - dotnet pack ${{env.PROJECT_PATH}} -p:PackageId='BRIDGES' -p:PackageVersion=${{needs.verify_inputs.outputs.version_number}} -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --output ${{ env.PKG_OUTPUT_DIR }} - elif [[ ${{github.ref}} =~ ^.*/release/.*$ ]] - then - dotnet pack ${{env.PROJECT_PATH}} -p:PackageId='BRIDGES' -p:PackageVersion=${{needs.verify_inputs.outputs.version_number}}-beta -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --output ${{ env.PKG_OUTPUT_DIR }} - elif [[ ${{github.ref}} =~ .*develop$ ]] - then - dotnet pack ${{env.PROJECT_PATH}} -p:PackageId='BRIDGES-Dev' -p:PackageVersion=${{needs.verify_inputs.outputs.version_number}}-beta -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg --output ${{ env.PKG_OUTPUT_DIR }} - else - echo "::error file=deploy.yml,line=94,col=9,endColumn=13::Wrong branch for deployement" - exit 1 - fi - - # Publish the NuGet package on GitHub - - name: Publish NuGet Package - run: | - dotnet nuget push ${{ env.PKG_OUTPUT_DIR }}/*.nupkg --api-key ${{ env.GITHUB_TOKEN }} --source ${{ env.NUGET_SRC_URL }} - dotnet nuget push ${{ env.PKG_OUTPUT_DIR }}/*.snupkg --api-key ${{ env.GITHUB_TOKEN }} --source ${{ env.NUGET_SRC_URL }} + dotnet pack ${{vars.PROJECT_PATH}} -p:PackageId=${{ env.PACKAGE_ID }} \ + -p:PackageVersion=${{ needs.manage_version.outputs.PKG_VERSION }}${{ needs.manage_version.outputs.PKG_RELEASE_TYPE }} \ + -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg \ + --output ${{ env.PKG_OUTPUT_DIR }} # Upload the artefacts (Package and Symbols) - name: Upload Github Artifacts uses: actions/upload-artifact@v3 with: name: package path: ${{ env.PKG_OUTPUT_DIR }}/* - - # Tag the commit with the package version - tag_commit: - needs : deploy_package - - runs-on : ubuntu-latest - + + publish_nuget: + needs : nuget_packaging # Specify jobs needed to run this one + runs-on : ubuntu-latest # Specify the runner os + steps: + # Setup the .Net environment + - name: Setup .Net environmnent + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + # Download the artefacts (Package and Symbols) + - name: Download Github Artifacts + uses: actions/download-artifact@v3 + with: + name: package + path: ${{ env.PKG_OUTPUT_DIR }}/ + # Publish the NuGet package on GitHub + - name: Publish NuGet Package + run: | + dotnet nuget push ${{ env.PKG_OUTPUT_DIR }}/*.nupkg --api-key ${{ github.token }} --source ${{ vars.NUGET_SRC_URL }} + dotnet nuget push ${{ env.PKG_OUTPUT_DIR }}/*.snupkg --api-key ${{ github.token }} --source ${{ vars.NUGET_SRC_URL }} + + create_tag: + needs: [manage_version, nuget_packaging] # Specify jobs needed to run this one + runs-on : ubuntu-latest # Specify the runner os steps: # Create a tag on the latest commit of the branch - name: Create tag @@ -126,16 +129,15 @@ jobs: github.rest.git.createRef({ owner: context.repo.owner, repo: context.repo.repo, - ref: 'refs/tags/${{inputs.version}}', + ref: 'refs/tags/v${{ needs.manage_version.outputs.PKG_VERSION }}${{ needs.manage_version.outputs.PKG_RELEASE_TYPE }}', sha: context.sha }) - - # Create a (Pre-)Release on Github - release_package: - needs : tag_commit - if : ${{ endsWith( github.ref , 'master') || contains( github.ref , '/release/') }} - + + create_release: + needs : [manage_version, create_tag] runs-on : ubuntu-latest + + if : ${{ endsWith( github.ref , 'master') || contains( github.ref , '/release/') }} steps: # Download the artefacts (Package and Symbols) @@ -148,21 +150,15 @@ jobs: - name: Evaluate if Pre-Release shell: bash run : | - if [[ ${{github.ref}} =~ .*master$ ]] - then + if [[ ${{github.ref}} =~ .*master$ ]]; then echo "IS_PRERELEASE=false" >> $GITHUB_ENV - elif [[ ${{github.ref}} =~ ^.*/release/.*$ ]] - then - echo "IS_PRERELEASE=true" >> $GITHUB_ENV else - echo "The package should not be released." - exit 1 + echo "IS_PRERELEASE=true" >> $GITHUB_ENV fi # Publish the Release - name: Publish Release uses: ncipollo/release-action@v1 with : - prerelease : ${{env.IS_PRERELEASE}} + prerelease : ${{ env.IS_PRERELEASE }} artifacts: ${{ env.PKG_OUTPUT_DIR }}/* - tag : ${{inputs.version}} - + tag : ${{ needs.manage_version.outputs.PKG_VERSION }}${{ needs.manage_version.outputs.PKG_RELEASE_TYPE }} \ No newline at end of file diff --git a/BRIDGES/Serialisation/Deserialise.DataStructures.cs b/BRIDGES/Serialisation/Deserialise.DataStructures.cs index 3a76b6a..5ec52b5 100644 --- a/BRIDGES/Serialisation/Deserialise.DataStructures.cs +++ b/BRIDGES/Serialisation/Deserialise.DataStructures.cs @@ -21,18 +21,18 @@ public static partial class Deserialise /// The deserialised from the string representation. /// The specified file format for the halfedge mesh deserialisation is not implemented. [Deserialiser(typeof(Meshes.HalfedgeMesh.Mesh<>))] - public static Meshes.HalfedgeMesh.Mesh HalfedgeMesh(string text, PolyhedralMeshSerialisationFormat format) + public static Meshes.HalfedgeMesh.Mesh HalfedgeMesh(string text, Formats.PolyhedralMeshSerialisationFormat format) where TPosition : IEquatable, Algebra.Fundamentals.IAddable /* To Do : Remove */, Algebra.Sets.IGroupAction { switch (format) { - case PolyhedralMeshSerialisationFormat.Json: + case Formats.PolyhedralMeshSerialisationFormat.Json: return HalfedgeMeshFromJson(text); - case PolyhedralMeshSerialisationFormat.Xml: + case Formats.PolyhedralMeshSerialisationFormat.Xml: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Obj: + case Formats.PolyhedralMeshSerialisationFormat.Obj: throw new NotImplementedException(); default: throw new NotImplementedException("The specified file format for the halfedge mesh deserialisation is not implemented."); @@ -47,18 +47,18 @@ public static Meshes.HalfedgeMesh.Mesh HalfedgeMesh(string /// Format of the serialisation. /// The deserialised from the string representation. [Deserialiser(typeof(Meshes.FaceVertexMesh.Mesh<>))] - public static Meshes.FaceVertexMesh.Mesh FaceVertexMesh(string text, PolyhedralMeshSerialisationFormat format) + public static Meshes.FaceVertexMesh.Mesh FaceVertexMesh(string text, Formats.PolyhedralMeshSerialisationFormat format) where TPosition : IEquatable, Algebra.Fundamentals.IAddable /* To Do : Remove */, Algebra.Sets.IGroupAction { switch (format) { - case PolyhedralMeshSerialisationFormat.Json: + case Formats.PolyhedralMeshSerialisationFormat.Json: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Xml: + case Formats.PolyhedralMeshSerialisationFormat.Xml: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Obj: + case Formats.PolyhedralMeshSerialisationFormat.Obj: throw new NotImplementedException(); default: throw new NotImplementedException("The specified file format for the face|vertex mesh deserialisation is not implemented."); diff --git a/BRIDGES/Serialisation/Formats/PolyhedralMeshFormat.cs b/BRIDGES/Serialisation/Formats/PolyhedralMeshFormat.cs index a82f223..f21b0d8 100644 --- a/BRIDGES/Serialisation/Formats/PolyhedralMeshFormat.cs +++ b/BRIDGES/Serialisation/Formats/PolyhedralMeshFormat.cs @@ -1,9 +1,7 @@ -using BRIDGES.Serialisation.Formats; -using System; -using System.Collections.Generic; -using System.Text; +using System; -namespace BRIDGES.Serialisation + +namespace BRIDGES.Serialisation.Formats { /// /// Specifies the file formats available for the meshes. diff --git a/BRIDGES/Serialisation/Serialise.DataStructures.cs b/BRIDGES/Serialisation/Serialise.DataStructures.cs index db68ca6..a04f6f1 100644 --- a/BRIDGES/Serialisation/Serialise.DataStructures.cs +++ b/BRIDGES/Serialisation/Serialise.DataStructures.cs @@ -21,18 +21,18 @@ public static partial class Serialise /// Format of the serialisation. /// A string representation of the . [Serialiser(typeof(Meshes.HalfedgeMesh.Mesh<>))] - public static string HalfedgeMesh(Meshes.HalfedgeMesh.Mesh mesh, PolyhedralMeshSerialisationFormat format) + public static string HalfedgeMesh(Meshes.HalfedgeMesh.Mesh mesh, Formats.PolyhedralMeshSerialisationFormat format) where TPosition : IEquatable, Algebra.Fundamentals.IAddable /* To Do : Remove */, Algebra.Sets.IGroupAction { switch (format) { - case PolyhedralMeshSerialisationFormat.Json: + case Formats.PolyhedralMeshSerialisationFormat.Json: return HalfedgeMeshToJson(mesh); - case PolyhedralMeshSerialisationFormat.Xml: + case Formats.PolyhedralMeshSerialisationFormat.Xml: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Obj: + case Formats.PolyhedralMeshSerialisationFormat.Obj: return PolyhedralMeshToObj(mesh); default: throw new NotImplementedException("The specified file format for the halfedge mesh serialisation is not implemented."); @@ -47,18 +47,18 @@ public static string HalfedgeMesh(Meshes.HalfedgeMesh.Mesh /// Format of the serialisation. /// A string representation of the . [Serialiser(typeof(Meshes.FaceVertexMesh.Mesh<>))] - public static string FaceVertexMesh(Meshes.FaceVertexMesh.Mesh mesh, PolyhedralMeshSerialisationFormat format) + public static string FaceVertexMesh(Meshes.FaceVertexMesh.Mesh mesh, Formats.PolyhedralMeshSerialisationFormat format) where TPosition : IEquatable, Algebra.Fundamentals.IAddable /* To Do : Remove */, Algebra.Sets.IGroupAction { switch (format) { - case PolyhedralMeshSerialisationFormat.Json: + case Formats.PolyhedralMeshSerialisationFormat.Json: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Xml: + case Formats.PolyhedralMeshSerialisationFormat.Xml: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Obj: + case Formats.PolyhedralMeshSerialisationFormat.Obj: return PolyhedralMeshToObj(mesh); default: throw new NotImplementedException("The specified file format for the face|vertex mesh serialisation is not implemented."); @@ -73,18 +73,18 @@ public static string FaceVertexMesh(Meshes.FaceVertexMesh.Mesh to serialise. /// Format of the serialisation. /// A string representation of the . - public static string PolyhedralMesh(Meshes.IMesh mesh, PolyhedralMeshSerialisationFormat format) + public static string PolyhedralMesh(Meshes.IMesh mesh, Formats.PolyhedralMeshSerialisationFormat format) where TPosition : IEquatable, Algebra.Fundamentals.IAddable /* To Do : Remove */, Algebra.Sets.IGroupAction { switch (format) { - case PolyhedralMeshSerialisationFormat.Json: + case Formats.PolyhedralMeshSerialisationFormat.Json: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Xml: + case Formats.PolyhedralMeshSerialisationFormat.Xml: throw new NotImplementedException(); - case PolyhedralMeshSerialisationFormat.Obj: + case Formats.PolyhedralMeshSerialisationFormat.Obj: return PolyhedralMeshToObj(mesh); default: throw new NotImplementedException("The specified file format for the polyhedral mesh serialisation is not implemented."); diff --git a/BRIDGES/Solvers/GuidedProjection/Interfaces/IQuadraticConstraintType.cs b/BRIDGES/Solvers/GuidedProjection/Abstracts/ConstraintType.cs similarity index 61% rename from BRIDGES/Solvers/GuidedProjection/Interfaces/IQuadraticConstraintType.cs rename to BRIDGES/Solvers/GuidedProjection/Abstracts/ConstraintType.cs index 237c7c7..ab7f8ae 100644 --- a/BRIDGES/Solvers/GuidedProjection/Interfaces/IQuadraticConstraintType.cs +++ b/BRIDGES/Solvers/GuidedProjection/Abstracts/ConstraintType.cs @@ -4,29 +4,29 @@ using BRIDGES.LinearAlgebra.Matrices; -namespace BRIDGES.Solvers.GuidedProjection.Interfaces +namespace BRIDGES.Solvers.GuidedProjection.Abstracts { /// - /// Interface defining a quadratic constraint type for the . + /// Abstract class defining a constraint type. /// - public interface IQuadraticConstraintType + public abstract class ConstraintType { #region Properties /// /// Gets the local symmetric matrix Hi of the energy. /// - SparseMatrix LocalHi { get; } + public SparseMatrix LocalHi { get; protected set; } /// /// Gets the local vector Bi of the energy. /// - SparseVector LocalBi { get; } + public SparseVector LocalBi { get; protected set; } /// /// Gets the scalar value Ci of the energy. /// - double Ci { get; } + public double Ci { get; protected set; } #endregion } diff --git a/BRIDGES/Solvers/GuidedProjection/Abstracts/EnergyType.cs b/BRIDGES/Solvers/GuidedProjection/Abstracts/EnergyType.cs new file mode 100644 index 0000000..ba40555 --- /dev/null +++ b/BRIDGES/Solvers/GuidedProjection/Abstracts/EnergyType.cs @@ -0,0 +1,27 @@ +using System; + +using BRIDGES.LinearAlgebra.Vectors; + + +namespace BRIDGES.Solvers.GuidedProjection.Abstracts +{ + /// + /// Abstract class defining an energy type. + /// + public abstract class EnergyType + { + #region Properties + + /// + /// Gets the local vector Ki of this energy. + /// + public SparseVector LocalKi { get; protected set; } + + /// + /// Gets the scalar value Si of this energy. + /// + public double Si { get; protected set; } + + #endregion + } +} diff --git a/BRIDGES/Solvers/GuidedProjection/Abstracts/LinearisedConstraintType.cs b/BRIDGES/Solvers/GuidedProjection/Abstracts/LinearisedConstraintType.cs new file mode 100644 index 0000000..d457385 --- /dev/null +++ b/BRIDGES/Solvers/GuidedProjection/Abstracts/LinearisedConstraintType.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + + +namespace BRIDGES.Solvers.GuidedProjection.Abstracts +{ + /// + /// Abstract class defining a linearised constraint type. + /// + public abstract class LinearisedConstraintType : ConstraintType + { + #region Methods + + /// + /// Updates the local members (i.e. LocalHi and LocalBi) and the value Ci of the linearised constraint using the local variables. + /// + /// Actualised value of the constraint's local variables. + public abstract void UpdateLocal(IReadOnlyList variables); + + #endregion + } +} diff --git a/BRIDGES/Solvers/GuidedProjection/Constraint.cs b/BRIDGES/Solvers/GuidedProjection/Constraint.cs new file mode 100644 index 0000000..e849a44 --- /dev/null +++ b/BRIDGES/Solvers/GuidedProjection/Constraint.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; + +using BRIDGES.Solvers.GuidedProjection.Abstracts; + + +namespace BRIDGES.Solvers.GuidedProjection +{ + /// + /// Class defining a quadratic constraint for the . + /// + public sealed class Constraint + { + #region Fields + + /// + /// Variables composing the local vector localX on which the is defined. + /// + private readonly Variable[] _variables; + + #endregion + + #region Properties + + /// /// + /// Gets the constraint type defining the local matrix , the local vector and the scalar value . + /// + public ConstraintType Type { get; private set; } + + /// + /// Gets the variables composing the local vector localX. + /// + public IReadOnlyList Variables => _variables; + + + /// + /// Gets or sets the weight of this constraint. + /// + public double Weight { get; internal set; } + + #endregion + + #region Constructors + + /// + /// Initialises a new instance of the class. + /// + /// Constraint type defining the local quantities of this constraint. + /// Variables composing the local vector localX on which the local symmetric matrix Hi and the local vector Bi are defined. + /// Weight of this constraint. + public Constraint(ConstraintType constraintType, IReadOnlyList variables, double weight) + { + this.Type = constraintType; + + this._variables = new Variable[variables.Count]; + for (int i = 0; i < variables.Count; i++) + { + _variables[i] = variables[i]; + } + + Weight = weight; + } + + #endregion + } +} diff --git a/BRIDGES/Solvers/GuidedProjection/Energy.cs b/BRIDGES/Solvers/GuidedProjection/Energy.cs index 71c06d0..9af1eb8 100644 --- a/BRIDGES/Solvers/GuidedProjection/Energy.cs +++ b/BRIDGES/Solvers/GuidedProjection/Energy.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection @@ -9,27 +9,32 @@ namespace BRIDGES.Solvers.GuidedProjection /// /// Class defining an energy for the . /// - public class Energy + public sealed class Energy { #region Fields /// - /// Energy type defining the reduced vector and the scalar value . + /// Variables composing the local vector localX on which the is defined. /// - internal protected IEnergyType energyType; + private readonly Variable[] _variables; - /// - /// Variables composing the local vector xReduced on which the is defined. - /// - /// The first component corresponds to the variable set and the second to the index of the variable in the set. - internal protected List<(VariableSet Set, int Index)> variables; - #endregion #region Properties /// - /// Gets or sets the weight of the energy. + /// Gets the energy type defining the local vector and the scalar value . + /// + public EnergyType Type { get; private set; } + + /// + /// Gets the variables composing the local vector localX. + /// + public IReadOnlyList Variables => _variables; + + + /// + /// Gets or sets the weight of this energy. /// public double Weight { get; internal set; } @@ -40,16 +45,19 @@ public class Energy /// /// Initialises a new instance of the class. /// - /// Energy type defining the energy locally. - /// Variables composing the reduced vector xReduced. + /// Energy type defining the local quantities of the energy. + /// Variables composing the local vector localX. /// Weight of the energy. - internal Energy(IEnergyType energyType, List<(VariableSet, int)> variablesKi, double weight) + public Energy(EnergyType energyType, IReadOnlyList variablesKi, double weight) { - // Initialise Fields - this.energyType = energyType; - this.variables = variablesKi; + this.Type = energyType; + + this._variables = new Variable[variablesKi.Count]; + for (int i = 0; i < variablesKi.Count; i++) + { + _variables[i] = variablesKi[i]; + } - // Initialise Properties Weight = weight; } diff --git a/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentOrthogonality.cs b/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentOrthogonality.cs index afe0818..56cc174 100644 --- a/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentOrthogonality.cs +++ b/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentOrthogonality.cs @@ -2,50 +2,68 @@ using System.Collections.Generic; using BRIDGES.LinearAlgebra.Vectors; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection.EnergyTypes { /// - /// Energy enforcing a segment defined from two point variables, pi and pj, to be orthogonal to a constant direction v. + /// Energy enforcing a segment to be orthogonal to a fixed direction V. The list of variables of this energy consists in: + /// + /// + /// Ps + /// Variable representing the start point of the segment. + /// + /// + /// Pe + /// Variable representing the end point of the segment. + /// + /// /// - /// The vector xReduced = [pi, pj]. - public class SegmentOrthogonality : IEnergyType + public class SegmentOrthogonality : EnergyType { - #region Properties - - /// - public SparseVector LocalKi { get; } - - /// - public double Si { get; } - - #endregion - #region Constructors /// /// Initialises a new instance of the class. /// - /// Coordinates of the target direction vector. - public SegmentOrthogonality(double[] coordinates) + /// Coordinates of the direction vector to which the segment must be orthogonal. + public SegmentOrthogonality(double[] direction) { - /******************** Define LocalKi ********************/ + // ----- Unitise the direction ----- // + + bool isZero = true; + double length = 0d; + for (int i = 0; i < direction.Length; i++) + { + if (isZero & Settings.AbsolutePrecision < Math.Abs(direction[i])) { isZero = false; } + + length += direction[i] * direction[i]; + } + length = Math.Sqrt(length); + + if (isZero) { throw new DivideByZeroException("The length of the target direction must be different from zero."); } + + for (int i = 0; i < direction.Length; i++) + { + direction[i] = direction[i] / length; + } + + // ----- Define LocalKi ----- // - Dictionary components = new Dictionary((2 * coordinates.Length)); - for (int i = 0; i < coordinates.Length; i++) + Dictionary components = new Dictionary((2 * direction.Length)); + for (int i = 0; i < direction.Length; i++) { - components.Add(i, -coordinates[i]); - components.Add(coordinates.Length + i, coordinates[i]); + components.Add(i, -direction[i]); + components.Add(direction.Length + i, direction[i]); } - LocalKi = new SparseVector(2 * coordinates.Length, ref components); + LocalKi = new SparseVector(2 * direction.Length, ref components); - /******************** Define Si ********************/ + // ----- Define Si ----- // - Si = 0.0; + Si = 0d; } #endregion diff --git a/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentParallelity.cs b/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentParallelity.cs index 9943a98..c6d1169 100644 --- a/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentParallelity.cs +++ b/BRIDGES/Solvers/GuidedProjection/EnergyTypes/SegmentParallelity.cs @@ -2,69 +2,74 @@ using System.Collections.Generic; using BRIDGES.LinearAlgebra.Vectors; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection.EnergyTypes { /// - /// Energy enforcing a segment defined from two point variables, pi and pj, to be parallel to a constant direction v. + /// Energy enforcing a segment to be parallel to a fixed direction V. The list of variables of this energy consists in: + /// + /// + /// Ps + /// Variable representing the start point of the segment. + /// + /// + /// Pe + /// Variable representing the end point of the segment. + /// + /// + /// L + /// Variable representing the length of the segment. + /// + /// /// - /// - /// A scalar variable l identified as the segment length must be defined.
- /// The vector xReduced = [pi, pj, l]. - ///
- public class SegmentParallelity : IEnergyType + /// The definition of a variable representing the length between to other variables must be accompanied by the use of the constraint. + public class SegmentParallelity : EnergyType { - #region Properties - - /// - public SparseVector LocalKi { get; } - - /// - public double Si { get; } - - #endregion - #region Constructors /// - /// Initialises a new instance of the class by defining the coordinates of the target direction vector. + /// Initialises a new instance of the class. /// - /// Coordinates of the target direction vector. - public SegmentParallelity(double[] coordinates) + /// Coordinates of the direction vector to which the segment must be parallel. + public SegmentParallelity(double[] direction) { - // Unitise the direction vector - double length = 0.0; - for (int i = 0; i < coordinates.Length; i++) + // ----- Unitise the direction ----- // + + bool isZero = true; + double length = 0d; + for (int i = 0; i < direction.Length; i++) { - length += coordinates[i] * coordinates[i]; + if (isZero & Settings.AbsolutePrecision < Math.Abs(direction[i])) { isZero = false; } + + length += direction[i] * direction[i]; } length = Math.Sqrt(length); - if (length == 0.0) - { - throw new DivideByZeroException("The length of the target direction vector must be different than zero."); - } + if (isZero) { throw new DivideByZeroException("The length of the target direction must be different from zero."); } - for (int i = 0; i < coordinates.Length; i++) + for (int i = 0; i < direction.Length; i++) { - coordinates[i] = coordinates[i] / length; + direction[i] = direction[i] / length; } - /******************** Define LocalKi ********************/ - Dictionary component = new Dictionary((2 * coordinates.Length) + 1); - for (int i = 0; i < coordinates.Length; i++) + // ----- Define LocalKi ----- // + + Dictionary component = new Dictionary((2 * direction.Length) + 1); + for (int i = 0; i < direction.Length; i++) { - component.Add(i, -coordinates[i]); - component.Add(coordinates.Length + i, coordinates[i]); + component.Add(i, -direction[i]); + component.Add(direction.Length + i, direction[i]); } - component.Add(2 * coordinates.Length, -1); + component.Add(2 * direction.Length, -1); + + LocalKi = new SparseVector((2 * direction.Length) + 1, ref component); + - LocalKi = new SparseVector((2 * coordinates.Length) + 1, ref component); + // ----- Define Si ----- // - /******************** Define Si ********************/ Si = 0.0; } diff --git a/BRIDGES/Solvers/GuidedProjection/GuidedProjectionAlgorithm.cs b/BRIDGES/Solvers/GuidedProjection/GuidedProjectionAlgorithm.cs index ca8bb11..9231bc3 100644 --- a/BRIDGES/Solvers/GuidedProjection/GuidedProjectionAlgorithm.cs +++ b/BRIDGES/Solvers/GuidedProjection/GuidedProjectionAlgorithm.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; using System.Collections.Generic; @@ -7,8 +7,8 @@ using BRIDGES.LinearAlgebra.Matrices.Sparse; using BRIDGES.LinearAlgebra.Matrices.Storage; -using BRIDGES.Solvers.GuidedProjection.Interfaces; -using System.Drawing; +using BRIDGES.Solvers.GuidedProjection.Abstracts; + namespace BRIDGES.Solvers.GuidedProjection { @@ -20,15 +20,15 @@ public sealed class GuidedProjectionAlgorithm { #region Events - /******************** For Weigths ********************/ + // ---------- For Weigths ---------- // /// - /// Event raised whenever and weights needs to be updated. + /// Event raised whenever and weights needs to be updated. /// private event Action WeigthUpdate; /// - /// Raises the event which updates the and the weights. + /// Raises the event which updates the and the weights. /// /// Index of the current iteration. private void OnWeigthUpdate(int iteration) @@ -37,20 +37,19 @@ private void OnWeigthUpdate(int iteration) } - /******************** For Quadratic Constraints ********************/ + // ---------- For Quadratic Constraints ---------- // /// - /// Event raised whenever the members of needs to be updated. + /// Event raised whenever the members of needs to be updated. /// - private event Action ConstraintUpdate; + private event Action LinearisedConstraintUpdate; /// - /// Raises the event which updates the members of . + /// Raises the event which updates the members of . /// - /// Global vector X at the current iteration. - private void OnConstraintUpdate(in DenseVector x) + private void OnLinearisedConstraintUpdate() { - ConstraintUpdate?.Invoke(x); + LinearisedConstraintUpdate?.Invoke(); } #endregion @@ -58,25 +57,32 @@ private void OnConstraintUpdate(in DenseVector x) #region Fields /// - /// List of the variable sets for the . + /// Collection of variables of this . /// - private List _variableSets; + /// The use of the collection allows for efficient search, but does not provide indexing. + private readonly HashSet _variables; /// - /// List of the energies for the . + /// List of energies of this . /// - private List _energies; + /// The use of the collection allows for efficient search, but does not provide indexing. + private readonly HashSet _energies; /// - /// List of the constraints for the . + /// List of constraints of this . + /// The use of the collection allows for efficient search, but does not provide indexing. /// - private List _constraints; + private readonly HashSet _constraints; + /// - /// Vector containing the variables of the . + /// Vector containing the variables of this . /// private DenseVector _x; + + // ---------- Utilities ---------- // + /// /// Identity matrix multiplied by Epsilon*Epsilon. /// @@ -87,12 +93,21 @@ private void OnConstraintUpdate(in DenseVector x) #region Properties /// - /// Gets the vector containing all the components of the . + /// Gets the number of components in the global vector X of this . + /// + public int ComponentCount { get; private set; } = 0; + + /// + /// Gets the number of energies of this . /// - public Vector X { get { return _x; } } + public int EnergyCount => _energies.Count; + /// + /// Gets the number of constraints of this . + /// + public int ConstraintCount => _constraints.Count; - /**************************************** Settings ****************************************/ + // ---------- Settings ---------- // /// /// Gets or sets the maximum number of iteration after which the solver is stopped. @@ -100,40 +115,38 @@ private void OnConstraintUpdate(in DenseVector x) public int MaxIteration { get; set; } /// - /// Gets the zero-based index of the current iteration. + /// Gets index of the current iteration. /// - public int IterationIndex { get; internal set; } + /// Zero means that no iteration was runned. + public int Iteration { get; internal set; } - /**************************************** For Solving ****************************************/ + // ---------- For Solving ---------- // /// /// Gets or sets the weight of the distance to the previous iteration. /// - double Epsilon { get; set; } + public double Epsilon { get; private set; } #endregion #region Constructors /// - /// Initializes a new instance of the class. + /// Initialises a new instance of the class. /// /// The weights of the distance to the previous iteration. /// The iteration index after which the solver is stopped. public GuidedProjectionAlgorithm(double epsilon, int maxIteration) { // Instanciate Fields - _variableSets = new List(); - - _energies = new List(); - - _constraints = new List(); - + _variables = new HashSet(); + _energies = new HashSet(); + _constraints = new HashSet(); // Initialize Properties MaxIteration = maxIteration; - IterationIndex = 0; + Iteration = 0; Epsilon = epsilon; } @@ -142,189 +155,196 @@ public GuidedProjectionAlgorithm(double epsilon, int maxIteration) #region Methods - /******************** For Variables ********************/ + // ---------- For Variables ---------- // /// - /// Creates a new and adds it after the other ones. + /// Creates a variable from its components and adds it to this model. /// - /// The dimension of the variables contained in set. - /// The newly created . - public VariableSet AddVariableSet(int variableDimension) + /// Values of the variable's components. + /// The newly added . + public Variable AddVariable(params double[] components) { - int setIndex = _variableSets.Count; + Variable variable = new Variable(components); - int firstRank; - if (setIndex == 0) { firstRank = 0; } - else - { - VariableSet previousSet = _variableSets[setIndex - 1]; - firstRank = previousSet.FirstRank + (previousSet.VariableCount * previousSet.VariableDimension); - } + _variables.Add(variable); + ComponentCount += variable.Dimension; - VariableSet newSet = new VariableSet(setIndex, firstRank, variableDimension); - _variableSets.Add(newSet); - return newSet; + return variable; } + /// - /// Creates a new and adds it after the other ones. + /// Attempts to add the specified variable to this model. /// - /// The dimension of the variables contained in set. - /// The indicative number of variables that the new set can initially store. - /// The newly created . - public VariableSet AddVariableSet(int variableDimension, int setCapacity) + /// Variable to add. + /// if the variable was added, if the variable already exists in the model. + public bool TryAddVariable(Variable variable) { - int setIndex = _variableSets.Count; - - int firstRank; - if (setIndex == 0) { firstRank = 0; } + if(_variables.Contains(variable)) // Complexity : O(1) + { + return false; + } else { - VariableSet previousSet = _variableSets[setIndex - 1]; - firstRank = previousSet.FirstRank + (previousSet.VariableCount * previousSet.VariableDimension); - } + _variables.Add(variable); + ComponentCount += variable.Dimension; - VariableSet newSet = new VariableSet(setIndex, firstRank, variableDimension, setCapacity); - _variableSets.Add(newSet); - return newSet; + return true; + } } - /******************** For Energies ********************/ + // ---------- For Energies ---------- // /// - /// Creates a new with a constant weight and adds it to the list. + /// Creates a new with a constant weight and adds it to this model. /// - /// Energy type defining the energy locally. - /// Variables composing the local vector xReduced. - /// Weight for the energy. - /// The new energy. - public Energy AddEnergy(IEnergyType energyType, List<(VariableSet, int)> variables, double weight = 1.0) + /// Energy type defining the local quantities of the energy. + /// + /// Variables composing the local vector localX. + /// See the class description to learn about the expected variables. The order of the variables matters. + /// + /// Weight of the energy. + public void AddEnergy(EnergyType energyType, IReadOnlyList variables, double weight = 1.0) { Energy energy = new Energy(energyType, variables, weight); _energies.Add(energy); - - return energy; } /// - /// Creates a new with a varying weight and adds it to the list. + /// Creates a new with a varying weight and adds it to this model. /// /// Energy type defining the energy locally. - /// Variables composing the local vector xReduced. + /// + /// Variables composing the local vector localX. + /// See the class description to learn about the expected variables. The order of the variables matters. + /// /// Function computing the weight from the iteration index. - /// - public Energy AddEnergy(IEnergyType energyType, List<(VariableSet, int)> variables, Func weightFunction) + public void AddEnergy(EnergyType energyType, IReadOnlyList variables, Func weightFunction) { Energy energy = new Energy(energyType, variables, 0.0); _energies.Add(energy); void energyWeightUpdater(int iteration) => energy.Weight = weightFunction(iteration); WeigthUpdate += energyWeightUpdater; - - return energy; } - /******************** For Quadratic Constraints ********************/ - /// - /// Creates a new with a constant weight and adds it to the list. + /// Attempts to add the specified energy to this model. /// - /// Quadratic constraint type defining the constraint locally. - /// Variables composing the local vector xReduced. - /// Weight for the constraint. - /// The new constraint. - public QuadraticConstraint AddConstraint(IQuadraticConstraintType constraintType, List<(VariableSet, int)> variables, double weight = 1.0) - { - QuadraticConstraint constraint = new QuadraticConstraint(constraintType, variables, weight); - _constraints.Add(constraint); - - return constraint; - } - - /// - /// Creates a new with a varying weight and adds it to the list. - /// - /// Quadratic constraint type defining the constraint locally. - /// Variables composing the local vector xReduced. - /// Function computing the weight from the iteration index. - /// The new constraint. - public QuadraticConstraint AddConstraint(IQuadraticConstraintType constraintType, List<(VariableSet, int)> variables, Func weightFunction) + /// Energy to add. + /// if the energy was added, if the energy already exists in the model. + public bool TryAddEnergy(Energy energy) { - QuadraticConstraint constraint = new QuadraticConstraint(constraintType, variables, 0.0); - _constraints.Add(constraint); - - void constraintWeightUpdater(int iteration) => constraint.Weight = weightFunction(iteration); - WeigthUpdate += constraintWeightUpdater; + if (_energies.Contains(energy)) // Complexity : O(1) + { + return false; + } + else + { + _energies.Add(energy); - return constraint; + return true; + } } - - /******************** For Linearised Constraints ********************/ + // ---------- For Quadratic Constraints ---------- // /// - /// Creates a new with a constant weight and adds it to the list. + /// Creates a new with a constant weight and adds it to this model. /// - /// Quadratic constraint type defining the constraint locally. - /// Variables composing the local vector xReduced. - /// Weight for the constraint. - /// The new constraint. - public LinearisedConstraint AddConstraint(ILinearisedConstraintType constraintType, List<(VariableSet, int)> variables, double weight = 1.0) + /// Constraint type defining the constraint locally. + /// + /// Variables composing the local vector localX. + /// See the class description to learn about the expected variables. The order of the variables matters. + /// + /// Weight for the constraint. + public void AddConstraint(ConstraintType constraintType, IReadOnlyList variables, double weight = 1.0) { - LinearisedConstraint constraint = new LinearisedConstraint(constraintType, variables, weight); + Constraint constraint = new Constraint(constraintType, variables, weight); _constraints.Add(constraint); - return constraint; + if (constraintType is LinearisedConstraintType linearisedType) + { + LinearisedConstraintUpdate += () => linearisedType.UpdateLocal(variables); ; + } } /// - /// Creates a new with a varying weight and adds it to the list. + /// Creates a new with a varying weight and adds it to this model. /// /// Quadratic constraint type defining the constraint locally. - /// Variables composing the local vector xReduced. + /// + /// Variables composing the local vector localX. + /// See the class description to learn about the expected variables. The order of the variables matters. + /// /// Function computing the weight from the iteration index. - /// The new constraint. - public LinearisedConstraint AddConstraint(ILinearisedConstraintType constraintType, List<(VariableSet, int)> variables, Func weightFunction) + public void AddConstraint(ConstraintType constraintType, IReadOnlyList variables, Func weightFunction) { - LinearisedConstraint constraint = new LinearisedConstraint(constraintType, variables, 0.0); + Constraint constraint = new Constraint(constraintType, variables, 0.0); _constraints.Add(constraint); void constraintWeightUpdater(int iteration) => constraint.Weight = weightFunction(iteration); WeigthUpdate += constraintWeightUpdater; - return constraint; + if (constraintType is LinearisedConstraintType linearisedType) + { + LinearisedConstraintUpdate += () => linearisedType.UpdateLocal(variables); ; + } } - /**************************************** For Solving ****************************************/ + /// + /// Attempts to add the specified constraint to this model. + /// + /// Constraint to add. + /// if the constraint was added, if the constraint already exists in the model. + public bool TryAddConstraint(Constraint constraint) + { + if (_constraints.Contains(constraint)) // Complexity : O(1) + { + return false; + } + else + { + _constraints.Add(constraint); + + return true; + } + } + + // ---------- For Solving ---------- // /// - /// Initialise the solver for the . + /// Initialises the members of this . /// public void InitialiseX() { - /******************** Create global X (Variable) ********************/ + // ----- Global vector X ----- // + + double[] array = new double[ComponentCount]; // ComponentCount is updated - // Get the size X - VariableSet lastVariableSet = _variableSets[_variableSets.Count - 1]; - int sizeX = lastVariableSet.FirstRank + (lastVariableSet.VariableCount * lastVariableSet.VariableDimension); + int i_Comp = 0; - // Create and fill X - _x = new DenseVector(sizeX); - for (int i_VariableSet = 0; i_VariableSet < _variableSets.Count; i_VariableSet++) + foreach (Variable variable in _variables) { - VariableSet variableSet = _variableSets[i_VariableSet]; - int componentCount = variableSet.VariableCount * variableSet.VariableDimension; - for (int i_Component = 0; i_Component < componentCount; i_Component++) + // Set the components in the global vector X + for (int i_VarComp = 0; i_VarComp < variable.Dimension; i_VarComp++) { - _x[variableSet.FirstRank + i_Component] = variableSet.GetComponent(i_Component); + array[i_Comp + i_VarComp] = variable[i_VarComp]; } + + // Change the reference in the variable to point toward a segment of the global vector X + variable.ChangeReference(array, i_Comp); + + + i_Comp += variable.Dimension; } + _x = new DenseVector(ref array); - /******************** Create Utilities ********************/ + // ----- Utilities ----- // _epsEpsIdentity = CompressedColumn.Multiply(Epsilon * Epsilon, CompressedColumn.Identity(_x.Size)); } @@ -335,41 +355,34 @@ public void InitialiseX() /// Evaluates whether the iteration should use asynchronous programming or not. public void RunIteration(bool useAsync) { - /********** Iteration Updates **********/ + // ----- Iteration Updates ----- // - OnConstraintUpdate(_x); + OnLinearisedConstraintUpdate(); - OnWeigthUpdate(IterationIndex); + OnWeigthUpdate(Iteration); - /********** Formulate and Solve the System **********/ + // ----- Formulate and Solve the System ----- // + DenseVector x; if (useAsync) { var task = FormAndSolveSystem_Async(); Task.WaitAll(task); - _x = task.Result; + x = task.Result; } else { - _x = FormAndSolveSystem(); + x = FormAndSolveSystem(); } - /********** Update Variables **********/ + // ----- Update Variables ----- // - // Fill the VariableSet with the updated values - for (int i_VariableSet = 0; i_VariableSet < _variableSets.Count; i_VariableSet++) - { - VariableSet variableSet = _variableSets[i_VariableSet]; - int componentCount = variableSet.VariableCount * variableSet.VariableDimension; - for (int i_Component = 0; i_Component < componentCount; i_Component++) - { - variableSet.SetComponent(i_Component, _x[variableSet.FirstRank + i_Component]); - } - } + // Fill the _x with the actualised values + for (int i = 0; i < x.Size; i++) { _x[i] = x[i]; } } #endregion @@ -377,9 +390,9 @@ public void RunIteration(bool useAsync) #region Other Methods /// - /// Compute the members of the system and solves it using Cholesky factorisation. + /// Computes the members of the system and solve it using Cholesky factorisation. /// - /// The solution of the sytem. + /// The solution of the system. private DenseVector FormAndSolveSystem() { /******************** Iterate on the quadratic constraints to create H and r ********************/ @@ -389,7 +402,7 @@ private DenseVector FormAndSolveSystem() /******************** Iterate on the energies to create K and s ********************/ - FromEnergyMembers(out CompressedColumn K, out SparseVector s); + FormEnergyMembers(out CompressedColumn K, out SparseVector s); /******************** Solve the minimisation problem ********************/ @@ -401,7 +414,7 @@ private DenseVector FormAndSolveSystem() { CompressedColumn HtH = CompressedColumn.TransposeMultiplySelf(H); CompressedColumn KtK = CompressedColumn.TransposeMultiplySelf(K); - + LHS = CompressedColumn.Add(HtH, KtK); RHS = DenseVector.Add(CompressedColumn.TransposeMultiply(H, r), CompressedColumn.TransposeMultiply(K, s)); } @@ -429,9 +442,9 @@ private DenseVector FormAndSolveSystem() } /// - /// Compute the members of the system and solves it using Cholesky factorisation. + /// Computes the members of the system and solve it using Cholesky factorisation. /// - /// The solution of the sytem. + /// The solution of the system. private async Task FormAndSolveSystem_Async() { CompressedColumn LHS; // Left hand side of the equation @@ -507,10 +520,10 @@ private async Task FormAndSolveSystem_Async() #region Helper - Synchronous /// - /// Forms the system members derived from the constraints. + /// Forms the global system members derived from the constraints. /// - /// The matrix H. - /// The vector r. + /// The global matrix H. + /// The global vector r. private void FormConstraintMembers(out CompressedColumn H, out DenseVector r) { DictionaryOfKeys dok_H = new DictionaryOfKeys(10 * _constraints.Count /* Random */); @@ -518,67 +531,64 @@ private void FormConstraintMembers(out CompressedColumn H, out DenseVector r) int constraintCount = 0; - for (int i_Cstr = 0; i_Cstr < _constraints.Count; i_Cstr++) + foreach (Constraint cstr in _constraints) { - QuadraticConstraint cstr = _constraints[i_Cstr]; - // Verifications if (cstr.Weight == 0d) { continue; } - List<(VariableSet Set, int Index)> variables = cstr.variables; - IQuadraticConstraintType constraintType = cstr.constraintType; + IReadOnlyList variables = cstr.Variables; + ConstraintType constraintType = cstr.Type; - int sizeReduced = constraintType.LocalHi.ColumnCount; + int localSize = constraintType.LocalHi.ColumnCount; - /******************** Create the Row Indices ********************/ + // ----- Create the Row Indices ----- // - // Translating the local indices of the constraint defined on xReduced into global indices defined on x. - List rowIndices = new List(sizeReduced); + // Translate the local indices of the constraint defined on localX into global indices defined on X. + List rowIndices = new List(localSize); for (int i_Variable = 0; i_Variable < variables.Count; i_Variable++) { - int startIndex = variables[i_Variable].Set.FirstRank + (variables[i_Variable].Set.VariableDimension * variables[i_Variable].Index); - - for (int i_VarComp = 0; i_VarComp < variables[i_Variable].Set.VariableDimension; i_VarComp++) - { - rowIndices.Add(startIndex + i_VarComp); + Variable variable = variables[i_Variable]; + int offset = variable.Offset; + for (int i_VarComp = 0; i_VarComp < variable.Dimension; i_VarComp++) + { + rowIndices.Add(offset + i_VarComp); } } + // ----- Create localX ----- // - /******************** Create xReduced ********************/ - - double[] components = new double[sizeReduced]; - for (int i_Comp = 0; i_Comp < sizeReduced; i_Comp++) + double[] components = new double[localSize]; + for (int i_Comp = 0; i_Comp < localSize; i_Comp++) { components[i_Comp] = _x[rowIndices[i_Comp]]; } - DenseVector xReduced = new DenseVector(components); + DenseVector localX = new DenseVector(components); - /******************** Compute Temporary Values ********************/ + // ----- Compute Temporary Values ----- // // Compute HiX - DenseVector tmp_Vect = SparseMatrix.Multiply(constraintType.LocalHi, xReduced); + DenseVector tmp_Vect = SparseMatrix.Multiply(constraintType.LocalHi, localX); // Compute XtHiX - double tmp_Val = DenseVector.TransposeMultiply(xReduced, tmp_Vect); + double tmp_Val = DenseVector.TransposeMultiply(localX, tmp_Vect); - /******************** For r ********************/ + // ----- For r ----- // if (constraintType.Ci == 0.0) { list_r.Add(cstr.Weight * 0.5 * tmp_Val); } else { list_r.Add(cstr.Weight * (0.5 * tmp_Val - constraintType.Ci)); } - /******************** For H ********************/ + // ----- For H ----- // if (!(constraintType.LocalBi is null)) { - tmp_Vect = DenseVector.Add(tmp_Vect, cstr.constraintType.LocalBi); + tmp_Vect = DenseVector.Add(tmp_Vect, constraintType.LocalBi); } - for (int i_Comp = 0; i_Comp < sizeReduced; i_Comp++) + for (int i_Comp = 0; i_Comp < localSize; i_Comp++) { if (tmp_Vect[i_Comp] == 0d) { continue; } dok_H.Add(cstr.Weight * tmp_Vect[i_Comp], constraintCount, rowIndices[i_Comp]); @@ -587,55 +597,54 @@ private void FormConstraintMembers(out CompressedColumn H, out DenseVector r) constraintCount++; } + H = new CompressedColumn(constraintCount, _x.Size, dok_H); r = new DenseVector(list_r.ToArray()); } /// - /// Forms the system members derived from the energies. + /// Forms the global system members derived from the energies. /// - /// The matrix K. - /// The vector s. - private void FromEnergyMembers(out CompressedColumn K, out SparseVector s) + /// The global matrix K. + /// The global vector s. + private void FormEnergyMembers(out CompressedColumn K, out SparseVector s) { DictionaryOfKeys dok_K = new DictionaryOfKeys(10 * _energies.Count /* Random */); Dictionary dict_s = new Dictionary(_energies.Count); int energyCount = 0; - for (int i_Energy = 0; i_Energy < _energies.Count; i_Energy++) + foreach (Energy energy in _energies) { - Energy energy = _energies[i_Energy]; - // Verifications if (energy.Weight == 0d) { continue; } + IReadOnlyList variables = energy.Variables; + EnergyType energyType = energy.Type; - List<(VariableSet Set, int Index)> variables = energy.variables; - IEnergyType energyType = energy.energyType; - + int localSize = energyType.LocalKi.Size; - /******************** Create the Row Indices ********************/ + // ----- Create the Row Indices ----- // - // Translating the local indices of the constraint defined on xReduced into global indices defined on x. - List rowIndices = new List(); + // Translating the local indices of the constraint defined on localX into global indices defined on X. + List rowIndices = new List(localSize); for (int i_Variable = 0; i_Variable < variables.Count; i_Variable++) { - int startIndex = variables[i_Variable].Set.FirstRank + (variables[i_Variable].Set.VariableDimension * variables[i_Variable].Index); - - for (int i_Component = 0; i_Component < variables[i_Variable].Set.VariableDimension; i_Component++) + Variable variable = variables[i_Variable]; + int offset = variable.Offset; + for (int i_VarComp = 0; i_VarComp < variable.Dimension; i_VarComp++) { - rowIndices.Add(startIndex + i_Component); + rowIndices.Add(offset + i_VarComp); } } - /******************** For s ********************/ + // ----- For s ----- // if (!(energyType.Si == 0.0)) { dict_s.Add(energyCount, energy.Weight * energyType.Si); } - /******************** For K ********************/ + // ----- For K ----- // foreach ((int rowIndex, double value) in energyType.LocalKi.NonZeros()) { @@ -653,7 +662,7 @@ private void FromEnergyMembers(out CompressedColumn K, out SparseVector s) #region Helpers - Asynchronous - /********** Constraint Members **********/ + // ---------- Constraint Members ---------- // /// /// Forms the system members derived from the constraints. @@ -665,63 +674,59 @@ private void FromEnergyMembers(out CompressedColumn K, out SparseVector s) System.Collections.Concurrent.ConcurrentBag<(SortedDictionary ColumnHt, double ValueR)> bag = new System.Collections.Concurrent.ConcurrentBag<(SortedDictionary ColumnHt, double ValueR)>(); - Parallel.For(0, _constraints.Count, (int i_Cstr) => + Parallel.ForEach(_constraints, (Constraint cstr) => { - /******************** Initialise Iteration ********************/ - - QuadraticConstraint cstr = _constraints[i_Cstr]; - // Verifications if (cstr.Weight == 0d) { return; } - List<(VariableSet Set, int Index)> variables = cstr.variables; - IQuadraticConstraintType constraintType = cstr.constraintType; + IReadOnlyList variables = cstr.Variables; + ConstraintType constraintType = cstr.Type; - int sizeReduced = constraintType.LocalHi.ColumnCount; + int localSize = constraintType.LocalHi.ColumnCount; - /******************** Devise xReduced ********************/ + // ----- Devise LocalX ----- // - DenseVector xReduced = DeviseXReduced(sizeReduced, variables, out int[] rowIndices); + DenseVector localX = DeviseLocalX(localSize, variables, out int[] rowIndices); - /******************** Compute Temporary Values ********************/ + // ----- Compute Temporary Values ----- // // Compute HiX - DenseVector tmp_Vect = SparseMatrix.Multiply(constraintType.LocalHi, xReduced); + DenseVector tmp_Vect = SparseMatrix.Multiply(constraintType.LocalHi, localX); // Compute XtHiX - double tmp_Val = DenseVector.TransposeMultiply(xReduced, tmp_Vect); + double tmp_Val = DenseVector.TransposeMultiply(localX, tmp_Vect); - /******************** For r *******************/ + // ----- For r ----- // double valueR = 0d; if (constraintType.Ci == 0.0) { valueR = cstr.Weight * 0.5 * tmp_Val; } else { valueR = cstr.Weight * (0.5 * tmp_Val - constraintType.Ci); } - /******************** For Ht *******************/ + // ----- For Ht ----- // if (!(constraintType.LocalBi is null)) { tmp_Vect = DenseVector.Add(tmp_Vect, constraintType.LocalBi); } - Dictionary components = new Dictionary(sizeReduced); - for (int i_Comp = 0; i_Comp < sizeReduced; i_Comp++) + Dictionary components = new Dictionary(localSize); + for (int i_Comp = 0; i_Comp < localSize; i_Comp++) { if (tmp_Vect[i_Comp] == 0d) { continue; } components.Add(rowIndices[i_Comp], cstr.Weight * tmp_Vect[i_Comp]); } SortedDictionary columnHt = new SortedDictionary(components); - /******************** Finally *******************/ + // ----- Finally ----- // bag.Add((columnHt, valueR)); - }); + (CompressedColumn Ht, DenseVector r) = AssembleConstraintMembers(_x.Size, bag); (CompressedColumn HtH, DenseVector Htr) = MultiplyConstraintMembers(Ht, r); @@ -732,33 +737,33 @@ private void FromEnergyMembers(out CompressedColumn K, out SparseVector s) /// - /// Devises the component of xReduced. + /// Devises the component of LocalX. /// - /// Size of xReduced. - /// Variables contained in xReduced. - /// The row indices of the components composing xReduced. - /// The dense vector xReduced. - private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> variables, out int[] rowIndices) + /// Size of LocalX. + /// Variables contained in LocalX. + /// The row indices of the components composing LocalX. + /// The dense vector LocalX. + private DenseVector DeviseLocalX(int size, IReadOnlyList variables, out int[] rowIndices) { - /******************** Create the Row Indices ********************/ + // ----- Create the Row Indices ----- // - // Translating the local indices of the constraint defined on xReduced into global indices defined on x. + // Translating the local indices of the constraint defined on LocalX into global indices defined on X. rowIndices = new int[size]; int counter = 0; for (int i_Variable = 0; i_Variable < variables.Count; i_Variable++) { - int startIndex = variables[i_Variable].Set.FirstRank + (variables[i_Variable].Set.VariableDimension * variables[i_Variable].Index); - - for (int i_VarComp = 0; i_VarComp < variables[i_Variable].Set.VariableDimension; i_VarComp++) + Variable variable = variables[i_Variable]; + int offset = variable.Offset; + for (int i_VarComp = 0; i_VarComp < variable.Dimension; i_VarComp++) { - rowIndices[counter] = startIndex + i_VarComp; + rowIndices[counter] = offset + i_VarComp; counter++; } } - /******************** Create xReduced ********************/ + // ----- Create LocalX ----- // double[] components = new double[size]; for (int i_Comp = 0; i_Comp < size; i_Comp++) @@ -771,7 +776,7 @@ private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> /// - /// Assemble the data to create the tranposed matrix Ht and the vector r. + /// Assembles the data to create the tranposed matrix Ht and the vector r. /// /// Size of the global vector x. /// Collection containing the components of the constraint members. @@ -832,7 +837,7 @@ private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> } - /********** Energy Members **********/ + // ---------- Energy Members ---------- // /// /// Forms the system members derived from the energies. @@ -844,33 +849,31 @@ private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> System.Collections.Concurrent.ConcurrentBag<(SortedDictionary ColumnKt, double ValueS)> bag = new System.Collections.Concurrent.ConcurrentBag<(SortedDictionary ColumnKt, double ValueS)>(); - Parallel.For(0, _energies.Count, (int i_Energy) => + Parallel.ForEach(_energies, (Energy energy) => { - Energy energy = _energies[i_Energy]; - // Verifications if (energy.Weight == 0d) { return; } - List<(VariableSet Set, int Index)> variables = energy.variables; - IEnergyType energyType = energy.energyType; + IReadOnlyList variables = energy.Variables; + EnergyType energyType = energy.Type; - int sizeReduced = energyType.LocalKi.Size; + int localSize = energyType.LocalKi.Size; - /******************** Create the Row Indices ********************/ + // ----- Create the Row Indices ----- // - // Translating the local indices of the constraint defined on xReduced into global indices defined on x. + // Translating the local indices of the constraint defined on LocalX into global indices defined on x. List rowIndices = new List(); for (int i_Variable = 0; i_Variable < variables.Count; i_Variable++) { - int startIndex = variables[i_Variable].Set.FirstRank + (variables[i_Variable].Set.VariableDimension * variables[i_Variable].Index); - - for (int i_Component = 0; i_Component < variables[i_Variable].Set.VariableDimension; i_Component++) + Variable variable = variables[i_Variable]; + int offset = variable.Offset; + for (int i_VarComp = 0; i_VarComp < variable.Dimension; i_VarComp++) { - rowIndices.Add(startIndex + i_Component); + rowIndices.Add(offset + i_VarComp); } } - /******************** For s ********************/ + // ----- For s ----- // double valueS = 0.0; if (!(energyType.Si == 0.0)) @@ -878,9 +881,9 @@ private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> valueS = energy.Weight * energyType.Si; } - /******************** For Kt ********************/ + // ----- For Kt ----- // - Dictionary components = new Dictionary(sizeReduced); + Dictionary components = new Dictionary(localSize); foreach ((int rowIndex, double value) in energyType.LocalKi.NonZeros()) { components.Add(rowIndices[rowIndex], energy.Weight * value); @@ -888,14 +891,14 @@ private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> SortedDictionary ColumnKt = new SortedDictionary(components); - /******************** Finally *******************/ + // ----- Finally ----- // bag.Add((ColumnKt, valueS)); - }); - (CompressedColumn Kt, SparseVector s) = AssembleEnergyMembers(_x.Size, bag); + (CompressedColumn Kt, SparseVector s) = AssembleEnergyMembers(_x.Size, bag); + (CompressedColumn KtK, SparseVector Kts) = MultiplyEnergyMembers(Kt, s); return (KtK, Kts as Vector); @@ -904,7 +907,7 @@ private DenseVector DeviseXReduced(int size, List<(VariableSet Set, int Index)> /// - /// Assemble the data to create the tranposed matrix Kt and the vector s. + /// Assembles the data to create the tranposed matrix Kt and the vector s. /// /// Size of the global vector x. /// Collection containing the components of the constraint members. diff --git a/BRIDGES/Solvers/GuidedProjection/Interfaces/IEnergyType.cs b/BRIDGES/Solvers/GuidedProjection/Interfaces/IEnergyType.cs deleted file mode 100644 index 1a415f3..0000000 --- a/BRIDGES/Solvers/GuidedProjection/Interfaces/IEnergyType.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -using BRIDGES.LinearAlgebra.Vectors; - - -namespace BRIDGES.Solvers.GuidedProjection.Interfaces -{ - /// - /// Interface defining an energy type for the . - /// - public interface IEnergyType - { - #region Properties - - /// - /// Gets the local vector Ki of the energy. - /// - SparseVector LocalKi { get; } - - /// - /// Gets the scalar value Si of the energy. - /// - double Si { get; } - - #endregion - } -} diff --git a/BRIDGES/Solvers/GuidedProjection/Interfaces/ILinearisedConstraintType.cs b/BRIDGES/Solvers/GuidedProjection/Interfaces/ILinearisedConstraintType.cs deleted file mode 100644 index b10c46c..0000000 --- a/BRIDGES/Solvers/GuidedProjection/Interfaces/ILinearisedConstraintType.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; - - -namespace BRIDGES.Solvers.GuidedProjection.Interfaces -{ - /// - /// Interface defining a linearised constraint type for the . - /// - public interface ILinearisedConstraintType : IQuadraticConstraintType - { - #region Methods - - /// - /// Updates the local members (LocalHi, LocalBi) of the linearised constraint using xReduced. - /// - /// Actualized components of the local vector xReduced formed from the constraint variables. - void UpdateLocal(double[] xReduced); - - #endregion - } -} diff --git a/BRIDGES/Solvers/GuidedProjection/LinearisedConstraint.cs b/BRIDGES/Solvers/GuidedProjection/LinearisedConstraint.cs deleted file mode 100644 index 357804c..0000000 --- a/BRIDGES/Solvers/GuidedProjection/LinearisedConstraint.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; - -using BRIDGES.LinearAlgebra.Vectors; - -using BRIDGES.Solvers.GuidedProjection.Interfaces; - - -namespace BRIDGES.Solvers.GuidedProjection -{ - /// - /// Class defining a linearised constraint for the . - /// - public sealed class LinearisedConstraint : QuadraticConstraint - { - #region Constructors - - /// - /// Initialises a new instance of the class. - /// - /// Constraint type defining the constraint locally. - /// Variables composing the reduced vector xReduced on which the local symmetric matrix Hi and the local vector Bi are defined. - /// Weight of the constraint. - internal LinearisedConstraint(ILinearisedConstraintType constraintType, List<(VariableSet, int)> variables, double weight) - : base(constraintType, variables, weight) - { - /* Do nothing */ - } - - #endregion - - #region Other Methods - - /// - /// Updates the local members (LocalHi, LocalBi) of the linearised constraint using x, - /// - /// Global vector x at the current iteration. - internal void Update(DenseVector x) - { - double[] xReduced = GetXReduced(x); - - ILinearisedConstraintType linearisedConstraintType = constraintType as ILinearisedConstraintType; - linearisedConstraintType.UpdateLocal(xReduced); - } - - - /// - /// Retrieves the components of the local vector xReduced from its global equivalent x. - /// - /// The global vector x. - /// the components of xReduced - private double[] GetXReduced(in DenseVector x) - { - List result = new List(); - for (int i_LocalVariable = 0; i_LocalVariable < variables.Count; i_LocalVariable++) - { - VariableSet variableSet = variables[i_LocalVariable].Set; - int variableIndex = variables[i_LocalVariable].Index; - - result.AddRange(variableSet.GetVariable(variableIndex)); - } - - return result.ToArray(); - } - - #endregion - } -} diff --git a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraint.cs b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraint.cs deleted file mode 100644 index 517277b..0000000 --- a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraint.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; - -using BRIDGES.Solvers.GuidedProjection.Interfaces; - - -namespace BRIDGES.Solvers.GuidedProjection -{ - /// - /// Class defining a quadratic constraint for the . - /// - public class QuadraticConstraint - { - #region Fields - - /// /// - /// Constraint type defining the reduced matrix , - /// the reduced vector and the scalar value . - /// - internal protected IQuadraticConstraintType constraintType; - - /// - /// Variables composing the local vector xReduced on which the is defined. - /// - /// The first item corresponds to the variable set and the second to the index of the variable in the set. - internal protected List<(VariableSet Set, int Index)> variables; - - #endregion - - #region Properties - - /// - /// Gets or sets the value of the weight for the constraint. - /// - public double Weight { get; internal set; } - - #endregion - - #region Constructors - - /// - /// Initialises a new instance of the class. - /// - /// Constraint type defining the constraint locally. - /// Variables composing the reduced vector xReduced on which the local symmetric matrix Hi and the local vector Bi are defined. - /// Weight of the constraint. - internal QuadraticConstraint(IQuadraticConstraintType constraintType, List<(VariableSet, int)> variables, double weight) - { - // Initialize Properties - this.constraintType = constraintType; - this.variables = variables; - - // Initialize Properties - Weight = weight; - } - - #endregion - } -} diff --git a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/CoherentLength.cs b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/CoherentLength.cs index 415e837..a1b391a 100644 --- a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/CoherentLength.cs +++ b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/CoherentLength.cs @@ -1,72 +1,71 @@ using System; -using BRIDGES.LinearAlgebra.Vectors; -using BRIDGES.LinearAlgebra.Matrices; using BRIDGES.LinearAlgebra.Matrices.Sparse; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection.QuadraticConstraintTypes { /// - /// Constraint enforcing a scalar variable l to match with the distance between two point variables, pi and pj. + /// Constraint enforcing a scalar variable to match with the distance between two variables. The list of variables of this constraint consists in: + /// + /// + /// Pi + /// First variable with which the distance is being computed. + /// + /// + /// Pj + /// Second variable with which the distance is being computed. + /// + /// + /// L + /// Scalar variable to match with the distance. + /// + /// /// - /// The vector xReduced = [pi, pj, l]. - public class CoherentLength : IQuadraticConstraintType + public class CoherentLength : ConstraintType { - #region Properties - - /// - public SparseMatrix LocalHi { get; } - - /// - public SparseVector LocalBi { get; } - - /// - public double Ci { get; } - - #endregion - #region Constructors /// /// Initialises a new instance of the class. /// - /// Dimension of the space containing the points. - public CoherentLength(int spaceDimension = 3) + /// Common dimension of the variables with which the distance is being computed. + public CoherentLength(int dimension) { - /******************** Define LocalHi ********************/ + // ----- Define LocalHi ----- // - int[] columnPointers = new int[(2 * spaceDimension) + 2]; - int[] rowIndices = new int[(4 * spaceDimension) + 1]; - double[] values = new double[(4 * spaceDimension) + 1]; + int[] columnPointers = new int[(2 * dimension) + 2]; + int[] rowIndices = new int[(4 * dimension) + 1]; + double[] values = new double[(4 * dimension) + 1]; columnPointers[0] = 0; - for (int i_C = 0; i_C < spaceDimension; i_C++) + for (int i_C = 0; i_C < dimension; i_C++) { columnPointers[i_C + 1] = 2 * (i_C + 1); - rowIndices[(2 * i_C)] = i_C; rowIndices[(2 * i_C) + 1] = spaceDimension + i_C; + rowIndices[(2 * i_C)] = i_C; rowIndices[(2 * i_C) + 1] = dimension + i_C; values[(2 * i_C)] = 2.0; values[(2 * i_C) + 1] = -2.0; - columnPointers[spaceDimension + i_C + 1] = 2 * (spaceDimension + i_C + 1); - rowIndices[(2 * (spaceDimension + i_C))] = i_C; rowIndices[(2 * (spaceDimension + i_C)) + 1] = spaceDimension + i_C; - values[(2 * (spaceDimension + i_C))] = -2.0; values[(2 * (spaceDimension + i_C)) + 1] = 2.0; + columnPointers[dimension + i_C + 1] = 2 * (dimension + i_C + 1); + rowIndices[(2 * (dimension + i_C))] = i_C; rowIndices[(2 * (dimension + i_C)) + 1] = dimension + i_C; + values[(2 * (dimension + i_C))] = -2.0; values[(2 * (dimension + i_C)) + 1] = 2.0; } - columnPointers[(2 * spaceDimension) + 1] = (4 * spaceDimension) + 1; - rowIndices[(4 * spaceDimension)] = (2 * spaceDimension); - values[(4 * spaceDimension)] = -2.0; + columnPointers[(2 * dimension) + 1] = (4 * dimension) + 1; + rowIndices[(4 * dimension)] = (2 * dimension); + values[(4 * dimension)] = -2.0; - LocalHi = new CompressedColumn((2 * spaceDimension) + 1, (2 * spaceDimension) + 1, columnPointers, rowIndices, values); + LocalHi = new CompressedColumn((2 * dimension) + 1, (2 * dimension) + 1, columnPointers, rowIndices, values); - /******************** Define LocalBi ********************/ + // ----- Define LocalBi ----- // LocalBi = null ; - /******************** Define Ci ********************/ - Ci = 0.0; + // ----- Define Ci ----- // + + Ci = 0d; } #endregion diff --git a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/LowerBound.cs b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/LowerBound.cs index bc5f09f..52079ac 100644 --- a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/LowerBound.cs +++ b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/LowerBound.cs @@ -2,63 +2,54 @@ using System.Collections.Generic; using BRIDGES.LinearAlgebra.Vectors; -using BRIDGES.LinearAlgebra.Matrices; using BRIDGES.LinearAlgebra.Matrices.Sparse; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection.QuadraticConstraintTypes { /// - /// Constraint enforcing a value variable l to be higher than a lower bound σ using a dummy value variable λ. + /// Constraint enforcing a scalar variable to be larger than a fixed lower bound. The list of variables of this constraint consists in: + /// + /// + /// S + /// Scalar variable to maintain above the fixed lower bound. + /// + /// + /// X + /// Dummy scalar variable used for the constraint formulation. + /// + /// /// - /// The vector xReduced = [l, λ], and Ci = σ. - public class LowerBound : IQuadraticConstraintType + public class LowerBound : ConstraintType { - #region Properties - - /// - public SparseMatrix LocalHi { get; } - - /// - public SparseVector LocalBi { get; } - - /// - public double Ci { get; } - - #endregion - #region Constructors /// /// Initialises a new instance of the class. /// - /// Value of the lower bound of the constraint. - public LowerBound(double lowerBound) + /// Value of the lower bound. + public LowerBound(double bound) { - /******************** Define LocalHi ********************/ + // ----- Define LocalHi ----- // - int[] columnPointers = new int[3]; - int[] rowIndices = new int[1]; - double[] values = new double[1]; - - columnPointers[0] = 0; - columnPointers[1] = 0; - columnPointers[2] = 1; rowIndices[0] = 1; values[0] = 2.0; + int[] columnPointers = new int[] { 0, 0, 1 }; + int[] rowIndices = new int[] { 1 }; + double[] values = new double[] { 2d }; LocalHi = new CompressedColumn(2, 2, columnPointers, rowIndices, values); - /******************** Define LocalBi ********************/ + // ----- Define LocalBi ----- // - Dictionary components = new Dictionary(); - components.Add(0, -1.0); + Dictionary components = new Dictionary { { 0, -1.0 } }; LocalBi = new SparseVector(2, ref components); - /******************** Define Ci ********************/ - Ci = lowerBound; + // ----- Define Ci ----- // + + Ci = bound; } #endregion diff --git a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/UpperBound.cs b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/UpperBound.cs index 60ef475..e9b05cb 100644 --- a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/UpperBound.cs +++ b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/UpperBound.cs @@ -2,63 +2,54 @@ using System.Collections.Generic; using BRIDGES.LinearAlgebra.Vectors; -using BRIDGES.LinearAlgebra.Matrices; using BRIDGES.LinearAlgebra.Matrices.Sparse; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection.QuadraticConstraintTypes { /// - /// Constraint enforcing a value variable l to be lower than an upper bound σ using a dummy value variable λ. + /// Constraint enforcing a scalar variable to be smaller than a fixed upper bound. The list of variables of this constraint consists in: + /// + /// + /// S + /// Scalar variable to maintain under the fixed upper bound. + /// + /// + /// X + /// Dummy scalar variable used for the constraint formulation. + /// + /// /// - /// The vector xReduced = [l, λ], and Ci = σ. - public class UpperBound : IQuadraticConstraintType + public class UpperBound : ConstraintType { - #region Properties - - /// - public SparseMatrix LocalHi { get; } - - /// - public SparseVector LocalBi { get; } - - /// - public double Ci { get; } - - #endregion - #region Constructors /// /// Initialises a new instance of the class. /// - /// Value of the upper bound of the constraint. - public UpperBound(double upperBound) + /// Value of the upper bound. + public UpperBound(double bound) { - /******************** Define LocalHi ********************/ + // ----- Define LocalHi ----- // - int[] columnPointers = new int[3]; - int[] rowIndices = new int[1]; - double[] values = new double[1]; - - columnPointers[0] = 0; - columnPointers[1] = 0; - columnPointers[2] = 1; rowIndices[0] = 1; values[0] = -2.0; + int[] columnPointers = new int[3] { 0, 0, 1 }; + int[] rowIndices = new int[1] { 1 }; + double[] values = new double[1] { -2d }; LocalHi = new CompressedColumn(2, 2, columnPointers, rowIndices, values); - /******************** Define LocalBi ********************/ + // ----- Define LocalBi ----- // - Dictionary components = new Dictionary(); - components.Add(0, -1.0); + Dictionary components = new Dictionary { { 0, -1.0 } }; LocalBi = new SparseVector(2, ref components); - /******************** Define Ci ********************/ - Ci = upperBound; + // ----- Define Ci ----- // + + Ci = bound; } #endregion diff --git a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/VectorLength.cs b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/VectorLength.cs index f4a1504..e76ac69 100644 --- a/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/VectorLength.cs +++ b/BRIDGES/Solvers/GuidedProjection/QuadraticConstraintTypes/VectorLength.cs @@ -1,66 +1,56 @@ using System; -using System.Collections.Generic; -using BRIDGES.LinearAlgebra.Matrices; + using BRIDGES.LinearAlgebra.Matrices.Sparse; -using BRIDGES.LinearAlgebra.Matrices.Storage; -using BRIDGES.LinearAlgebra.Vectors; -using BRIDGES.Solvers.GuidedProjection.Interfaces; +using BRIDGES.Solvers.GuidedProjection.Abstracts; namespace BRIDGES.Solvers.GuidedProjection.QuadraticConstraintTypes { /// - /// Constraint enforcing a vector variable v to have a given length l (computed with euclidean norm). + /// Constraint enforcing a vector variable to equal a fixed target length (computed with euclidean norm). The list of variables of this constraint consists in: + /// + /// + /// V + /// Variable representing the vector to resize. + /// + /// /// - /// The vector xReduced = [v], and Ci = l2. - public class VectorLength : IQuadraticConstraintType + public class VectorLength : ConstraintType { - #region Properties - - /// - public SparseMatrix LocalHi { get; } - - /// - public SparseVector LocalBi { get; } - - /// - public double Ci { get; } - - #endregion - #region Constructors /// /// Initialises a new instance of the class. /// - /// Target length for the vector. - /// Dimension of the space containing the vector. - public VectorLength(double targetLength, int spaceDimension = 3) + /// Target length of the vector. + /// Dimension of the vector variable. + public VectorLength(double length, int dimension = 3) { - /******************** Define LocalHi ********************/ + // ----- Define LocalHi ********************/ - int[] columnPointers = new int[spaceDimension + 1]; - int[] rowIndices = new int[spaceDimension]; - double[] values = new double[spaceDimension]; + int[] columnPointers = new int[dimension + 1]; + int[] rowIndices = new int[dimension]; + double[] values = new double[dimension]; columnPointers[0] = 0; - for (int i = 0; i < spaceDimension; i++) + for (int i = 0; i < dimension; i++) { columnPointers[i + 1] = i + 1; rowIndices[i] = i; values[i] = -2.0; } - LocalHi = new CompressedColumn(spaceDimension, spaceDimension, columnPointers, rowIndices, values); + LocalHi = new CompressedColumn(dimension, dimension, columnPointers, rowIndices, values); - /******************** Define LocalBi ********************/ + // ----- Define LocalBi ----- // LocalBi = null; - /******************** Define Ci ********************/ - Ci = targetLength * targetLength; + // ----- Define Ci ----- // + + Ci = length * length; } #endregion diff --git a/BRIDGES/Solvers/GuidedProjection/Variable.cs b/BRIDGES/Solvers/GuidedProjection/Variable.cs new file mode 100644 index 0000000..2c4e74f --- /dev/null +++ b/BRIDGES/Solvers/GuidedProjection/Variable.cs @@ -0,0 +1,145 @@ +using System; + + +namespace BRIDGES.Solvers.GuidedProjection +{ + /// + /// Variable of the . + /// + public sealed class Variable : IEquatable + { + #region Fields + + /// + /// Segment of the global vector X representing this variable. + /// + private ArraySegment _components; + + #endregion + + #region Properties + + /// + /// Gets the component at the specified index in this variable. + /// + /// The zero-based index of the variable's component to get. + /// The component at the specified index. + public double this[int index] + { + get + { + return index < _components.Count ? _components.Array[_components.Offset + index] : + throw new IndexOutOfRangeException("The index must be positive and smaller than the dimmension of the variable."); + } + } + + /// + /// Get the number of components of this variable. + /// + public int Dimension => _components.Count; + + + /// + /// Gets the index of the variable's first component, relative to the start of the global vector X. + /// + internal int Offset => _components.Offset; + + #endregion + + #region Constructors + + /// + /// Initialises a new instance of the class from its components. + /// + /// Components of the variable. + public Variable(params double[] components) + { + if (components is null) { throw new ArgumentNullException(nameof(components)); } + if (components.Length == 0) { throw new RankException("The variable must be initialised with at least one component value."); } + + double[] array = (double[])components.Clone(); + + _components = new ArraySegment(array); + } + + #endregion + + #region Methods + + /// + /// Creates an array representation of the variable. + /// + /// The double-precision array representing the variable. + public double[] ToArray() + { + double[] array = new double[Dimension]; + for (int i = 0; i < Dimension; i++) + { + array[i] = this[i]; + } + + return array; + } + + + /// + /// Creates a representation of the variable + /// + /// The representation of the variable. + public Span ToSpan() + { + return new Span(_components.Array, _components.Offset, _components.Count); + } + + /// + /// Creates a representation of the variable + /// + /// Zero-based index of the first component to include in the . + /// Number of components to include in the . + /// The representation of the variable. + public Span ToSpan(int start, int count) + { + return new Span(_components.Array, _components.Offset + start, count); + } + + + /// + /// Changes the reference of this variable. + /// + /// Interfering with the variable's reference can create issues with the solving. + /// New array to refer to. + /// Index of the variable's first component in the array. + internal void ChangeReference(double[] array, int offset) + { + _components = new ArraySegment(array, offset, Dimension); + } + + + // ---------- Implement IEquatable<.> ---------- // + + /// + /// Indicates whether this is equal to another . + /// A to compare with this one. + /// if their field are equal, otherwise. + public bool Equals(Variable other) => _components.Equals(other._components); + + #endregion + + + #region Override : Object + + /// + public override bool Equals(object obj) + { + return obj is Variable variable && Equals(variable); + } + + /// + public override int GetHashCode() + { + return 1716805434 + _components.GetHashCode(); + } + + #endregion + } +} diff --git a/BRIDGES/Solvers/GuidedProjection/VariableSet.cs b/BRIDGES/Solvers/GuidedProjection/VariableSet.cs deleted file mode 100644 index a1a8b3d..0000000 --- a/BRIDGES/Solvers/GuidedProjection/VariableSet.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; - - -namespace BRIDGES.Solvers.GuidedProjection -{ - /// - /// Class defining a set of variables with the same dimension (i.e. variables with the same number of components). - /// - public class VariableSet - { - #region Fields - - /// - /// List of variables of the set. - /// - private List _variables; - - #endregion - - #region Properties - - /// - /// Gets the index of the set in the 's list of variable sets. - /// - public int SetIndex { get; private set; } - - /// - /// Gets the common dimension of variables in the set. - /// - public int VariableDimension { get; private set; } - - /// - /// Gets the number of variables in the set. - /// - public int VariableCount { get; private set; } - - - /// - /// Gets the rank of the first component of the first variable in the set. - /// - internal int FirstRank { get; private set; } - - #endregion - - #region Constructors - - /// - /// Initializes a new instance of the class. - /// - /// Index of the set in the 's list of variable sets. - /// Rank of the first component of the first variable in the set. - /// Dimension of the variables in the set. - internal VariableSet(int setIndex, int firstRank, int variableDimension) - { - // Instanciate Fields - _variables = new List(); - - // Initialise Properties - FirstRank = firstRank; - - SetIndex = setIndex; - VariableCount = 0; - VariableDimension = variableDimension; - } - - /// - /// Initializes a new instance of the class. - /// - /// Index of the set in the 's list of VariableSet. - /// Index of the first component of the first variable in the set. - /// Dimension of the variables contained in the set. - /// Indicative capacity of the set. - internal VariableSet(int setIndex, int firstRank, int variableDimension, int setCapacity) - { - // Instanciate Fields - _variables = new List(variableDimension * setCapacity); - - // Initialise Properties - FirstRank = firstRank; - - SetIndex = setIndex; - VariableCount = 0; - VariableDimension = variableDimension; - } - - #endregion - - #region Methods - - /// - /// Returns the component at the given index in the set. - /// - /// Index of the component to get. - /// The component at the given index in the set. - internal double GetComponent(int componentIndex) - { - return _variables[componentIndex]; - } - - /// - /// Sets the component at the given index in the set. - /// - /// Index of the component to set. - /// Value to set. - internal void SetComponent(int componentIndex, double value) - { - _variables[componentIndex] = value; - } - - - /// - /// Adds a variable to the set. - /// - /// Components of the variables to add. - public void AddVariable(params double[] components) - { - if (components.Length != VariableDimension) - { - throw new ArgumentOutOfRangeException("The number of components for the new variable" + - "does not match the expected dimension of the variables of the set."); - } - - _variables.AddRange(components); - VariableCount++; - } - - /// - /// Returns the components of the variable at the given index. - /// - /// Index of the variable to get. - /// The components of the variable at the index. - public double[] GetVariable(int variableIndex) - { - double[] variable = new double[VariableDimension]; - int index = variableIndex * VariableDimension; - for (int i = 0; i < VariableDimension; i++) - { - variable[i] = _variables[index + i]; - } - return variable; - } - - #endregion - } -}