/// <summary> /// Gets the set of floating objects within a reaction radius from a given position. /// Only objects unused in this simulation step are considered. /// Only objects with no obstacle between them and the given position are considered. /// </summary> /// <param name="position">Position whose neighborhood is searched</param> /// <param name="targetMultiset">OPTIMIZATION: Objects are collected only until this multiset is reached</param> private FloatingObjectsSet GetNearObjects(Point3D position, NamedMultiset targetMultiset) { var missingObjects = new NamedMultiset(targetMultiset.ToDictionary()); var nearObjectsSet = new FloatingObjectsSet(); if (!missingObjects.Any()) { return(nearObjectsSet); } Vector3D radiusVector = new Vector3D(v_MSystem.Mobility, v_MSystem.Mobility, v_MSystem.Mobility); var gridKeys = KeysInBox(new Box3D(position - radiusVector, position + radiusVector)).ToList(); gridKeys.Shuffle(); // Random order of grid boxes where objects are sought for foreach (var key in gridKeys) { foreach (var fltObject in v_Grid[key].OldSet) { if (missingObjects.Contains(fltObject.Name) && fltObject.Position.DistanceTo(position) < fltObject.Type.Mobility && !v_tilesWorld.IntersectsWith(fltObject.Position, position, false)) { nearObjectsSet.Add(fltObject); missingObjects.Remove(fltObject.Name); if (!missingObjects.Any()) { return(nearObjectsSet); } } } } return(nearObjectsSet); }
/// <summary> /// Adds the multiset of floating objects at a given position. /// </summary> public void AddAt(NamedMultiset multiset, Point3D position) { foreach (var name in multiset) { Add(new FloatingObjectInWorld(v_MSystem.FloatingObjects[name], position), true); } }
/// <summary> /// Gets the set of floating objects within the reaction distance from any position of a given connector. /// Only objects unused in this simulation step are considered. /// TODO low priority: return floating objects close to the whole shape of the connector except endpoints /// </summary> public FloatingObjectsSet GetNearObjects(ConnectorOnTileInSpace connector, NamedMultiset targetMultiset) { FloatingObjectsSet objectsSet = new FloatingObjectsSet(); foreach (var position in connector.Positions) { objectsSet.UnionWith(GetNearObjects(connector.SidePoint(position), targetMultiset)); } return(objectsSet); }
/// <summary> /// Computes union of a sequence of multisets /// </summary> /// <param name="list"></param> public static NamedMultiset Union(IEnumerable <NamedMultiset> list) { var result = new NamedMultiset(); foreach (var element in list) { result.UnionWith(element); } return(result); }
/// <summary> /// Metabolic evolution rule constructor. /// </summary> /// <param name="priority">Priority of the evolution rule.</param> /// <param name="leftSideObjects">List of left side objects.</param> /// <param name="rightSideObjects">List of right side objects.</param> /// <param name="delay">Number of steps which must be done before rule is applied to tiles.</param> /// <exception cref="ArgumentException"> /// If format of the metabolic rule is invalid /// </exception> public EvoMetabolicRule(int priority, List <ISimulationObject> leftSideObjects, List <ISimulationObject> rightSideObjects, int delay) : base(RuleType.Metabolic, priority, leftSideObjects, rightSideObjects, delay) { string errorMessage = string.Format("{0}\n{1} ", "Invalid metabolic rule format:", this); // The rules must contain exactly one protein. try { RProtein = LeftSideObjects.OfType <Protein>().Single(); if (RProtein != RightSideObjects.OfType <Protein>().Single()) { throw new ArgumentException(errorMessage); } } catch (InvalidOperationException) { throw new ArgumentException(errorMessage); } // The objects before protein are "out" (must be on the outer side of 2D object). // The objects after protein are "in" (must be on the inner side of 2D object). MLeftOutNames = new NamedMultiset(LeftSideObjects.TakeWhile(obj => obj is FloatingObject)); MLeftInNames = new NamedMultiset(LeftSideObjects.SkipWhile(obj => obj is FloatingObject).OfType <FloatingObject>()); MRightOutNames = new NamedMultiset(RightSideObjects.TakeWhile(obj => obj is FloatingObject)); MRightInNames = new NamedMultiset(RightSideObjects.SkipWhile(obj => obj is FloatingObject).OfType <FloatingObject>()); // Both left and right-hand side of the rule must contain at least one floating object if (MLeftInNames.Count + MLeftOutNames.Count > 0 && MRightInNames.Count + MRightOutNames.Count > 0) { if (MLeftOutNames.Count + MRightOutNames.Count == 0 || MLeftInNames.Count + MRightInNames.Count == 0) { SubType = MetabolicRuleType.Catalyzed; } else if (MLeftInNames.Equals(MRightOutNames) && MLeftOutNames.Equals(MRightInNames)) { if (MLeftInNames.Count == 0 || MLeftOutNames.Count == 0) { SubType = MetabolicRuleType.Symport; } else { SubType = MetabolicRuleType.Antiport; } } } if (SubType == MetabolicRuleType.Undefined) { throw new ArgumentException(errorMessage); } }
/// <summary> /// Removes the multiset of names of floating objects from a given set of floating objects in space /// </summary> /// <param name="multiset">Multiset of floating object names to be removed</param> /// <param name="targetSet">Set of floating objects from which the multiset is removed - all must be of type "FloatingObjectsInWorld"</param> /// <exception cref="ArgumentNullException">If the set contains object which is not "FloatingObjectsInWorld"</exception> /// <exception cref="ArgumentException">If the multiset could not be removed</exception> public void RemoveFrom(NamedMultiset multiset, FloatingObjectsSet targetSet) { // Deep copy of the original multiset NamedMultiset myMultiset = new NamedMultiset(multiset.ToDictionary()); foreach (var fltObject in targetSet) { if (myMultiset.Remove(fltObject.Name)) { Remove(fltObject as FloatingObjectInWorld); } } if (myMultiset.Count > 0) { throw new ArgumentException($"{myMultiset} could not be removed from the world!"); } }
/// <summary> /// Non-metabolic evolution rule constructor. /// </summary> /// <param name="type">Type of the evolution rule.</param> /// <param name="priority">Priority of the evolution rule.</param> /// <param name="leftSideObjects">List of left side objects.</param> /// <param name="rightSideObjects">List of right side objects.</param> /// <param name="delay">Number of steps which must be done before rule is applied to tiles.</param> /// <exception cref="ArgumentException"> /// If format of the non-metabolic rule is invalid /// </exception> public EvoNonMetabolicRule(RuleType type, int priority, List <ISimulationObject> leftSideObjects, List <ISimulationObject> rightSideObjects, int delay) : base(type, priority, leftSideObjects, rightSideObjects, delay) { string errorMessage = $"{"Invalid rule format:"}\n{this} "; bool correct = false; switch (type) { case RuleType.Create: case RuleType.Insert: correct = //leftSideObjects.Count >= 1 && leftSideObjects.TrueForAll(obj => obj is FloatingObject) && rightSideObjects.SingleOrDefault() is Tile; break; case RuleType.Destroy: correct = leftSideObjects.Count >= 2 && leftSideObjects.OfType <Tile>().Count() == 1 && leftSideObjects.TrueForAll(obj => obj is FloatingObject || obj is Tile) && rightSideObjects.TrueForAll(obj => obj is FloatingObject); break; case RuleType.Divide: correct = leftSideObjects.Count >= 3 && leftSideObjects.OfType <Glue>().Count() == 2 && leftSideObjects.TrueForAll(obj => obj is FloatingObject || obj is Glue) && rightSideObjects.Count() == 2 && rightSideObjects[0] == leftSideObjects.OfType <Glue>().First() && rightSideObjects[1] == leftSideObjects.OfType <Glue>().Last(); break; } if (!correct) { throw new ArgumentException(errorMessage); } MLeftSideFloatingNames = new NamedMultiset(LeftSideObjects.OfType <FloatingObject>()); MRightSideFloatingNames = new NamedMultiset(RightSideObjects.OfType <FloatingObject>()); }
/// <summary> /// Gets the set of floating objects within a reaction distance from a given position on a tile. /// Only objects unused in this simulation step are considered. /// If the tile is 2D, only floating objects on the inner/outer side are returned as specified by the parameter "isInside" /// Otherwise the parameter "isInside" is ignored. /// </summary> public FloatingObjectsSet GetNearObjects(ProteinOnTileInSpace protein, Tile.SideType side, NamedMultiset targetMultiset) { return(GetNearObjects(protein.m_tile.SidePoint(protein.Position, side), targetMultiset)); }
/// <summary> /// Gets the set of floating objects within a reaction distance from the center of a tile. /// Only objects unused in this simulation step are considered. /// TODO low priority: return floating objects close to the whole shape of the tile except border /// </summary> public FloatingObjectsSet GetNearObjects(TileInSpace tile, NamedMultiset targetMultiset) { return(GetNearObjects(tile.Position, targetMultiset)); }