Skip to content

Commit dc44773

Browse files
nbollisNic BollisAlexander-Sol
authored
IEquality hot fix hot fix (#819)
* Added parent accession check back to PeptideWithSetMods * Added Test * oopsies * Refactor Equals methods and add IEquatable regions Removed Equals from IBioPolymerWithSetMods interface in Omics. Updated Equals in PeptideWithSetModifications to check OneBasedStartResidue and Parent?.Accession. Updated Equals in OligoWithSetMods to check FullSequence and DigestionParams?.DigestionAgent. Added IEquatable regions to PeptideWithSetModifications and OligoWithSetMods. Organized Equals methods with #region IEquatable directives. * workflow edit * Even more equality tetsts * adjusted oligo with set mods * ugh --------- Co-authored-by: Nic Bollis <nbollis@wisc.edu> Co-authored-by: Alex <AlexSolivais@gmail.com>
1 parent 90bd259 commit dc44773

File tree

7 files changed

+131
-45
lines changed

7 files changed

+131
-45
lines changed

mzLib/Omics/IBioPolymerWithSetMods.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,6 @@ public interface IBioPolymerWithSetMods : IHasChemicalFormula, IEquatable<IBioPo
4444
char this[int zeroBasedIndex] => BaseSequence[zeroBasedIndex];
4545
IBioPolymer Parent { get; }
4646

47-
/// <summary>
48-
/// Default Equals Method for IBioPolymerWithSetMods
49-
/// </summary>
50-
/// <param name="other"></param>
51-
/// <returns></returns>
52-
/// <remarks>
53-
/// Different parent but same sequence and digestion condition => are equal
54-
/// Different Digestion agent but same sequence => are not equal (this is for multi-protease analysis in MetaMorpheus)
55-
/// </remarks>
56-
bool IEquatable<IBioPolymerWithSetMods>.Equals(IBioPolymerWithSetMods? other)
57-
{
58-
if (other is null) return false;
59-
if (ReferenceEquals(this, other)) return true;
60-
if (other.GetType() != GetType()) return false;
61-
62-
// for those constructed from sequence and mods only
63-
if (Parent is null && other.Parent is null)
64-
return FullSequence.Equals(other.FullSequence);
65-
66-
return FullSequence == other.FullSequence
67-
&& Equals(DigestionParams?.DigestionAgent, other.DigestionParams?.DigestionAgent);
68-
}
69-
7047
public void Fragment(DissociationType dissociationType, FragmentationTerminus fragmentationTerminus,
7148
List<Product> products);
7249

mzLib/Proteomics/ProteolyticDigestion/PeptideWithSetModifications.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Proteomics.ProteolyticDigestion
1616
[Serializable]
1717
public class PeptideWithSetModifications : ProteolyticPeptide, IBioPolymerWithSetMods, IEquatable<PeptideWithSetModifications>
1818
{
19-
public string FullSequence { get; private set; } //sequence with modifications
19+
public string FullSequence { get; init; } //sequence with modifications
2020
public int NumFixedMods { get; }
2121
// Parameter to store the full sequence of the corresponding Target or Decoy peptide
2222
// If the peptide in question is a decoy, this pairs it to the target it was generated from
@@ -884,6 +884,11 @@ public override string ToString()
884884
return FullSequence + string.Join("\t", AllModsOneIsNterminus.Select(m => m.ToString()));
885885
}
886886

887+
#region IEquatable
888+
889+
/// <summary>
890+
/// Peptides are equal if they have the same full sequence, parent, and digestion agent
891+
/// </summary>
887892
public override bool Equals(object obj)
888893
{
889894
if (obj is PeptideWithSetModifications peptide)
@@ -893,12 +898,29 @@ public override bool Equals(object obj)
893898
return false;
894899
}
895900

901+
/// <summary>
902+
/// Peptides are equal if they have the same full sequence, parent, and digestion agent
903+
/// </summary>
904+
public bool Equals(IBioPolymerWithSetMods other) => Equals(other as PeptideWithSetModifications);
905+
906+
/// <summary>
907+
/// Peptides are equal if they have the same full sequence, parent, and digestion agent
908+
/// </summary>
896909
public bool Equals(PeptideWithSetModifications other)
897910
{
898-
// interface equals first because it does null and reference checks
899-
return (this as IBioPolymerWithSetMods).Equals(other)
911+
if (other is null) return false;
912+
if (ReferenceEquals(this, other)) return true;
913+
if (other.GetType() != GetType()) return false;
914+
915+
// for those constructed from sequence and mods only
916+
if (Parent is null && other.Parent is null)
917+
return FullSequence.Equals(other.FullSequence);
918+
919+
return FullSequence == other.FullSequence
920+
&& Equals(DigestionParams?.DigestionAgent, other.DigestionParams?.DigestionAgent)
921+
// These last two are important for parsimony in MetaMorpheus
900922
&& OneBasedStartResidue == other!.OneBasedStartResidue
901-
&& Equals(Parent, other.Parent);
923+
&& Equals(Parent?.Accession, other.Parent?.Accession);
902924
}
903925

904926
public override int GetHashCode()
@@ -917,6 +939,8 @@ public override int GetHashCode()
917939
return hash.ToHashCode();
918940
}
919941

