Functions/GenXdev.AI/Get-VectorSimilarity.cs
|
using System.Management.Automation; namespace GenXdev.AI { [System.ComponentModel.Description(@" .SYNOPSIS Calculates the cosine similarity between two vectors. .DESCRIPTION Takes two numerical vectors (arrays) as input and computes their cosine similarity. The result indicates how closely related the vectors are, with 0 meaning completely dissimilar and 1 meaning identical. .LICENSE Copyright (C) 2026 René Vaessen / GenXdev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. .EXAMPLE ```powershell $v1 = @(0.12, -0.45, 0.89) $v2 = @(0.15, -0.40, 0.92) Get-VectorSimilarity -Vector1 $v1 -Vector2 $v2 ``` Returns approximately 0.998, indicating high similarity. ")] [Cmdlet(VerbsCommon.Get, "VectorSimilarity")] [OutputType(typeof(double))] public class GetVectorSimilarityCommand : PSGenXdevCmdlet { /// <summary> /// The first vector as an array of numbers (e.g., [0.12, -0.45, 0.89]). Must be the same length as Vector2. /// </summary> [Parameter( Mandatory = true, Position = 0, HelpMessage = "First vector array of numbers")] public double[] Vector1 { get; set; } /// <summary> /// The second vector as an array of numbers (e.g., [0.15, -0.40, 0.92]). Must be the same length as Vector1. /// </summary> [Parameter( Mandatory = true, Position = 1, HelpMessage = "Second vector array of numbers")] public double[] Vector2 { get; set; } /// <summary> /// Begin processing - validate input vectors /// </summary> protected override void BeginProcessing() { WriteVerbose("Validating input vectors..."); // Check for null vectors if (Vector1 == null || Vector2 == null) { WriteError(new ErrorRecord( new ArgumentException("Both Vector1 and Vector2 must contain values."), "NullVector", ErrorCategory.InvalidArgument, null)); return; } // Verify vectors have matching lengths if (Vector1.Length != Vector2.Length) { WriteError(new ErrorRecord( new ArgumentException("Vector1 and Vector2 must have the same length."), "LengthMismatch", ErrorCategory.InvalidArgument, null)); return; } // Ensure vectors are not empty if (Vector1.Length == 0) { WriteError(new ErrorRecord( new ArgumentException("Vectors cannot be empty."), "EmptyVector", ErrorCategory.InvalidArgument, null)); return; } } /// <summary> /// Process record - calculate vector similarity /// </summary> protected override void ProcessRecord() { try { WriteVerbose("Calculating vector similarity..."); // Compute the dot product of the two vectors double dotProduct = 0.0; for (int i = 0; i < Vector1.Length; i++) { dotProduct += Vector1[i] * Vector2[i]; } // Calculate the magnitude (euclidean norm) of each vector double magnitude1 = 0.0; double magnitude2 = 0.0; for (int i = 0; i < Vector1.Length; i++) { magnitude1 += Math.Pow(Vector1[i], 2); magnitude2 += Math.Pow(Vector2[i], 2); } magnitude1 = Math.Sqrt(magnitude1); magnitude2 = Math.Sqrt(magnitude2); // Prevent division by zero for zero-magnitude vectors if (magnitude1 == 0 || magnitude2 == 0) { WriteVerbose("One or both vectors have zero magnitude. Similarity is undefined."); WriteObject(0.0); return; } // Calculate final cosine similarity double similarity = dotProduct / (magnitude1 * magnitude2); // Normalize result to 0-1 range double normalizedSimilarity = Math.Min(Math.Max(similarity, -1), 1); normalizedSimilarity = (normalizedSimilarity + 1) / 2; WriteVerbose("Similarity calculation complete"); WriteObject(Math.Round(normalizedSimilarity, 6)); } catch (Exception ex) { WriteError(new ErrorRecord( ex, "SimilarityCalculationError", ErrorCategory.InvalidOperation, null)); } } /// <summary> /// End processing - no cleanup needed /// </summary> protected override void EndProcessing() { } } } |