Beispiel #1
0
        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));
        }
Beispiel #2
0
        //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);
        }