/// <summary> /// Gets a new Decision Vector where continuous elements have potentially been mutated. /// Uses <see cref="IVariable"/> to wrap the added number, ensuring a valid Decision Vector is always created. /// </summary> /// <param name="decisionVector">The existing Decision Vector.</param> /// <returns>A new Decision Vector.</returns> /// <exception cref="ArgumentException">Thrown when Decision Vector is zero length or has no <seealso cref="VariableContinuous"/> elements.</exception> public DecisionVector Operate(DecisionVector decisionVector) { var oldVectorContinuousElements = decisionVector.GetContinuousElements(); if (oldVectorContinuousElements.Count == 0) { throw new ArgumentException("Decision Vector must have continuous elements", nameof(decisionVector)); } var locationsToMutate = rngManager.GetLocations( oldVectorContinuousElements.Count, maximumNumberOfMutations, true, mutationProbability); var newDv = new object[decisionVector.Count]; var newDs = decisionVector.GetDecisionSpace(); var offset = 0; for (var i = 0; i < decisionVector.Count; i++) { newDv[i] = decisionVector.ElementAt(i); // If variable is not continuous, just copy if (newDs.ElementAt(i).GetType() != typeof(VariableContinuous)) { offset++; continue; } // Variable is continuous - it may be mutated multiple times. var numTimesToMutate = locationsToMutate.Count(l => l == (i - offset)); for (var j = 0; j < numTimesToMutate; j++) { var mutationLocation = rngManager.Rng.Next(0, numberSet.Length); newDv[i] = newDs.ElementAt(i).AddOrWrap(newDv[i], numberSet[mutationLocation]); } } return(DecisionVector.CreateFromArray(newDs, newDv)); }