/// <summary> /// Generate a random QGraph using the given info /// </summary> /// <param name="possibleStates">Possible states.</param> /// <param name="possibleActions">Possible actions.</param> /// <param name="default_float_mult">Default float mult.</param> /// <param name="default_restriction_range">Default restriction range.</param> /// <param name="stateConstraints">State constraints.</param> /// <param name="actionConstraints">Action constraints.</param> /// <param name="edgeMutationChance">Edge mutation chance.</param> /// <param name="actionMutationChance">Action mutation chance.</param> /// <param name="addNodeChance">Add node chance.</param> /// <param name="changeInterruptWeightChance">Change interrupt weight chance.</param> /// <param name="numNodesToConnectToNewNode">Number nodes to connect to new node.</param> /// <param name="numNodesToConnectNewNodeTo">Number nodes to connect new node to.</param> /// <param name="comparison_ops">Comparison ops.</param> /// <param name="windowSize">Window size.</param> /// <param name="timeCostDiscount">Time cost discount.</param> public QGraph(IEnumerable <string> possibleStates, IEnumerable <string> possibleActions, IEnumerable <float> default_float_mult, IEnumerable <FloatRange> default_restriction_range, IEnumerable <SAConstraint> stateConstraints, IEnumerable <SAConstraint> actionConstraints, float edgeMutationChance, float actionMutationChance, float addNodeChance, float changeInterruptWeightChance, float numNodesToConnectToNewNode, float numNodesToConnectNewNodeTo, IEnumerable <ComparisonOperator> comparison_ops, int windowSize, float timeCostDiscount) { this.stateConstraints = new ConstraintMapping(stateConstraints.ToList()); this.actionConstraints = new ConstraintMapping(actionConstraints.ToList()); this.comparison_operators = comparison_ops.ToList(); this.timeCostDiscount = timeCostDiscount; ID = numGraphs; ++numGraphs; root = new QGraphNode(); nodes.Add(root); currentNode = root; string[] states = possibleStates.ToArray(); string[] actions = possibleActions.ToArray(); this.possibleStates = new List <string> (states); this.possibleActions = new List <string> (actions); this.float_mult = new List <float> (default_float_mult.ToArray()); this.float_restriction_range = new List <FloatRange> (default_restriction_range.ToArray()); this.edgeMutationChance = edgeMutationChance; this.actionMutationChance = actionMutationChance; this.addNodeChance = addNodeChance; this.changeInterruptWeightChance = changeInterruptWeightChance; this.numNodesToConnectToNewNode = numNodesToConnectToNewNode; this.numNodesToConnectNewNodeTo = numNodesToConnectNewNodeTo; Debug.Assert(float_restriction_range.Count == float_restriction_range.Count); this.possibleStates = Utils.ShuffleList(this.possibleStates); this.possibleActions = Utils.ShuffleList(this.possibleActions); int s_c = states.Count(); int a_c = actions.Count(); //Debug.Assert (s_c > 0); Debug.Assert(a_c > 0); for (int i = 0; i < a_c; ++i) { QGraphNode tempNode = new QGraphNode(actions [i]); nodes.Add(tempNode); } //randomly plug root node into other nodes for (int i = 1; i < a_c + 1; ++i) { QGraphEdge temp_edge = new QGraphEdge(i); if (s_c > 0) { temp_edge.RequiredStates = new List <string> { states [i % s_c] }; } temp_edge.Float_restrictions = new List <float> (float_restriction_range.Count); for (int j = 0; j < float_restriction_range.Count; ++j) { temp_edge.Float_restrictions.Add(UnityEngine.Random.Range(float_restriction_range [j].min, float_restriction_range [j].max)); //temp_edge.Float_restrictions [j] = (UnityEngine.Random.Range (float_restriction_range, 1f)); //temp_edge.Float_restrictions [j] = Mathf.ac } temp_edge.Float_mult = new List <float> (default_float_mult.ToArray()); temp_edge.Comparison_operators = new List <ComparisonOperator> (this.comparison_operators); root.AddEdge(temp_edge); } states = Utils.ShuffleArray(states); int stateIndex = -1; for (int i = 1; i < a_c + 1; ++i) { for (int j = 1; j < a_c + 1; ++j) { if (i == j) { continue; } ++stateIndex; if (stateIndex > s_c) { stateIndex = 0; states = Utils.ShuffleArray(states); } QGraphEdge temp_edge = new QGraphEdge(j); if (s_c > 0) { temp_edge.RequiredStates = new List <string> { states [stateIndex] }; } temp_edge.Float_restrictions = new List <float> (float_restriction_range.Count); for (int k = 0; k < float_restriction_range.Count; ++k) { temp_edge.Float_restrictions.Add(UnityEngine.Random.Range(float_restriction_range [k].min, float_restriction_range [k].max)); } temp_edge.Float_mult = new List <float> (default_float_mult.ToArray()); temp_edge.Comparison_operators = new List <ComparisonOperator> (this.comparison_operators); nodes [i].AddEdge(temp_edge); } } //init window this.windowSize = windowSize; memoryWindow = new List <QGraphNode> (this.windowSize); memoryWindow.Add(currentNode); }
static QGraph SmartMutateQGraph(QGraph graph) { QGraph mutant = new QGraph(ref graph); mutant.edgeMutationChance += mutant.mutationIncrement * (0.5f - UnityEngine.Random.value); mutant.actionMutationChance += mutant.mutationIncrement * (0.5f - UnityEngine.Random.value); mutant.addNodeChance += mutant.mutationIncrement * (0.5f - UnityEngine.Random.value); mutant.changeInterruptWeightChance += mutant.mutationIncrement * (0.5f - UnityEngine.Random.value); // float mutationIncrement = 0.001f; // // float edgeMutationChance = 0.1f; // float actionMutationChance = 0.1f; // float addNodeChance = 0.8f; // float changeInterruptWeightChance = 0.01f; //mutate edges List <QGraphNode> t_nodes = new List <QGraphNode> (mutant.nodes); float n_c = t_nodes.Count; float numChanges = n_c; t_nodes = Utils.ShuffleList <QGraphNode> (t_nodes); float max_delta_reward = 0; float min_delta_reward = 0; //calculate max and min change in reward between two nodes for (int i = 0; i < n_c; ++i) { for (int j = 0; j < mutant.nodes [i].outgoingEdges.Count; ++j) { float delta = (mutant.nodes [mutant.nodes [i].outgoingEdges [j].targetNode].Reward - mutant.nodes [i].Reward); if (max_delta_reward < delta) { max_delta_reward = delta; } if (min_delta_reward > delta) { min_delta_reward = delta; } } } for (int i = 0; i < numChanges; ++i) { for (int j = 0; j < mutant.nodes [i].outgoingEdges.Count; ++j) { float mutationChance = (mutant.nodes [mutant.nodes [i].outgoingEdges [j].targetNode].Reward - mutant.nodes [i].Reward) / (max_delta_reward - min_delta_reward); if (UnityEngine.Random.value > mutationChance * 0.8f) { mutant.nodes [i].outgoingEdges [j] = QGraphEdge.MutateEdge(mutant.nodes [i].outgoingEdges [j], mutant.possibleStates, mutant.mutationIncrement, mutant.stateConstraints); } } } //mutate nodes //numChanges = mutant.nodes.Count * mutant.actionMutationChance; t_nodes = Utils.ShuffleList <QGraphNode> (t_nodes); for (int i = 0; i < numChanges; ++i) { int nodeToChange = UnityEngine.Random.Range(0, t_nodes.Count); t_nodes [nodeToChange] = QGraphNode.MutateNode(t_nodes [nodeToChange], mutant.possibleActions, mutant.actionConstraints); } //add nodes numChanges = mutant.nodes.Count * mutant.addNodeChance; t_nodes = Utils.ShuffleList <QGraphNode> (t_nodes); if (numChanges < 1) { numChanges = 1f; } for (int i = 0; i < numChanges; ++i) { QGraphNode newNode = new QGraphNode(t_nodes [UnityEngine.Random.Range(0, t_nodes.Count - 1)]); newNode = QGraphNode.MutateNode(newNode, mutant.possibleActions, mutant.actionConstraints); int numNodesToConnectTo = (int)(n_c * mutant.numNodesToConnectToNewNode); if (numNodesToConnectTo < 1) { numNodesToConnectTo = 1; } List <QGraphNode> nodesToRandomlyConnectToTemp = new List <QGraphNode> (mutant.nodes); nodesToRandomlyConnectToTemp = Utils.ShuffleList(nodesToRandomlyConnectToTemp); //connect nodes to the new node for (int j = 0; j < numNodesToConnectTo; ++j) { QGraphEdge temp_edge = new QGraphEdge(mutant.nodes.Count); if (mutant.possibleStates.Count > 0) { temp_edge.RequiredStates = new List <string> { mutant.possibleStates [j % mutant.possibleStates.Count] }; } temp_edge.Float_restrictions = new List <float> (mutant.float_restriction_range.Count); for (int k = 0; k < temp_edge.Float_restrictions.Count; ++k) { temp_edge.Float_restrictions.Add(UnityEngine.Random.Range(mutant.float_restriction_range [k].min, mutant.float_restriction_range [k].max)); } temp_edge.Float_mult = new List <float> (mutant.float_mult); temp_edge.Comparison_operators = new List <ComparisonOperator> (mutant.comparison_operators); nodesToRandomlyConnectToTemp [j].AddEdge(temp_edge); } numNodesToConnectTo = (int)(n_c * mutant.numNodesToConnectNewNodeTo); if (numNodesToConnectTo < 1) { numNodesToConnectTo = 1; } //connect the new node to other nodes; nodesToRandomlyConnectToTemp = Utils.ShuffleList(nodesToRandomlyConnectToTemp); for (int j = 0; j < numNodesToConnectTo; ++j) { QGraphEdge temp_edge = new QGraphEdge(mutant.nodes.IndexOf(nodesToRandomlyConnectToTemp [j])); if (mutant.possibleStates.Count > 0) { temp_edge.RequiredStates = new List <string> { mutant.possibleStates [j % mutant.possibleStates.Count] }; } temp_edge.Float_restrictions = new List <float> (mutant.float_restriction_range.Count); for (int k = 0; k < temp_edge.Float_restrictions.Count; ++k) { temp_edge.Float_restrictions.Add(UnityEngine.Random.Range(mutant.float_restriction_range [k].min, mutant.float_restriction_range [k].max)); } temp_edge.Float_mult = new List <float> (mutant.float_mult); temp_edge.Comparison_operators = new List <ComparisonOperator> (mutant.comparison_operators); newNode.AddEdge(temp_edge); } mutant.nodes.Add(newNode); } mutant.ResetCurrentNodeToRoot(); mutant.memoryWindow = new List <QGraphNode> (graph.memoryWindow.Count); mutant.windowSize = graph.windowSize; mutant.windowIndex = 0; mutant.memoryWindow.Add(mutant.currentNode); return(mutant); }