/// <summary> /// Creates all fermion terms generated by all symmetries of a one-body orbital integral. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="orbitalIntegral">Input orbital integral.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> private static IEnumerable <(HermitianFermionTerm, double)> ToOneBodySpinOrbitalTerms( this OrbitalIntegral orbitalIntegral, int nOrbitals, IndexConvention indexConvention) { // One-electron orbital integral symmetries // ij = ji var pqSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals(); var coefficient = orbitalIntegral.Coefficient; foreach (var pq in pqSpinOrbitals) { var pInt = pq[0].ToInt(indexConvention, nOrbitals); var qInt = pq[1].ToInt(indexConvention, nOrbitals); if (pInt == qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt }.ToLadderSequence()), orbitalIntegral.Coefficient); } else if (pInt < qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt }.ToLadderSequence()), 2.0 * orbitalIntegral.Coefficient); } } }
/// <summary> /// Creates all fermion terms generated by all symmetries of an orbital integral. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="orbitalIntegral">Input orbital integral.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> /// <returns>List of fermion terms generated by all symmetries of an orbital integral.</returns> public static IEnumerable <(HermitianFermionTerm, double)> ToHermitianFermionTerms( this OrbitalIntegral orbitalIntegral, int nOrbitals, IndexConvention indexConvention = IndexConvention.UpDown) { var termType = orbitalIntegral.TermType; if (termType == TermType.OrbitalIntegral.OneBody) { return(orbitalIntegral.ToOneBodySpinOrbitalTerms(nOrbitals, indexConvention)); } else if (termType == TermType.OrbitalIntegral.TwoBody) { return(orbitalIntegral.ToTwoBodySpinOrbitalTerms(nOrbitals, indexConvention)); } else if (termType == TermType.OrbitalIntegral.Identity) { return(new List <(HermitianFermionTerm, double)>() { (new HermitianFermionTerm(), orbitalIntegral.Coefficient) }); } else { throw new System.NotImplementedException(); } }
public void UpsertConventions() { string scope = "TestConventionsScope"; string flowConventionsCode = "GBP-6M"; string indexConventionCode = "GBP-6M-Libor"; // CREATE the flow conventions, index convention for swap var flowConventions = new FlowConventions( scope: scope, code: flowConventionsCode, currency: "GBP", paymentFrequency: "6M", rollConvention: "ModifiedFollowing", dayCountConvention: "Actual365", paymentCalendars: new List <string>(), resetCalendars: new List <string>(), settleDays: 2, resetDays: 2 ); var indexConvention = new IndexConvention( scope: scope, code: indexConventionCode, publicationDayLag: 0, currency: "GBP", paymentTenor: "6M", dayCountConvention: "Actual365", fixingReference: "BP00" ); var flowConventionsResponse = _conventionsApi.UpsertFlowConventions(new UpsertFlowConventionsRequest(flowConventions)); Assert.That(flowConventionsResponse, Is.Not.Null); Assert.That(flowConventionsResponse.Value, Is.Not.Null); var indexConventionsResponse = _conventionsApi.UpsertIndexConvention(new UpsertIndexConventionRequest(indexConvention)); Assert.That(indexConventionsResponse, Is.Not.Null); Assert.That(indexConventionsResponse.Value, Is.Not.Null); var retrievedFlowConventions = _conventionsApi.GetFlowConventions(scope, flowConventionsCode); Assert.That(retrievedFlowConventions, Is.Not.Null); Assert.That(retrievedFlowConventions.Value.Scope, Is.EqualTo(flowConventions.Scope)); Assert.That(retrievedFlowConventions.Value.Code, Is.EqualTo(flowConventions.Code)); var retrievedIndexConvention = _conventionsApi.GetIndexConvention(scope, indexConventionCode); Assert.That(retrievedIndexConvention, Is.Not.Null); Assert.That(retrievedIndexConvention.Value.Scope, Is.EqualTo(indexConvention.Scope)); Assert.That(retrievedIndexConvention.Value.Code, Is.EqualTo(indexConvention.Code)); }
/// <summary> /// Loads a Hamiltonian from integral data represented /// in Broombridge format. /// Please see the <a href="https://docs.microsoft.com/azure/quantum/user-guide/libraries/chemistry/schema/broombridge"> /// Broombridge documentation</a> /// for further details about the /// format parsed by this method. /// </summary> /// <param name="filename">The name of the file to be loaded.</param> /// <param name="indexConvention"> /// The index convention to be used in converting the loaded /// electronic structure problem into a fermionic Hamiltonian. /// </param> /// <returns> /// An instance of <see cref="FermionHamiltonian"/> representing the /// data contained in <paramref name="filename"/>. /// </returns> public static IEnumerable <FermionHamiltonian> LoadFromBroombridge( string filename, IndexConvention indexConvention) { var broombridgeData = Deserializers.DeserializeBroombridge(filename); // Create electronic structure Hamiltonian var fermionHamiltonians = broombridgeData.ProblemDescriptions .Select(o => o.OrbitalIntegralHamiltonian .ToFermionHamiltonian(indexConvention)); return(fermionHamiltonians); }
// Takes in a standard Q# format and outputs interpretable data to text // Input: Problem, state, indexConvention (default), qubitEncoding (default) // Output: No output, see ToPauliHamiltonian for generated filed public static void ToQSharpFormat( ProblemDescription problem, string state = "", IndexConvention indexConvention = IndexConvention.UpDown, QubitEncoding qubitEncoding = QubitEncoding.JordanWigner ) { var fermionHamiltonian = problem .OrbitalIntegralHamiltonian .ToFermionHamiltonian(indexConvention); Auxiliary.ToPauliHamiltonian(fermionHamiltonian, qubitEncoding); }
/// <summary> /// Sample implementation of end-to-end electronic structure problem simulation. /// </summary> /// <param name="filename"></param> public static void SampleWorkflow( string filename, string wavefunctionLabel, IndexConvention indexConvention ) { // Deserialize Broombridge from file. Data broombridge = Deserializers.DeserializeBroombridge(filename); // A single file can contain multiple problem descriptions. Let us pick the first one. var problemData = broombridge.ProblemDescriptions.First(); #region Create electronic structure Hamiltonian // Electronic structure Hamiltonians are usually represented compactly by orbital integrals. Let us construct // such a Hamiltonian from broombridge. OrbitalIntegralHamiltonian orbitalIntegralHamiltonian = problemData.OrbitalIntegralHamiltonian; // We can obtain the full fermion Hamiltonian from the more compact orbital integral representation. // This transformation requires us to pick a convention for converting a spin-orbital index to a single integer. // Let us pick one according to the formula `integer = 2 * orbitalIndex + spinIndex`. FermionHamiltonian fermionHamiltonian = orbitalIntegralHamiltonian.ToFermionHamiltonian(indexConvention); // We target a qubit quantum computer, which requires a Pauli representation of the fermion Hamiltonian. // A number of mappings from fermions to qubits are possible. Let us choose the Jordan–Wigner encoding. PauliHamiltonian pauliHamiltonian = fermionHamiltonian.ToPauliHamiltonian(QubitEncoding.JordanWigner); #endregion #region Create wavefunction Ansatzes // A list of trial wavefunctions can be provided in the Broombridge file. For instance, the wavefunction // may be a single-reference Hartree--Fock state, a multi-reference state, or a unitary coupled-cluster state. // In this case, Broombridge indexes the fermion operators with spin-orbitals instead of integers. Dictionary <string, FermionWavefunction <SpinOrbital> > inputStates = problemData.Wavefunctions ?? new Dictionary <string, FermionWavefunction <SpinOrbital> >(); // If no states are provided, use the Hartree--Fock state. // As fermion operators the fermion Hamiltonian are already indexed by, we now apply the desired // spin-orbital -> integer indexing convention. FermionWavefunction <int> inputState = inputStates.ContainsKey(wavefunctionLabel) ? inputStates[wavefunctionLabel].ToIndexing(indexConvention) : fermionHamiltonian.CreateHartreeFockState(problemData.NElectrons); #endregion #region Pipe to QSharp and simulate // We now convert this Hamiltonian and a selected state to a format that than be passed onto the QSharp component // of the library that implements quantum simulation algorithms. var qSharpHamiltonian = pauliHamiltonian.ToQSharpFormat(); var qSharpWavefunction = inputState.ToQSharpFormat(); var qSharpData = QSharpFormat.Convert.ToQSharpFormat(qSharpHamiltonian, qSharpWavefunction); #endregion }
/// <summary> /// Method for constructing a fermion Hamiltonian from an orbital integral Hamiltonina. /// </summary> /// <param name="sourceHamiltonian">Input orbital integral Hamiltonian.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> /// <returns>Fermion Hamiltonian constructed from orbital integrals.</returns> public static FermionHamiltonian ToFermionHamiltonian( this OrbitalIntegralHamiltonian sourceHamiltonian, IndexConvention indexConvention = IndexConvention.UpDown) { var nOrbitals = sourceHamiltonian.SystemIndices.Max() + 1; var hamiltonian = new FermionHamiltonian(); Func <OrbitalIntegral, double, IEnumerable <(HermitianFermionTerm, DoubleCoeff)> > conversion = (orb, coeff) => new OrbitalIntegral(orb.OrbitalIndices, coeff).ToHermitianFermionTerms(nOrbitals, indexConvention) .Select(o => (o.Item1, o.Item2.ToDoubleCoeff())); foreach (var termType in sourceHamiltonian.Terms) { foreach (var term in termType.Value) { hamiltonian.AddRange(conversion(term.Key, term.Value.Value)); } } // Number of fermions is twice the number of orbitals. hamiltonian.SystemIndices = new HashSet <int>(Enumerable.Range(0, 2 * nOrbitals)); return(hamiltonian); }
/// <summary> /// Converts an electronic structure problem description /// into a format consumable by Q# using default settings. /// </summary> /// <param name="problem">Input electronic structure problem description.</param> /// <param name="state">Selected wavefunction ansatz. This uses the Hartree–Fock state by default.</param> /// <param name="indexConvention">Convention for mapping spin-orbit indices to integer indices.</param> /// <param name="qubitEncoding">Scheme for mapping fermions to qubits.</param> /// <returns> /// A representation of <paramref name="problem" /> suitable for passing to Q# simulation operations. /// </returns> public static JordanWignerEncodingData ToQSharpFormat( this ProblemDescription problem, string state = "", IndexConvention indexConvention = IndexConvention.UpDown, QubitEncoding qubitEncoding = QubitEncoding.JordanWigner ) { var fermionHamiltonian = problem .OrbitalIntegralHamiltonian .ToFermionHamiltonian(indexConvention); var wavefunction = problem.Wavefunctions.ContainsKey(state) ? problem.Wavefunctions[state].ToIndexing(indexConvention) : fermionHamiltonian.CreateHartreeFockState(problem.NElectrons); var pauliHamiltonian = fermionHamiltonian.ToPauliHamiltonian(qubitEncoding); var pauliHamiltonianQSharpFormat = pauliHamiltonian.ToQSharpFormat(); var wavefunctionQSharpFormat = wavefunction.ToQSharpFormat(); return(QSharpFormat.Convert.ToQSharpFormat(pauliHamiltonianQSharpFormat, wavefunctionQSharpFormat)); }
/// <summary> /// Updates an instance of <see cref="FermionHamiltonian"/> /// with all spin-orbitals from described by a sequence of four-body orbital integrals. /// </summary> /// <param name="nOrbitals">Total number of distinct orbitals.</param> /// <param name="orbitalIntegral">Sequence of four-body orbital integrals.</param> /// <param name="indexConvention">Indexing scheme from spin-orbitals to integers.</param> private static IEnumerable <(HermitianFermionTerm, double)> ToTwoBodySpinOrbitalTerms( this OrbitalIntegral orbitalIntegral, int nOrbitals, IndexConvention indexConvention) { List <(HermitianFermionTerm, double)> fermionTerms = new List <(HermitianFermionTerm, double)>(); // Two-electron orbital integral symmetries // ijkl = lkji = jilk = klij = ikjl = ljki = kilj = jlik. var pqrsSpinOrbitals = orbitalIntegral.EnumerateOrbitalSymmetries().EnumerateSpinOrbitals(); var coefficient = orbitalIntegral.Coefficient; // We only need to see one of these. // Now iterate over pqrsArray foreach (var pqrs in pqrsSpinOrbitals) { var p = pqrs[0]; var q = pqrs[1]; var r = pqrs[2]; var s = pqrs[3]; var pInt = p.ToInt(indexConvention, nOrbitals); var qInt = q.ToInt(indexConvention, nOrbitals); var rInt = r.ToInt(indexConvention, nOrbitals); var sInt = s.ToInt(indexConvention, nOrbitals); // Only consider terms on the lower diagonal due to Hermitian symmetry. // For terms with two different orbital indices, possibilities are // PPQQ (QQ = 0), PQPQ, QPPQ (p<q), PQQP, QPQP (p<q), QQPP (PP=0) // Hence, if we only count PQQP, and PQPQ, we need to double the coefficient. // iU jU jU iU | iU jD jD iD | iD jU jU iD | iD jD jD iD if (pInt == sInt && qInt == rInt && pInt < qInt) { // PQQP yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 1.0 * coefficient); } else if (pInt == rInt && qInt == sInt && pInt < qInt) { // iU jU iU jU | iD jD iD jD // PQPQ yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -1.0 * coefficient); } else if (qInt == rInt && pInt < sInt && rInt != sInt && pInt != qInt) { // PQQR // For any distinct pqr, [i;j;j;k] generates PQQR ~ RQQP ~ QPRQ ~ QRPQ. We only need to record one. if (rInt < sInt) { if (pInt < qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { qInt, pInt, sInt, rInt }.ToLadderSequence()), 2.0 * coefficient); } } else { if (pInt < qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { qInt, pInt, rInt, sInt }.ToLadderSequence()), -2.0 * coefficient); } } } else if (qInt == sInt && pInt < rInt && rInt != sInt && pInt != sInt) { // PQRQ // For any distinct pqr, [i;j;k;j] generates {p, q, r, q}, {q, r, q, p}, {q, p, q, r}, {r, q, p, q}. We only need to record one. if (pInt < qInt) { if (rInt > qInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient); } } else { yield return(new HermitianFermionTerm(new[] { qInt, pInt, rInt, sInt }.ToLadderSequence()), -2.0 * coefficient); } } else if (pInt < qInt && pInt < rInt && pInt < sInt && qInt != rInt && qInt != sInt && rInt != sInt) { // PQRS // For any distinct pqrs, [i;j;k;l] generates // {{p, q, r, s}<->{s, r, q, p}<->{q, p, s, r}<->{r, s, p, q}, // {1,2,3,4}<->{4,3,2,1}<->{2,1,4,3}<->{3,4,1,2} // {p, r, q, s}<->{s, q, r, p}<->{r, p, s, q}<->{q, s, p, r}} // 1324, 4231, 3142, 2413 if (rInt < sInt) { yield return(new HermitianFermionTerm(new[] { pInt, qInt, sInt, rInt }.ToLadderSequence()), -2.0 * coefficient); } else { yield return(new HermitianFermionTerm(new[] { pInt, qInt, rInt, sInt }.ToLadderSequence()), 2.0 * coefficient); } } } }
public void DemonstrateCreationOfSwaption() { // CREATE an Interest Rate Swap (IRS) var startDate = new DateTimeOffset(2020, 2, 7, 0, 0, 0, TimeSpan.Zero); var maturityDate = new DateTimeOffset(2030, 2, 7, 0, 0, 0, TimeSpan.Zero); // CREATE the flow conventions, index convention for swap var flowConventions = new FlowConventions( scope: null, code: null, currency: "GBP", paymentFrequency: "6M", rollConvention: FlowConventions.RollConventionEnum.MF, dayCountConvention: FlowConventions.DayCountConventionEnum.Act365, holidayCalendars: new List <string>(), settleDays: 2, resetDays: 2 ); var idxConvention = new IndexConvention( code: "GbpLibor6m", publicationDayLag: 0, currency: "GBP", paymentTenor: "6M", dayCountConvention: IndexConvention.DayCountConventionEnum.Act365, fixingReference: "BP00" ); // CREATE the leg definitions var fixedLegDef = new LegDefinition( rateOrSpread: 0.05m, // fixed leg rate (swap rate) stubType: LegDefinition.StubTypeEnum.Front, payReceive: LegDefinition.PayReceiveEnum.Pay, notionalExchangeType: LegDefinition.NotionalExchangeTypeEnum.None, conventions: flowConventions ); var floatLegDef = new LegDefinition( rateOrSpread: 0.002m, // float leg spread over curve rate, often zero stubType: LegDefinition.StubTypeEnum.Front, payReceive: LegDefinition.PayReceiveEnum.Pay, notionalExchangeType: LegDefinition.NotionalExchangeTypeEnum.None, conventions: flowConventions, indexConvention: idxConvention ); // CREATE the fixed leg var fixedLeg = new FixedLeg( notional: 100m, startDate: startDate, maturityDate: maturityDate, legDefinition: fixedLegDef, instrumentType: LusidInstrument.InstrumentTypeEnum.FixedLeg ); // CREATE the floating leg var floatLeg = new FloatingLeg( notional: 100m, startDate: startDate, maturityDate: maturityDate, legDefinition: floatLegDef, instrumentType: LusidInstrument.InstrumentTypeEnum.FloatingLeg ); var swap = new InterestRateSwap( startDate: startDate, maturityDate: maturityDate, legs: new List <InstrumentLeg> { floatLeg, fixedLeg }, instrumentType: LusidInstrument.InstrumentTypeEnum.InterestRateSwap ); // CREATE swaption to upsert to LUSID var swaption = new InterestRateSwaption( startDate: new DateTimeOffset(2020, 1, 15, 0, 0, 0, TimeSpan.Zero), payOrReceiveFixed: InterestRateSwaption.PayOrReceiveFixedEnum.Pay, deliveryMethod: InterestRateSwaption.DeliveryMethodEnum.Cash, swap: swap, instrumentType: LusidInstrument.InstrumentTypeEnum.InterestRateSwaption); // ASSERT that it was created Assert.That(swaption, Is.Not.Null); Assert.That(swaption.Swap, Is.Not.Null); // CAN NOW UPSERT TO LUSID string uniqueId = "id-swaption-1"; UpsertOtcToLusid(swaption, "some-name-for-this-swaption", uniqueId); // CAN NOW QUERY FROM LUSID var retrieved = QueryOtcFromLusid(uniqueId); Assert.That(retrieved.InstrumentType == LusidInstrument.InstrumentTypeEnum.InterestRateSwaption); var roundTripSwaption = retrieved as InterestRateSwaption; Assert.That(roundTripSwaption, Is.Not.Null); Assert.That(roundTripSwaption.DeliveryMethod, Is.EqualTo(swaption.DeliveryMethod)); Assert.That(roundTripSwaption.StartDate, Is.EqualTo(swaption.StartDate)); Assert.That(roundTripSwaption.PayOrReceiveFixed, Is.EqualTo(swaption.PayOrReceiveFixed)); Assert.That(roundTripSwaption.Swap, Is.Not.Null); Assert.That(roundTripSwaption.Swap.InstrumentType, Is.EqualTo(LusidInstrument.InstrumentTypeEnum.InterestRateSwap)); }
/// <summary> /// Converts spin-orbital indices to integer indices /// </summary> /// <param name="wavefunction">A fermionic wavefunction whose spin-orbital indices are to be converted.</param> /// <param name="indexConvention">The convention for mapping spin-orbitals to indices to be used in converting the spin-orbital indices of <paramref name="wavefunction" />.</param> /// <returns> /// A fermion wavefunction where spin-orbitals are indexed by integers /// according to the chosen indexing scheme. /// </returns> public static FermionWavefunction <int> ToIndexing(this FermionWavefunction <SpinOrbital> wavefunction, IndexConvention indexConvention) => new FermionWavefunction <int>() { Method = wavefunction.Method, Energy = wavefunction.Energy, SCFData = wavefunction.SCFData.SelectIndex <int>((x) => x.ToInt(indexConvention)), MCFData = wavefunction.MCFData.SelectIndex <int>((x) => x.ToInt(indexConvention)), UCCData = wavefunction.UCCData.SelectIndex <int>((x) => x.ToInt(indexConvention)) };
/// <summary> /// This maps the separate orbital and spin indices of a <c>SpinOrbital</c> /// to a single integer index. /// </summary> /// <param name="nOrbitals">The total number of orbitals.</param> public int ToInt(IndexConvention indexConvention, int nOrbitals = maxOrbital) => indexConvention == IndexConvention.UpDown ? Orbital * 2 + Spin : Orbital + nOrbitals * Spin;
public void DemonstrateCreationOfSwap() { // CREATE an Interest Rate Swap (IRS) (that can then be upserted into LUSID) var startDate = new DateTimeOffset(2020, 2, 7, 0, 0, 0, TimeSpan.Zero); var maturityDate = new DateTimeOffset(2030, 2, 7, 0, 0, 0, TimeSpan.Zero); // CREATE the flow conventions, index convention var flowConventions = new FlowConventions( scope: null, code: null, currency: "GBP", paymentFrequency: "6M", rollConvention: "MF", dayCountConvention: "Act365", paymentCalendars: new List <string>(), resetCalendars: new List <string>(), settleDays: 2, resetDays: 2 ); var idxConvention = new IndexConvention( code: "GbpLibor6m", publicationDayLag: 0, currency: "GBP", paymentTenor: "6M", dayCountConvention: "Act365", fixingReference: "BP00" ); // CREATE the leg definitions var fixedLegDef = new LegDefinition( rateOrSpread: 0.05m, // fixed leg rate (swap rate) stubType: "Front", payReceive: "Pay", notionalExchangeType: "None", conventions: flowConventions ); var floatLegDef = new LegDefinition( rateOrSpread: 0.002m, // float leg spread over curve rate, often zero stubType: "Front", payReceive: "Pay", notionalExchangeType: "None", conventions: flowConventions, indexConvention: idxConvention ); // CREATE the fixed leg var fixedLeg = new FixedLeg( notional: 100m, startDate: startDate, maturityDate: maturityDate, legDefinition: fixedLegDef, instrumentType: LusidInstrument.InstrumentTypeEnum.FixedLeg ); // CREATE the floating leg var floatLeg = new FloatingLeg( notional: 100m, startDate: startDate, maturityDate: maturityDate, legDefinition: floatLegDef, instrumentType: LusidInstrument.InstrumentTypeEnum.FloatingLeg ); var irs = new InterestRateSwap( startDate: startDate, maturityDate: maturityDate, legs: new List <InstrumentLeg> { floatLeg, fixedLeg }, instrumentType: LusidInstrument.InstrumentTypeEnum.InterestRateSwap ); // ASSERT that it was created Assert.That(irs, Is.Not.Null); // CAN NOW UPSERT TO LUSID string uniqueId = "id-swap-1"; UpsertOtcToLusid(irs, "some-name-for-this-swap", uniqueId); // CAN NOW QUERY FROM LUSID var retrieved = QueryOtcFromLusid(uniqueId); Assert.That(retrieved.InstrumentType == LusidInstrument.InstrumentTypeEnum.InterestRateSwap); var retrSwap = retrieved as InterestRateSwap; Assert.That(retrSwap, Is.Not.Null); Assert.That(retrSwap.MaturityDate, Is.EqualTo(irs.MaturityDate)); Assert.That(retrSwap.StartDate, Is.EqualTo(irs.StartDate)); Assert.That(retrSwap.Legs.Count, Is.EqualTo(irs.Legs.Count)); }