942+
#endregion
943+
920944
/// <summary>
921945
/// This should be run after deserialization of a PeptideWithSetModifications, in order to set its Protein and Modification objects, which were not serialized
922946
/// </summary>

mzLib/Test/TestPeptideWithSetMods.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ public static void TestPeptideOligoEquality()
7171
Assert.That(!peptide.Equals(oligo));
7272
Assert.That(!((IBioPolymerWithSetMods)oligo).Equals(peptide));
7373
Assert.That(!((IBioPolymerWithSetMods)peptide).Equals(oligo));
74+
Assert.That(!((object)oligo).Equals(peptide));
75+
Assert.That(!((object)peptide).Equals(oligo));
7476
}
7577

7678
[Test]
@@ -1194,6 +1196,45 @@ public static void TestPeptideWithSetModsNoParentProtein()
11941196
Assert.AreEqual('-', last.NextResidue);
11951197
}
11961198

1199+
[Test]
1200+
public static void TestPeptideWithSetModsEquals()
1201+
{
1202+
// Create two proteins
1203+
Protein protein1 = new Protein("SEQUENCEK", "accession1");
1204+
Protein protein2 = new Protein("SEQUENCEK", "accession2");
1205+
1206+
// Create digestion parameters
1207+
DigestionParams digestionParams = new DigestionParams(protease: "trypsin", maxMissedCleavages: 0, initiatorMethionineBehavior: InitiatorMethionineBehavior.Retain);
1208+
1209+
// Digest the proteins to get peptides
1210+
PeptideWithSetModifications peptide1 = protein1.Digest(digestionParams, new List<Modification>(), new List<Modification>()).First();
1211+
PeptideWithSetModifications peptide2 = protein2.Digest(digestionParams, new List<Modification>(), new List<Modification>()).First();
1212+
1213+
// Test equality - same peptide
1214+
Assert.IsTrue(peptide1.Equals(peptide1));
1215+
1216+
// different peptide
1217+
Assert.IsTrue(!peptide1.Equals(peptide2));
1218+
Assert.IsTrue(!peptide1.Equals((object)peptide2));
1219+
Assert.IsTrue(!peptide1.Equals((IBioPolymerWithSetMods)peptide2));
1220+
Assert.AreNotEqual(peptide1.GetHashCode(), peptide2.GetHashCode());
1221+
1222+
// Test inequality with different start residue
1223+
PeptideWithSetModifications peptide3 = new PeptideWithSetModifications(protein1, digestionParams, 2, 9, CleavageSpecificity.Full, "", 0, new Dictionary<int, Modification>(), 0);
1224+
Assert.IsFalse(peptide1.Equals(peptide3));
1225+
1226+
// Test inequality with different parent accession
1227+
PeptideWithSetModifications peptide4 = new PeptideWithSetModifications(protein2, digestionParams, 1, 9, CleavageSpecificity.Full, "", 0, new Dictionary<int, Modification>(), 0);
1228+
Assert.IsFalse(peptide1.Equals(peptide4));
1229+
1230+
// all fail on null
1231+
Assert.That(!peptide1.Equals(null));
1232+
Assert.That(!peptide1.Equals((object)null));
1233+
Assert.That(!peptide1.Equals((PeptideWithSetModifications)null));
1234+
}
1235+
1236+
1237+
11971238
[Test]
11981239
public static void TestIBioPolymerWithSetModsModificationFromFullSequence()
11991240
{

mzLib/Test/Transcriptomics/TestOligoWithSetMods.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,43 +91,55 @@ public static void TestEquality()
9191
.Digest(new RnaDigestionParams(), [], [])
9292
.ElementAt(1);
9393

94-
Assert.That(oligoWithSetMods, Is.EqualTo(oligoWithSetMods2));
94+
// same oligos
95+
Assert.That(oligoWithSetMods.Equals(oligoWithSetMods2));
96+
Assert.That(oligoWithSetMods.Equals((object)oligoWithSetMods2));
97+
Assert.That(oligoWithSetMods.Equals((OligoWithSetMods)oligoWithSetMods2));
98+
Assert.That(oligoWithSetMods.Equals(oligoWithSetMods));
99+
Assert.That(oligoWithSetMods.Equals((object)oligoWithSetMods));
100+
Assert.That(oligoWithSetMods.Equals((OligoWithSetMods)oligoWithSetMods));
95101
Assert.That(oligoWithSetMods.GetHashCode(), Is.EqualTo(oligoWithSetMods2.GetHashCode()));
96-
Assert.That(oligoWithSetMods.Equals((object)oligoWithSetMods2)); // Test the Equals(Object obj) method
102+
103+
// all fail on null
97104
Assert.That(!oligoWithSetMods2.Equals(null));
105+
Assert.That(!oligoWithSetMods2.Equals((object)null));
106+
Assert.That(!oligoWithSetMods2.Equals((OligoWithSetMods)null));
98107

99108
// Null parent checks
100109
oligoWithSetMods = new(oligoWithSetMods.FullSequence, modDict.ToDictionary(p => p.Value.First().IdWithMotif, p => p.Value.First()));
101110
oligoWithSetMods2 = new OligoWithSetMods(oligoWithSetMods.FullSequence, modDict.ToDictionary(p => p.Value.First().IdWithMotif, p => p.Value.First()));
102111
var oligoWithSetMods3 = new OligoWithSetMods(oligoWithSetMods.FullSequence + "AGAUA", modDict.ToDictionary(p => p.Value.First().IdWithMotif, p => p.Value.First()));
103112

104-
Assert.That(oligoWithSetMods, Is.EqualTo(oligoWithSetMods2));
105-
Assert.That(oligoWithSetMods, Is.EqualTo((object)oligoWithSetMods2));
106-
Assert.That(oligoWithSetMods, Is.EqualTo((OligoWithSetMods)oligoWithSetMods2));
107-
Assert.That(oligoWithSetMods, Is.Not.EqualTo(oligoWithSetMods3));
108-
Assert.That(oligoWithSetMods, Is.Not.EqualTo((object)oligoWithSetMods3));
109-
Assert.That(oligoWithSetMods, Is.Not.EqualTo((IBioPolymerWithSetMods)oligoWithSetMods3));
113+
// same oligo null parent
114+
Assert.That(oligoWithSetMods.Equals(oligoWithSetMods2));
115+
Assert.That(oligoWithSetMods.Equals((object)oligoWithSetMods2));
116+
Assert.That(oligoWithSetMods.Equals((OligoWithSetMods)oligoWithSetMods2));
117+
118+
// different oligo null parent
119+
Assert.That(!oligoWithSetMods.Equals(oligoWithSetMods3));
120+
Assert.That(!oligoWithSetMods.Equals((object)oligoWithSetMods3));
121+
Assert.That(!oligoWithSetMods.Equals((IBioPolymerWithSetMods)oligoWithSetMods3));
110122
}
111123

