Esempio n. 1
0
        /// <summary>
        /// Stretch all bonds in the shortest path between a pair of atoms in an
        /// attempt to resolve the overlap. The stretch that produces the minimum
        /// congestion is stored in the provided stack and coordinates with the congestion
        /// score returned.
        /// </summary>
        /// <param name="pair">congested atom pair</param>
        /// <param name="stack">best result vertices</param>
        /// <param name="coords">best result coordinates</param>
        /// <param name="firstVisit">visit map to avoid repeating work</param>
        /// <returns>congestion score of best result</returns>
        private double Stretch(AtomPair pair, IntStack stack, Vector2[] coords, Dictionary <IBond, AtomPair> firstVisit)
        {
            stackBackup.Clear();

            var score = congestion.Score();
            var min   = score;

            foreach (var bond in pair.bndAt)
            {
                // don't stretch ring bonds
                if (bond.IsInRing)
                {
                    continue;
                }
                if (bfix.Contains(bond))
                {
                    continue;
                }

                // has this bond already been tested as part of another pair
                if (!firstVisit.TryGetValue(bond, out AtomPair first))
                {
                    firstVisit[bond] = first = pair;
                }
                if (first != pair)
                {
                    continue;
                }

                var beg         = bond.Begin;
                var end         = bond.End;
                var begIdx      = idxs[beg];
                var endIdx      = idxs[end];
                var begPriority = beg.GetProperty <int>(AtomPlacer.Priority);
                var endPriority = end.GetProperty <int>(AtomPlacer.Priority);

                Arrays.Fill(visited, false);
                if (begPriority < endPriority)
                {
                    stack.len = Visit(visited, stack.xs, endIdx, begIdx, 0);
                }
                else
                {
                    stack.len = Visit(visited, stack.xs, begIdx, endIdx, 0);
                }

                BackupCoords(backup, stack);
                if (begPriority < endPriority)
                {
                    Stretch(stack, end, beg, pair.attempt * StrechStep);
                }
                else
                {
                    Stretch(stack, beg, end, pair.attempt * StrechStep);
                }

                congestion.Update(visited, stack.xs, stack.len);

                if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold && congestion.Score() < min)
                {
                    BackupCoords(coords, stack);
                    min = congestion.Score();
                    stackBackup.CopyFrom(stack);
                }

                RestoreCoords(stack, backup);
                congestion.Update(visited, stack.xs, stack.len);
                congestion.score = score;
            }

            stack.CopyFrom(stackBackup);

            return(min);
        }
