diff --git a/samples/chemistry/FermionicSwap/COPYRIGHT.txt b/samples/chemistry/FermionicSwap/COPYRIGHT.txt
new file mode 100644
index 00000000000..b644aabc084
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/COPYRIGHT.txt
@@ -0,0 +1,9 @@
+Copyright 2023 Battelle Memorial Institute
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/samples/chemistry/FermionicSwap/DISCLAIMER.txt b/samples/chemistry/FermionicSwap/DISCLAIMER.txt
new file mode 100644
index 00000000000..82318b6a3d8
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/DISCLAIMER.txt
@@ -0,0 +1,8 @@
+This material was prepared as an account of work sponsored by an agency of the United States Government. Neither the United States Government nor the United States Department of Energy, nor Battelle, nor any of their employees, nor any jurisdiction or organization that has cooperated in the development of these materials, makes any warranty, express or implied, or assumes any legal liability or responsibility for the accuracy, completeness, or usefulness or any information, apparatus, product, software, or process disclosed, or represents that its use would not infringe privately owned rights.
+Reference herein to any specific commercial product, process, or service by trade name, trademark, manufacturer, or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or any agency thereof, or Battelle Memorial Institute. The views and opinions of authors expressed herein do not necessarily state or reflect those of the United States Government or any agency thereof.
+PACIFIC NORTHWEST NATIONAL LABORATORY
+operated by
+BATTELLE
+for the
+UNITED STATES DEPARTMENT OF ENERGY
+under Contract DE-AC05-76RL01830
diff --git a/samples/chemistry/FermionicSwap/FermionicSwap.QSharp/FermionicSwap.QSharp.csproj b/samples/chemistry/FermionicSwap/FermionicSwap.QSharp/FermionicSwap.QSharp.csproj
new file mode 100644
index 00000000000..b6bec602636
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/FermionicSwap.QSharp/FermionicSwap.QSharp.csproj
@@ -0,0 +1,11 @@
+
+
+
+ net6.0
+
+
+
+
+
+
+
diff --git a/samples/chemistry/FermionicSwap/FermionicSwap.QSharp/FermionicSwap.qs b/samples/chemistry/FermionicSwap/FermionicSwap.QSharp/FermionicSwap.qs
new file mode 100644
index 00000000000..0ec83128044
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/FermionicSwap.QSharp/FermionicSwap.qs
@@ -0,0 +1,283 @@
+// Copyright Battelle Memorial Institute 2022. All rights reserved.
+
+// Q# functions for Fermionic Swap.
+
+// Code rationale: the code that creates swap networks uses
+// dictionaries, which are not available in Q#. The eventual goal is to call
+// the needed C# functions from Q#, but for now everything is driven from C#.
+// These functions take a data structure produced by C# code and use it to perform
+// evolution of Jordan-Wigner represented fermions using swap networks.
+
+namespace FermionicSwap
+{
+ open Microsoft.Quantum.Intrinsic;
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Chemistry.JordanWigner;
+ open Microsoft.Quantum.Simulation;
+ open Microsoft.Quantum.Math;
+ open Microsoft.Quantum.Convert;
+ open Microsoft.Quantum.Arrays;
+
+ /// # Summary
+ /// Swap two qubits and apply -1 phase if both are in occupied states.
+ /// Effectively permutes pairwise elements in the Jordan-Wigner ordering.
+ ///
+ /// # Input
+ /// ## a
+ /// A Qubit.
+ /// ## b
+ /// Another Qubit. Should be adjacent to the first qubit in the Jordan-Wigner ordering.
+ operation FermionicSwap(a : Qubit, b : Qubit) : Unit is Adj + Ctl {
+ SWAP(a,b);
+ CZ(a,b);
+ }
+
+ /// # Summary
+ /// Apply a sequence of fermionic swaps.
+ ///
+ /// # Input
+ /// ## swaps : An array of pairs of qubit indices to swap,
+ /// ## qubits: The qubits encoding the state, in the Jordan-Wigner representation.
+ operation FermionicSwapLayer( swaps : (Int,Int)[], qubits : Qubit[]) : Unit is Adj + Ctl {
+ for (a,b) in swaps {
+ FermionicSwap(qubits[a],qubits[b]);
+ }
+ }
+
+ /// # Summary
+ /// ## Apply Fermionic Swap Trotter steps to qubits.
+ ///
+ /// # Input
+ /// ## generator
+ /// an EvolutionGenerator which describes a Fermionic Swap Trotter step,
+ /// ## trotterStepSize
+ /// Time duration of a single Trotter step,
+ /// ## time
+ /// Total duration of evolution,
+ /// ## register
+ /// The qubits to be operated upon.
+ ///
+ /// # Remarks
+ /// Changes the Jordan-Wigner ordering if evolution requires an odd number
+ /// of time steps.
+ operation FermionicSwapEvolveUnderGenerator(
+ generator : EvolutionGenerator,
+ trotterStepSize : Double,
+ time : Double,
+ register : Qubit[]
+ ) : Unit is Adj + Ctl {
+ let evolveFor = (FermionicSwapSimulationAlgorithm(trotterStepSize))!;
+ evolveFor(time, generator, register);
+ }
+
+ /// # Summary
+ /// Apply a single fermionic swap Trotter step.
+ ///
+ /// # Input
+ /// ## swapNetwork
+ /// The swaps to be performed. An array of arrays, one for each layer.
+ /// ## localEvolutions
+ /// Local evolutions to be performed between swap layers. Each evolution
+ /// is a JWOptimizedHTerms object, and each local evolution layer is an
+ /// array of such to keep Q# from optimizing. If Q# optimization is
+ /// desired, the layer may be specified as a length one array with all
+ /// evolutions combined in a single JWOptimizedHTerms object.
+ /// ## time
+ /// The duration of the Trotter step.
+ /// ## qubits
+ /// The qubits to be acted upon.
+ ///
+ /// # Remarks
+ /// Changes the Jordan-Wigner ordering. Applying again with layers reversed
+ /// restores the original Jordan-Wigner ordering.
+ operation FermionicSwapTrotterStep(
+ swapNetwork : (Int,Int)[][],
+ localEvolutions : JWOptimizedHTerms[][],
+ time : Double,
+ qubits : Qubit[]) : Unit
+ {
+ let nTerms = Length(qubits);
+ for i in 0 .. Length(swapNetwork) {
+ for ops in localEvolutions[i] {
+ mutable empty = true;
+ let (opa,opb,opc,opd) = ops!;
+ if Length(opa) > 0 or Length(opb) > 0 or Length(opc) > 0 or Length(opd) > 0 {
+ set empty = false;
+ }
+ if (not empty) {
+ let generatorSystem = JordanWignerGeneratorSystem(ops);
+ let evolutionGenerator = EvolutionGenerator(JordanWignerFermionEvolutionSet(), generatorSystem);
+ TrotterStep(evolutionGenerator, 1, time)(qubits);
+ }
+ }
+ if i < Length(swapNetwork) {
+ FermionicSwapLayer(swapNetwork[i], qubits);
+ }
+ }
+ }
+
+ /// # Summary
+ /// Internal implementation of single layer for a fermionic swap
+ /// Hamiltonian evolution Trotter step.
+ /// Trotterized swap network.
+ ///
+ /// # Input
+ /// ## stepSize
+ /// Duration of a Trotter step.
+ /// ## time
+ /// Duration of the evolution.
+ /// ## generator
+ /// An EvolutionGenerator.
+ /// ## qubits
+ /// The qubits in the system to be acted upon.
+ operation FermionicSwapEvolutionImpl(
+ swapNetwork : (Int,Int)[][],
+ localEvolutions : JWOptimizedHTerms[][],
+ generatorIndex : GeneratorIndex,
+ time : Double,
+ qubits : Qubit[]
+ ) : Unit is Adj + Ctl{
+ body (...) {
+ let ((indices, _), _) = generatorIndex!;
+ let index = indices[0];
+ let gi = (index-1) / 2;
+ if index % 2 != 0 {
+ for ops in localEvolutions[gi] {
+ let (opa,opb,opc,opd) = ops!;
+ if (Length(opa) > 0 or Length(opb) > 0 or Length(opc) > 0 or Length(opd) > 0) {
+ let generatorSystem = JordanWignerGeneratorSystem(ops);
+ let evolutionGenerator = EvolutionGenerator(JordanWignerFermionEvolutionSet(), generatorSystem);
+ TrotterStep(evolutionGenerator, 1, time)(qubits);
+ }
+ }
+ } else {
+ FermionicSwapLayer(swapNetwork[gi], qubits);
+ }
+ }
+ }
+
+ /// # Summary
+ /// Create an EvolutionFunction that evolves a single swap or Hamiltonian
+ /// layer in a swap network. An EvolutionGenerator uses these to perform
+ /// a Trotter step.
+ ///
+ /// # Input
+ /// ## swapNetwork
+ /// The network of layers of swaps to perform.
+ /// ## localEvolutions
+ /// Local evolutions to be performed between swap layers.
+ /// ## generatorIndex
+ /// An index indicating the swap or Hamiltonian interaction layer to evolve.
+ ///
+ /// # Output
+ /// An EvolutionFunction that evolves the layer.
+ function FermionicSwapEvolutionFunction(
+ swapNetwork : (Int,Int)[][],
+ localEvolutions : JWOptimizedHTerms[][],
+ generatorIndex : GeneratorIndex
+ ) : EvolutionUnitary {
+ return EvolutionUnitary(FermionicSwapEvolutionImpl(swapNetwork, localEvolutions, generatorIndex, _, _));
+ }
+
+ /// # Summary
+ /// Return an EvolutionSet for a swap network.
+ ///
+ /// # Input
+ /// ## swapNetwork
+ /// The fermionic swaps to be performed.
+ /// ## localEvolutions
+ /// Local evolutions to be performed between swap layers.
+ ///
+ /// # Output
+ /// An EvolutionSet which converts indices to layer evolutions.
+ function FermionicSwapEvolutionSet(
+ swapNetwork : (Int,Int)[][],
+ localEvolutions : JWOptimizedHTerms[][]
+ ) : EvolutionSet {
+ return EvolutionSet(FermionicSwapEvolutionFunction(swapNetwork, localEvolutions, _));
+ }
+
+ /// # Summary
+ /// Return a GeneratorSystem for a fermionic swap network
+ ///
+ /// # Inputs
+ /// ## Size
+ /// The size of the system. Should be twice the number of swap layers, plus
+ /// one.
+ ///
+ /// # Output
+ /// A GeneratorSystem.
+ function FermionicSwapGeneratorSystem(
+ size : Int
+ ) : GeneratorSystem {
+ return GeneratorSystem(size, s -> GeneratorIndex(([s], []), []));
+ }
+
+ /// # Summary
+ /// Internal implementation of timed evolution of a Hamiltonian through
+ /// Trotterized swap network.
+ ///
+ /// # Input
+ /// ## stepSize
+ /// Duration of a Trotter step.
+ /// ## time
+ /// Duration of the evolution.
+ /// ## generator
+ /// An EvolutionGenerator.
+ /// ## qubits
+ /// The qubits in the system to be acted upon.
+ operation FermionicSwapSimulationAlgorithmImpl(
+ stepSize : Double,
+ time : Double,
+ generator : EvolutionGenerator,
+ qubits : Qubit[]
+ ) : Unit is Adj + Ctl {
+ let (evoSet, genSys) = generator!;
+ let (numTerms, termDict) = genSys!;
+ let timeSteps = Ceiling(time / stepSize);
+ for i in 1..timeSteps {
+ let thisTime = (i
+
+
+ net6.0
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/chemistry/FermionicSwap/FermionicSwap.Tests.QSharp/QSharp.qs b/samples/chemistry/FermionicSwap/FermionicSwap.Tests.QSharp/QSharp.qs
new file mode 100644
index 00000000000..5e174e62e78
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/FermionicSwap.Tests.QSharp/QSharp.qs
@@ -0,0 +1,79 @@
+// Copyright Battelle Memorial Institute 2022. All rights reserved.
+
+// QSharp unit tests for Fermionic Swap QSharp code.
+// These are tests are driven from the C# unit tests;
+// See notes in FermionicSwap.qs for rationale.
+namespace FermionicSwap.Tests {
+ open Microsoft.Quantum.Simulation;
+ open Microsoft.Quantum.Intrinsic;
+ open Microsoft.Quantum.Canon;
+ open Microsoft.Quantum.Math;
+ open Microsoft.Quantum.Chemistry;
+ open Microsoft.Quantum.Chemistry.JordanWigner;
+ open Microsoft.Quantum.Arrays;
+ open FermionicSwap;
+
+ // We open the diagnostics namespace under an alias to help avoid
+ // conflicting with deprecation stubs in Microsoft.Quantum.Canon.
+ open Microsoft.Quantum.Diagnostics as Diag;
+
+ // This test as currently written will only work for Hamiltonians with a
+ // single summand due to Trotter summand reordering issues.
+ operation SwapNetworkOneSummandTestOp(swapNetwork : (Int,Int)[][],
+ qsharpNetworkData : JWOptimizedHTerms[][],
+ qsharpHamiltonian : JWOptimizedHTerms,
+ numQubits : Int
+ ) : Unit {
+ let time = 1.0;
+ Diag.AssertOperationsEqualReferenced(numQubits,
+ _FixedOrderFermionicSwapTrotterStep(swapNetwork, qsharpNetworkData, time, _),
+ _JordanWignerApplyTrotterStep(qsharpHamiltonian, time, _ )
+ );
+ }
+
+ // Perform trotter evolution with straight Jordan-Wigner evolution, and
+ // using Fermionic swap network. These are only the same in the
+ // small stepSize limit.
+ operation SwapNetworkEvolutionTestOp(
+ swapNetwork : (Int,Int)[][],
+ qsharpNetworkData : JWOptimizedHTerms[][],
+ qsharpHamiltonian : JWOptimizedHTerms,
+ numQubits : Int,
+ stepSize : Double,
+ time : Double
+ ) : Unit {
+ let generatorSystem = JordanWignerGeneratorSystem(qsharpHamiltonian);
+ let jwGenerator = EvolutionGenerator(JordanWignerFermionEvolutionSet(), generatorSystem);
+ let fsGenerator = FermionicSwapEvolutionGenerator(swapNetwork, qsharpNetworkData);
+ Diag.AssertOperationsEqualReferenced(numQubits,
+ FermionicSwapEvolveUnderGenerator(fsGenerator, stepSize, time, _),
+ _EvolveUnderGenerator(jwGenerator, stepSize, time,_ )
+ );
+ }
+
+ // Copied from a QDK example
+ operation _EvolveUnderGenerator(generator : EvolutionGenerator, trotterStepSize : Double, time : Double, register : Qubit[])
+ : Unit is Adj + Ctl {
+ let trotterOrder = 1;
+ let evolveFor = (TrotterSimulationAlgorithm(trotterStepSize, trotterOrder))!;
+ evolveFor(time, generator, register);
+ }
+
+
+ operation _FixedOrderFermionicSwapTrotterStep(swapNetwork : (Int,Int)[][],
+ qsharpNetworkData : JWOptimizedHTerms[][],
+ time : Double, qubits : Qubit[]) : Unit {
+ FermionicSwapTrotterStep(swapNetwork, qsharpNetworkData, time, qubits);
+ let empty = new JWOptimizedHTerms[][Length(swapNetwork)+1];
+ FermionicSwapTrotterStep(Reversed(swapNetwork), empty, 0.0, qubits);
+ }
+
+ operation _JordanWignerApplyTrotterStep (data : JWOptimizedHTerms, trotterStepSize : Double, qubits :
+Qubit[])
+ : Unit is Adj + Ctl {
+ let generatorSystem = JordanWignerGeneratorSystem(data);
+ let evolutionGenerator = EvolutionGenerator(JordanWignerFermionEvolutionSet(), generatorSystem);
+ let trotterOrder = 1;
+ TrotterStep(evolutionGenerator, trotterOrder, trotterStepSize)(qubits);
+ }
+}
\ No newline at end of file
diff --git a/samples/chemistry/FermionicSwap/FermionicSwap.Tests/FermionicSwap.Tests.csproj b/samples/chemistry/FermionicSwap/FermionicSwap.Tests/FermionicSwap.Tests.csproj
new file mode 100644
index 00000000000..d402dd57fb5
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/FermionicSwap.Tests/FermionicSwap.Tests.csproj
@@ -0,0 +1,32 @@
+
+
+
+ net6.0
+ x64
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/samples/chemistry/FermionicSwap/FermionicSwap.Tests/TestFermionicSwap.cs b/samples/chemistry/FermionicSwap/FermionicSwap.Tests/TestFermionicSwap.cs
new file mode 100644
index 00000000000..ffc7e9b7f7f
--- /dev/null
+++ b/samples/chemistry/FermionicSwap/FermionicSwap.Tests/TestFermionicSwap.cs
@@ -0,0 +1,703 @@
+// Copyright Battelle Memorial Institute 2022. All rights reserved.
+
+using Microsoft.Quantum.Chemistry.Fermion;
+using Microsoft.Quantum.Chemistry.LadderOperators;
+using Microsoft.Quantum.Chemistry;
+using Microsoft.Quantum.Simulation.Core;
+using Microsoft.Quantum.Simulation.Simulators;
+using Microsoft.Quantum.Chemistry.JordanWigner;
+using static FermionicSwap.FSTools;
+using Microsoft.Quantum.Chemistry.QSharpFormat;
+using static FermionicSwap.SwapNetwork;
+using System.Linq;
+using System.Collections.Immutable;
+using System;
+
+namespace FermionicSwap.Tests
+{
+
+ using SwapLayer = List<(int,int)>;
+ using OperatorLayer = List<(HermitianFermionTerm, DoubleCoeff)>;
+ using OperatorNetwork = List>;
+
+ public class TestFermionicSwap
+{
+
+ [Theory]
+ [MemberData(nameof(Data))]
+ public void TestEvenOddSwap(int[] startOrder, int[] endOrder, SwapNetwork swapNetwork)
+ {
+ var result = FSTools.EvenOddSwap(startOrder, endOrder);
+ Assert.True(result.Count == swapNetwork.Count, $"Need swap layers {LayersString(swapNetwork)}, but got {LayersString(result)}.");
+ // for each swap layer, check that the list of swaps matches the test list
+ foreach (var (first,second) in result.Zip(swapNetwork, (f,s)=> (f,s))) {
+ Assert.True(first.SequenceEqual(second), $"Swap network {LayersString(result)} should be {LayersString(swapNetwork)}.");
+ }
+ }
+
+ public static IEnumerable