112124
[Test]
113125
[TestCase("GUACUG", "GUACUGGUACUG", "RNase A")]
114126
[TestCase("GUAGGAG", "GUAGCAG", "RNase A")]
115-
public static void TestEquality_DifferentParentSameDigestionProduct(string sequence1, string sequence2, string enzyme)
127+
public static void TestInequality_DifferentParentSameDigestionProduct(string sequence1, string sequence2, string enzyme)
116128
{
117129
var digestionParams = new RnaDigestionParams(rnase: enzyme, minLength: 1, maxMissedCleavages: 0);
118130

119-
var oligo1 = new RNA(sequence1)
131+
var oligo1 = new RNA(sequence1, "", "rna1", "", "")
120132
.Digest(digestionParams, [], [])
121133
.First();
122134

123-
var oligo2 = new RNA(sequence2)
135+
var oligo2 = new RNA(sequence2, "", "rna3", "", "")
124136
.Digest(digestionParams, [], [])
125137
.First();
126138

127-
Assert.That(oligo1, Is.EqualTo(oligo2));
139+
Assert.That(oligo1, Is.Not.EqualTo(oligo2));
128140
Assert.That(oligo1.Equals(oligo1));
129-
Assert.That(oligo1, Is.EqualTo((object)oligo2));
130-
Assert.That(oligo1.GetHashCode(), Is.EqualTo(oligo2.GetHashCode()));
141+
Assert.That(oligo1, Is.Not.EqualTo((object)oligo2));
142+
Assert.That(oligo1.GetHashCode(), Is.Not.EqualTo(oligo2.GetHashCode()));
131143
}
132144

133145
/// <summary>

mzLib/Transcriptomics/Digestion/OligoWithSetMods.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ public void Fragment(DissociationType dissociationType, FragmentationTerminus fr
215215
products.AddRange(GetNeutralFragments(type, sequence));
216216
}
217217

218+
#region IEquatable
219+
220+
/// <summary>
221+
/// Oligos are equal if they have the same full sequence, parent, and digestion agent, and terminal caps
222+
/// </summary>
218223
public override bool Equals(object? obj)
219224
{
220225
if (obj is OligoWithSetMods oligo)
@@ -224,9 +229,31 @@ public override bool Equals(object? obj)
224229
return false;
225230
}
226231