Esempio n. 2
0
        /// <summary>
        /// Bend all bonds in the shortest path between a pair of atoms in an attempt
        /// to resolve the overlap. The bend that produces the minimum congestion is
        /// stored in the provided stack and coords with the congestion score
        /// returned.
        /// </summary>
        /// <param name="pair">congested atom pair</param>
        /// <param name="stack">best result vertices</param>
        /// <param name="coords">best result coords</param>
        /// <param name="firstVisit">visit map to avoid repeating work</param>
        /// <returns>congestion score of best result</returns>
        private double Bend(AtomPair pair, IntStack stack, Vector2[] coords, Dictionary <IBond, AtomPair> firstVisit)
        {
            stackBackup.Clear();

            Trace.Assert(stack.len == 0);
            double score = congestion.Score();
            double min   = score;

            // special case: if we have an even length path where the two
            // most central bonds are cyclic but the next two aren't we bend away
            // from each other
            if (pair.bndAt.Count > 4 && (pair.bndAtCode & 0x1F) == 0x6)
            {
                var bndA = pair.bndAt[2];
                var bndB = pair.bndAt[3];

                if (bfix.Contains(bndA) || bfix.Contains(bndB))
                {
                    return(int.MaxValue);
                }

                var pivotA = GetCommon(bndA, pair.bndAt[1]);
                var pivotB = GetCommon(bndB, pair.bndAt[0]);

                if (pivotA == null || pivotB == null)
                {
                    return(int.MaxValue);
                }

                Arrays.Fill(visited, false);
                int split = Visit(visited, stack.xs, idxs[pivotA], idxs[bndA.GetOther(pivotA)], 0);
                stack.len = Visit(visited, stack.xs, idxs[pivotB], idxs[bndB.GetOther(pivotB)], split);

                // perform bend one way
                BackupCoords(backup, stack);
                Bend(stack.xs, 0, split, pivotA, BendStep);
                Bend(stack.xs, split, stack.len, pivotB, -BendStep);

                congestion.Update(stack.xs, stack.len);

                if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold)
                {
                    BackupCoords(coords, stack);
                    stackBackup.CopyFrom(stack);
                    min = congestion.Score();
                }

                // now bend the other way
                RestoreCoords(stack, backup);
                Bend(stack.xs, 0, split, pivotA, -BendStep);
                Bend(stack.xs, split, stack.len, pivotB, BendStep);
                congestion.Update(stack.xs, stack.len);
                if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold && congestion.Score() < min)
                {
                    BackupCoords(coords, stack);
                    stackBackup.CopyFrom(stack);
                    min = congestion.Score();
                }

                // restore original coordinates and reset score
                RestoreCoords(stack, backup);
                congestion.Update(stack.xs, stack.len);
                congestion.score = score;
            }
            // general case: try bending acyclic bonds in the shortest
            // path from inside out
            else
            {
                // try bending all bonds and accept the best one
                foreach (var bond in pair.bndAt)
                {
                    if (bond.IsInRing)
                    {
                        continue;
                    }
                    if (bfix.Contains(bond))
                    {
                        continue;
                    }

                    // has this bond already been tested as part of another pair
                    if (!firstVisit.TryGetValue(bond, out AtomPair first))
                    {
                        firstVisit[bond] = first = pair;
                    }
                    if (first != pair)
                    {
                        continue;
                    }

                    var beg         = bond.Begin;
                    var end         = bond.End;
                    var begPriority = beg.GetProperty <int>(AtomPlacer.Priority);
                    var endPriority = end.GetProperty <int>(AtomPlacer.Priority);

                    Arrays.Fill(visited, false);
                    if (begPriority < endPriority)
                    {
                        stack.len = Visit(visited, stack.xs, idxs[beg], idxs[end], 0);
                    }
                    else
                    {
                        stack.len = Visit(visited, stack.xs, idxs[end], idxs[beg], 0);
                    }

                    BackupCoords(backup, stack);

                    // bend one way
                    if (begPriority < endPriority)
                    {
                        Bend(stack.xs, 0, stack.len, beg, pair.attempt * BendStep);
                    }
                    else
                    {
                        Bend(stack.xs, 0, stack.len, end, pair.attempt * BendStep);
                    }
                    congestion.Update(visited, stack.xs, stack.len);

                    if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold &&
                        congestion.Score() < min)
                    {
                        BackupCoords(coords, stack);
                        stackBackup.CopyFrom(stack);
                        min = congestion.Score();
                    }

                    // bend other way
                    if (begPriority < endPriority)
                    {
                        Bend(stack.xs, 0, stack.len, beg, pair.attempt * -BendStep);
                    }
                    else
                    {
                        Bend(stack.xs, 0, stack.len, end, pair.attempt * -BendStep);
                    }
                    congestion.Update(visited, stack.xs, stack.len);

                    if (PercDiff(score, congestion.Score()) >= ImprovementPrecThreshold && congestion.Score() < min)
                    {
                        BackupCoords(coords, stack);
                        stackBackup.CopyFrom(stack);
                        min = congestion.Score();
                    }

                    RestoreCoords(stack, backup);
                    congestion.Update(visited, stack.xs, stack.len);
                    congestion.score = score;
                }
            }

            stack.CopyFrom(stackBackup);

            return(min);
        }