public static MutateUtility.ShipMutateArgs BuildMutateArgs(FlyingBeanOptions options) { #region Neural MutateUtility.NeuronMutateArgs neuralArgs = null; if (options.MutateChangeNeural) { MutateUtility.MuateArgs neuronMovement = new MutateUtility.MuateArgs(false, options.NeuronPercentToMutate, null, null, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.NeuronMovementAmount)); // neurons are all point3D (positions need to drift around freely. percent doesn't make much sense) MutateUtility.MuateArgs linkMovement = new MutateUtility.MuateArgs(false, options.LinkPercentToMutate, new Tuple <string, MutateUtility.MuateFactorArgs>[] { Tuple.Create("FromContainerPosition", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkContainerMovementAmount)), Tuple.Create("FromContainerOrientation", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.LinkContainerRotateAmount)) }, new Tuple <PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { Tuple.Create(PropsByPercent.DataType.Double, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkWeightAmount)), // all the doubles are weights, which need to be able to cross over zero (percents can't go + to -) Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkMovementAmount)), // using a larger value for the links }, null); neuralArgs = new MutateUtility.NeuronMutateArgs(neuronMovement, null, linkMovement, null); } #endregion #region Body MutateUtility.MuateArgs bodyArgs = null; if (options.MutateChangeBody) { var mutate_Vector3D = Tuple.Create(PropsByPercent.DataType.Vector3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.BodySizeChangePercent)); var mutate_Point3D = Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.BodyMovementAmount)); // positions need to drift around freely. percent doesn't make much sense var mutate_Quaternion = Tuple.Create(PropsByPercent.DataType.Quaternion, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.BodyOrientationChangePercent)); //NOTE: The mutate class has special logic for Scale and ThrusterDirections bodyArgs = new MutateUtility.MuateArgs(true, options.BodyNumToMutate, null, new Tuple <PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { mutate_Vector3D, mutate_Point3D, mutate_Quaternion, }, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, .01d)); // this is just other (currently there aren't any others - just being safe) } #endregion return(new MutateUtility.ShipMutateArgs(null, bodyArgs, neuralArgs)); }
//TODO: Make a random version //private static FitnessTracker GetRandomRules(Bot bot = null) private static MutateUtility.NeuronMutateArgs GetMutateArgs(ItemOptionsArco options) { MutateUtility.NeuronMutateArgs retVal = null; MutateUtility.MuateArgs neuronMovement = new MutateUtility.MuateArgs(false, options.Neuron_PercentToMutate, null, null, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.Neuron_MovementAmount)); // neurons are all point3D (positions need to drift around freely. percent doesn't make much sense) MutateUtility.MuateArgs linkMovement = new MutateUtility.MuateArgs(false, options.Link_PercentToMutate, new Tuple <string, MutateUtility.MuateFactorArgs>[] { Tuple.Create("FromContainerPosition", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkContainer_MovementAmount)), Tuple.Create("FromContainerOrientation", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.LinkContainer_RotateAmount)) }, new Tuple <PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { Tuple.Create(PropsByPercent.DataType.Double, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.Link_WeightAmount)), // all the doubles are weights, which need to be able to cross over zero (percents can't go + to -) Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.Link_MovementAmount)), // using a larger value for the links }, null); retVal = new MutateUtility.NeuronMutateArgs(neuronMovement, null, linkMovement, null); return(retVal); }
private void btnMutate_Click(object sender, RoutedEventArgs e) { try { #region Extract dna ShipPartDNA[] gravDNA1 = null; if (_gravSensors != null) { gravDNA1 = _gravSensors.Select(o => o.Sensor.GetNewDNA()).ToArray(); // no need to call NeuralUtility.PopulateDNALinks, only the neurons are stored } ShipPartDNA[] brainDNA1 = null; if (_brains != null) { brainDNA1 = _brains.Select(o => { ShipPartDNA dna = o.Brain.GetNewDNA(); if (_links != null) { NeuralUtility.PopulateDNALinks(dna, o.Brain, _links.Outputs); } return dna; }).ToArray(); } ThrusterDNA[] thrustDNA1 = null; if (_thrusters != null) { thrustDNA1 = _thrusters.Select(o => { ThrusterDNA dna = (ThrusterDNA)o.Thrust.GetNewDNA(); if (_links != null) { NeuralUtility.PopulateDNALinks(dna, o.Thrust, _links.Outputs); } return dna; }).ToArray(); } ShipPartDNA energyDNA1 = null; ShipPartDNA fuelDNA1 = null; if (_containers != null) { energyDNA1 = _containers.Energy.GetNewDNA(); fuelDNA1 = _containers.Fuel.GetNewDNA(); } // Combine the lists List<ShipPartDNA> allParts1 = UtilityCore.Iterate<ShipPartDNA>(gravDNA1, brainDNA1, thrustDNA1).ToList(); if (allParts1.Count == 0) { // There is nothing to do return; } if (energyDNA1 != null) { allParts1.Add(energyDNA1); } if (fuelDNA1 != null) { allParts1.Add(fuelDNA1); } #endregion bool hadLinks = _links != null; // Clear existing ClearLinks(); ClearGravSensors(); ClearBrains(); ClearThrusters(); #region Fill in mutate args //TODO: Store these args in ShipDNA itself. That way, mutation rates are a property of ship //TODO: Fill in the params from ItemOptions //NOTE: These mutate factors are pretty large. Good for a unit tester, but not a real simulation var mutate_Vector3D = Tuple.Create(PropsByPercent.DataType.Vector3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, .08d)); var mutate_Point3D = Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, .04d)); // positions need to drift around freely. percent doesn't make much sense var mutate_Quaternion = Tuple.Create(PropsByPercent.DataType.Quaternion, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, .08d)); MutateUtility.ShipPartAddRemoveArgs addRemoveArgs = null; if (chkMutateAddRemoveParts.IsChecked.Value) { //addRemoveArgs = new MutateUtility.ShipPartAddRemoveArgs(); } MutateUtility.MuateArgs partChangeArgs = null; if (chkMutateChangeParts.IsChecked.Value) { //NOTE: The mutate class has special logic for Scale and ThrusterDirections partChangeArgs = new MutateUtility.MuateArgs(true, 1d, null, new Tuple<PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { mutate_Vector3D, mutate_Point3D, mutate_Quaternion, }, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, .1d)); } MutateUtility.NeuronMutateArgs neuralArgs = null; if (chkMutateChangeNeural.IsChecked.Value) { MutateUtility.MuateArgs neuronMovement = new MutateUtility.MuateArgs(false, .05d, null, null, mutate_Point3D.Item2); // neurons are all point3D MutateUtility.MuateArgs linkMovement = new MutateUtility.MuateArgs(false, .05d, null, new Tuple<PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { Tuple.Create(PropsByPercent.DataType.Double, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, .1d)), // all the doubles are weights, which need to be able to cross over zero (percents can't go + to -) Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, .2d)), // using a larger value for the links mutate_Quaternion, }, null); neuralArgs = new MutateUtility.NeuronMutateArgs(neuronMovement, null, linkMovement, null); } MutateUtility.ShipMutateArgs shipArgs = new MutateUtility.ShipMutateArgs(addRemoveArgs, partChangeArgs, neuralArgs); #endregion // Mutate ShipDNA oldDNA = ShipDNA.Create(allParts1); ShipDNA newDNA = MutateUtility.Mutate(oldDNA, shipArgs); if (chkMutateWriteToFile.IsChecked.Value) { #region Write to file string foldername = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); string timestamp = DateTime.Now.ToString("yyyyMMdd HHmmssfff"); string oldFilename = System.IO.Path.Combine(foldername, timestamp + " Old DNA.xml"); string newFilename = System.IO.Path.Combine(foldername, timestamp + " New DNA.xml"); using (System.IO.StreamWriter writer = new System.IO.StreamWriter(oldFilename, false)) { System.Xaml.XamlServices.Save(writer, oldDNA); } using (System.IO.StreamWriter writer = new System.IO.StreamWriter(newFilename, false)) { System.Xaml.XamlServices.Save(writer, newDNA); } #endregion } #region Rebuild Parts ShipPartDNA[] allParts2 = newDNA.PartsByLayer.SelectMany(o => o.Value).ToArray(); ShipPartDNA[] gravDNA2 = allParts2.Where(o => o.PartType == SensorGravity.PARTTYPE).ToArray(); if (gravDNA2.Length > 0) { CreateGravSensors(gravDNA2); } ShipPartDNA[] brainDNA2 = allParts2.Where(o => o.PartType == Brain.PARTTYPE).ToArray(); if (brainDNA2.Length > 0) { CreateBrains(brainDNA2); } ShipPartDNA fuelDNA2 = allParts2.Where(o => o.PartType == FuelTank.PARTTYPE).FirstOrDefault(); //NOTE: This is too simplistic if part remove/add is allowed in the mutator ThrusterDNA[] thrustDNA2 = allParts2.Where(o => o.PartType == Thruster.PARTTYPE).Select(o => (ThrusterDNA)o).ToArray(); if (thrustDNA2.Length > 0) { CreateThrusters(thrustDNA2); } #endregion // Relink if (hadLinks) { CreateLinks(); } } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
//TODO: Make a random version //private static FitnessTracker GetRandomRules(Bot bot = null) private static MutateUtility.NeuronMutateArgs GetMutateArgs(ItemOptionsArco options) { MutateUtility.NeuronMutateArgs retVal = null; MutateUtility.MuateArgs neuronMovement = new MutateUtility.MuateArgs(false, options.Neuron_PercentToMutate, null, null, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.Neuron_MovementAmount)); // neurons are all point3D (positions need to drift around freely. percent doesn't make much sense) MutateUtility.MuateArgs linkMovement = new MutateUtility.MuateArgs(false, options.Link_PercentToMutate, new Tuple<string, MutateUtility.MuateFactorArgs>[] { Tuple.Create("FromContainerPosition", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkContainer_MovementAmount)), Tuple.Create("FromContainerOrientation", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.LinkContainer_RotateAmount)) }, new Tuple<PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { Tuple.Create(PropsByPercent.DataType.Double, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.Link_WeightAmount)), // all the doubles are weights, which need to be able to cross over zero (percents can't go + to -) Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.Link_MovementAmount)), // using a larger value for the links }, null); retVal = new MutateUtility.NeuronMutateArgs(neuronMovement, null, linkMovement, null); return retVal; }
private const double MAXERROR = 100000000000; // need something excessively large, but less than double.max #endregion /// <summary> /// This is a wrapper of UtilityAI.DiscoverSolution /// </summary> public static void DiscoverSolutionAsync(Bot bot, Vector3D? idealLinear, Vector3D? idealRotation, CancellationToken? cancel = null, ThrustContributionModel model = null, Action<ThrusterMap> newBestFound = null, Action<ThrusterMap> finalFound = null, DiscoverSolutionOptions<Tuple<int, int, double>> options = null) { long token = bot.Token; // Cache Thrusters Thruster[] allThrusters = bot.Thrusters; if (allThrusters == null || allThrusters.Length == 0) { throw new ArgumentException("This bot has no thrusters"); } // Ensure model is created (if the caller wants to find solutions for several directions at the same time, it would be // more efficient to calculate the model once, and pass to all the solution finders) model = model ?? new ThrustContributionModel(bot.Thrusters, bot.PhysicsBody.CenterOfMass); // Figure out how much force can be generated in the ideal directions double maxForceLinear = idealLinear == null ? 0d : ThrustControlUtil.GetMaximumPossible_Linear(model, idealLinear.Value); double maxForceRotate = idealRotation == null ? 0d : ThrustControlUtil.GetMaximumPossible_Rotation(model, idealRotation.Value); // Mutate 2% of the elements, with a 10% value drift MutateUtility.MuateArgs mutateArgs = new MutateUtility.MuateArgs(false, .02, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, .1)); #region delegates //NOTE: While breeding/mutating, they don't get normalized. But error calculation and returned maps need them normalized var delegates = new DiscoverSolutionDelegates<Tuple<int, int, double>>() { GetNewSample = new Func<Tuple<int, int, double>[]>(() => { ThrusterMap map = ThrustControlUtil.GenerateRandomMap(allThrusters, token); return map.Flattened; }), GetError = new Func<Tuple<int, int, double>[], SolutionError>(o => { ThrusterMap map = new ThrusterMap(ThrustControlUtil.Normalize(o), allThrusters, token); return ThrustControlUtil.GetThrustMapScore(map, model, idealLinear, idealRotation, maxForceLinear, maxForceRotate); }), Mutate = new Func<Tuple<int, int, double>[], Tuple<int, int, double>[]>(o => { ThrusterMap map = new ThrusterMap(o, allThrusters, token); return ThrustControlUtil.Mutate(map, mutateArgs, false).Flattened; }), }; if (cancel != null) { delegates.Cancel = cancel.Value; } if (newBestFound != null) { delegates.NewBestFound = new Action<SolutionResult<Tuple<int, int, double>>>(o => { ThrusterMap map = new ThrusterMap(ThrustControlUtil.Normalize(o.Item), allThrusters, token); newBestFound(map); }); } if (finalFound != null) { delegates.FinalFound = new Action<SolutionResult<Tuple<int, int, double>>>(o => { ThrusterMap map = new ThrusterMap(ThrustControlUtil.Normalize(o.Item), allThrusters, token); finalFound(map); }); } #endregion // Do it //NOTE: If options.ThreadShare is set, then there's no reason to do this async, but there's no harm either Task.Run(() => UtilityAI.DiscoverSolution(delegates, options)); }
public static ThrusterMap Mutate(ThrusterMap map, bool shouldNormalize = true) { // Modify 2% of the properties // Each property should drift up to 10% each direction (the values get capped between 0 and 100%) MutateUtility.MuateArgs args = new MutateUtility.MuateArgs(false, .02, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, .1)); return Mutate(map, args); }
public static MutateUtility.ShipMutateArgs BuildMutateArgs(FlyingBeanOptions options) { #region Neural MutateUtility.NeuronMutateArgs neuralArgs = null; if (options.MutateChangeNeural) { MutateUtility.MuateArgs neuronMovement = new MutateUtility.MuateArgs(false, options.NeuronPercentToMutate, null, null, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.NeuronMovementAmount)); // neurons are all point3D (positions need to drift around freely. percent doesn't make much sense) MutateUtility.MuateArgs linkMovement = new MutateUtility.MuateArgs(false, options.LinkPercentToMutate, new Tuple<string, MutateUtility.MuateFactorArgs>[] { Tuple.Create("FromContainerPosition", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkContainerMovementAmount)), Tuple.Create("FromContainerOrientation", new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.LinkContainerRotateAmount)) }, new Tuple<PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { Tuple.Create(PropsByPercent.DataType.Double, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkWeightAmount)), // all the doubles are weights, which need to be able to cross over zero (percents can't go + to -) Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.LinkMovementAmount)), // using a larger value for the links }, null); neuralArgs = new MutateUtility.NeuronMutateArgs(neuronMovement, null, linkMovement, null); } #endregion #region Body MutateUtility.MuateArgs bodyArgs = null; if (options.MutateChangeBody) { var mutate_Vector3D = Tuple.Create(PropsByPercent.DataType.Vector3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.BodySizeChangePercent)); var mutate_Point3D = Tuple.Create(PropsByPercent.DataType.Point3D, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Distance, options.BodyMovementAmount)); // positions need to drift around freely. percent doesn't make much sense var mutate_Quaternion = Tuple.Create(PropsByPercent.DataType.Quaternion, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, options.BodyOrientationChangePercent)); //NOTE: The mutate class has special logic for Scale and ThrusterDirections bodyArgs = new MutateUtility.MuateArgs(true, options.BodyNumToMutate, null, new Tuple<PropsByPercent.DataType, MutateUtility.MuateFactorArgs>[] { mutate_Vector3D, mutate_Point3D, mutate_Quaternion, }, new MutateUtility.MuateFactorArgs(MutateUtility.FactorType.Percent, .01d)); // this is just other (currently there aren't any others - just being safe) } #endregion return new MutateUtility.ShipMutateArgs(null, bodyArgs, neuralArgs); }