232+
/// <summary>
233+
/// Oligos are equal if they have the same full sequence, parent, and digestion agent, and terminal caps
234+
/// </summary>
235+
public bool Equals(IBioPolymerWithSetMods? other) => Equals(other as OligoWithSetMods);
236+
237+
/// <summary>
238+
/// Oligos are equal if they have the same full sequence, parent, and digestion agent, and terminal caps
239+
/// </summary>
227240
public bool Equals(OligoWithSetMods? other)
228241
{
229-
return (this as IBioPolymerWithSetMods).Equals(other);
242+
if (other is null) return false;
243+
if (ReferenceEquals(this, other)) return true;
244+
if (other.GetType() != GetType()) return false;
245+
246+
// for those constructed from sequence and mods only
247+
if (Parent is null && other.Parent is null)
248+
return FullSequence.Equals(other.FullSequence);
249+
250+
return FullSequence == other.FullSequence
251+
&& Equals(DigestionParams?.DigestionAgent, other.DigestionParams?.DigestionAgent)
252+
&& _fivePrimeTerminus.Equals(other._fivePrimeTerminus)
253+
&& _threePrimeTerminus.Equals(other._threePrimeTerminus)
254+
// These last two are important for parsimony in MetaMorpheus
255+
&& OneBasedStartResidue == other!.OneBasedStartResidue
256+
&& Equals(Parent?.Accession, other.Parent?.Accession);
230257
}
231258

232259
public override int GetHashCode()
@@ -242,9 +269,13 @@ public override int GetHashCode()
242269
{
243270
hash.Add(DigestionParams.DigestionAgent);
244271
}
272+
hash.Add(FivePrimeTerminus);
273+
hash.Add(ThreePrimeTerminus);
245274
return hash.ToHashCode();
246275
}
247276

277+
#endregion
278+
248279
/// <summary>
249280
/// Generates theoretical internal fragments for given dissociation type for this peptide.
250281
/// The "products" parameter is filled with these fragments.

mzLib/Transcriptomics/RNA.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public RNA(string sequence, IHasChemicalFormula? fivePrimeTerm = null, IHasChemi
2323
/// </summary>
2424
/// <param name="sequence"></param>
2525
/// <param name="name"></param>
26-
/// <param name="identifier"></param>
26+
/// <param name="accession"></param>
2727
/// <param name="organism"></param>
2828
/// <param name="databaseFilePath"></param>
2929
/// <param name="fivePrimeTerminus"></param>
@@ -33,12 +33,12 @@ public RNA(string sequence, IHasChemicalFormula? fivePrimeTerm = null, IHasChemi
3333
/// <param name="isDecoy"></param>
3434
/// <param name="geneNames"></param>
3535
/// <param name="databaseAdditionalFields"></param>
36-
public RNA(string sequence, string name, string identifier, string organism, string databaseFilePath,
36+
public RNA(string sequence, string name, string accession, string organism, string databaseFilePath,
3737
IHasChemicalFormula? fivePrimeTerminus = null, IHasChemicalFormula? threePrimeTerminus = null,
3838
IDictionary<int, List<Modification>>? oneBasedPossibleModifications = null,
3939
bool isContaminant = false, bool isDecoy = false, List<Tuple<string, string>> geneNames = null,
4040
Dictionary<string, string>? databaseAdditionalFields = null)
41-
: base(sequence, name, identifier, organism, databaseFilePath, fivePrimeTerminus, threePrimeTerminus,
41+
: base(sequence, name, accession, organism, databaseFilePath, fivePrimeTerminus, threePrimeTerminus,
4242
oneBasedPossibleModifications, isContaminant, isDecoy, geneNames, databaseAdditionalFields)
4343
{
4444

mzLib/mzLib.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<s:Boolean x:Key="/Default/UserDictionary/Words/=Modomics/@EntryIndexedValue">True</s:Boolean>
99
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nucleolytic/@EntryIndexedValue">True</s:Boolean>
1010
<s:Boolean x:Key="/Default/UserDictionary/Words/=Oligo/@EntryIndexedValue">True</s:Boolean>
11+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Oligos/@EntryIndexedValue">True</s:Boolean>
1112
<s:Boolean x:Key="/Default/UserDictionary/Words/=Prsm/@EntryIndexedValue">True</s:Boolean>
1213
<s:Boolean x:Key="/Default/UserDictionary/Words/=Regexes/@EntryIndexedValue">True</s:Boolean>
1314
<s:Boolean x:Key="/Default/UserDictionary/Words/=Toppic/@EntryIndexedValue">True</s:Boolean>

0 commit comments

Comments
 (0)