diff --git a/CHANGELOG.md b/CHANGELOG.md
index e2f3aee..987cd04 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,30 @@ All notable changes to this project are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [1.0.0] — unreleased
+## [1.0.1]
+
+### Added
+
+- **.NET Standard 2.0** target, reaching .NET Framework 4.6.1+, Mono, Godot and Unity
+ 2018–2020. The package now ships `netstandard2.0`, `netstandard2.1`, `net8.0` and `net10.0`.
+- A dedicated package readme. nuget.org cannot resolve relative links, so the repository
+ readme rendered there with a broken logo.
+
+### Changed
+
+- The package icon is now a square 512×512 image. nuget.org renders icons in a square slot,
+ which letterboxed the previous 1024×363 banner.
+
+### Fixed
+
+- State and matrix strings used the current culture's decimal separator and printed full
+ double precision, so `ToString()` returned `0,7071067811865475|00>` on any machine with a
+ comma separator. Output is now culture-invariant and rounded to four decimals.
+- Amplitudes that are only numerical noise are no longer printed: `H(0); H(0);` reads `|0>`
+ rather than including a `1E-17` term.
+- A negative imaginary part reads `0.5 - 0.5i` rather than `0.5 + -0.5i`.
+
+## [1.0.0]
First packaged release. Qubit.NET is now installable with `dotnet add package Qubit.NET`
and usable from Unity.
@@ -75,4 +98,8 @@ and usable from Unity.
flags with the original, so gates applied to a copy also affected the source circuit.
- Toffoli gates rendered their second control as a target marker in circuit diagrams.
- `GetStringResult` threw an exception when every measurement count was zero.
+- State and matrix strings used the current culture's decimal separator and printed full
+ double precision, so `ToString()` returned `0,7071067811865475|00>` on a machine with a
+ comma separator. Output is now culture-invariant and rounded to four decimals, and
+ amplitudes that are numerical noise are no longer printed at all.
- Renamed the internal `ApplayGate` to `ApplyGate`.
diff --git a/README.md b/README.md
index a7a3a4e..ae746df 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-
+
# Qubit.NET
@@ -21,11 +21,12 @@ The state vector holds 2ⁿ complex amplitudes, so memory is the limit: **20 qub
dotnet add package Qubit.NET
```
-Zero dependencies. Targets **.NET Standard 2.1**, **.NET 8** and **.NET 10**.
+Zero dependencies. Targets **.NET Standard 2.0 / 2.1**, **.NET 8** and **.NET 10**, so it’s
+also usable from .NET Framework 4.6.1+, Mono and Godot.
### 🎮 Unity
-Qubit.NET ships a `netstandard2.1` build, so it works in Unity 2021.2+. Either install it
+Qubit.NET ships `netstandard2.0` and `netstandard2.1` builds, so it works in Unity 2018 and later. Either install it
through [NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity), or drop
`lib/netstandard2.1/Qubit.NET.dll` from the package into `Assets/Plugins/`.
diff --git a/README.nuget.md b/README.nuget.md
new file mode 100644
index 0000000..6eb9200
--- /dev/null
+++ b/README.nuget.md
@@ -0,0 +1,124 @@
+
+
+# Qubit.NET
+
+**A quantum computing simulator for .NET — and the only one that runs in Unity.**
+
+Build quantum circuits, apply gates, measure results, draw circuit diagrams, and export to
+OpenQASM so your circuit runs on real hardware. No dependencies.
+
+```bash
+dotnet add package Qubit.NET
+```
+
+Targets **.NET Standard 2.0 / 2.1**, **.NET 8** and **.NET 10** — so it also runs on
+.NET Framework 4.6.1+, Mono and Godot.
+
+---
+
+## Quick start
+
+```csharp
+using Qubit.NET;
+
+var qc = new QuantumCircuit(2);
+
+qc.H(0); // superposition
+qc.CNOT(0, 1); // entangle
+
+Console.WriteLine(qc); // 0.7071|00> + 0.7071|11>
+Console.WriteLine(qc.Measure()); // "00" or "11", never "01" or "10"
+```
+
+Run it many times and count outcomes:
+
+```csharp
+using Qubit.NET.Simulation;
+
+qc.Measure();
+var result = Simulator.Run(qc, 1000)[0];
+
+Console.WriteLine(result); // {'00': 512, '11': 488}
+Console.WriteLine(result.Probability("11")); // 0.488
+```
+
+## Draw circuits
+
+```csharp
+qc.Draw(); // colored, to the console
+qc.ToDiagram(); // the same thing as a string
+```
+
+```
+q2 (0): ───────────[+]──[X]──[M]─
+ | | |
+q1 (0): ──────[+]───@────|───[M]─
+ | | | |
+q0 (0): ─[H]───@────@───[X]──[M]─
+```
+
+## Unity
+
+Qubit.NET ships a `netstandard2.1` build, so it works in Unity 2021.2+. Install through
+[NuGetForUnity](https://github.com/GlitchEnzo/NuGetForUnity), or drop
+`lib/netstandard2.1/Qubit.NET.dll` into `Assets/Plugins/`.
+
+Unity has no `Console`, so use the string-returning APIs:
+
+```csharp
+Debug.Log(qc.ToDiagram());
+
+var (x, y, z) = qc.BlochVector(0); // drive a Bloch sphere gizmo
+arrow.transform.localPosition = new Vector3((float)x, (float)y, (float)z);
+```
+
+A qubit entangled with others sits *inside* the Bloch sphere — maximally entangled means
+the origin, which makes entanglement something you can actually see.
+
+## Built-in algorithms
+
+```csharp
+using Qubit.NET.Circuits;
+
+var grover = Algorithms.Grover(2, c => c.CZ(0, 1)); // marks |11>
+Console.WriteLine(grover.ToHistogram()); // 11 | ######### 1.000
+
+var bv = Algorithms.BernsteinVazirani([true, false, true]);
+Console.WriteLine(bv.Measure(2, 1, 0)); // 101
+```
+
+Also: Deutsch–Jozsa, teleportation, superdense coding, QFT, and the Bell and GHZ states.
+
+## Run on real hardware
+
+```csharp
+using Qubit.NET.Export;
+
+File.WriteAllText("bell.qasm", qc.ToQasm());
+```
+
+```python
+# Qiskit
+qc = QuantumCircuit.from_qasm_file("bell.qasm")
+```
+
+## What else is in the box
+
+- **27 gates** — Pauli, Hadamard, phase, √X/√Y/√Z, rotations, U3, controlled forms, Toffoli, Fredkin, and your own unitary matrices
+- **Mid-circuit measurement and classical feedforward** — `MeasureInto` and `When`, enough for teleportation and error correction
+- **Partial measurement** of any subset of qubits
+- **Pluggable randomness** via `IRandomSource` — seed it for reproducible tests, or plug in a quantum RNG
+- **In-place simulation** — a 20-qubit GHZ chain runs in 34 ms and allocates one state vector, not one per gate
+
+Up to 26 qubits; memory is the limit, since the state vector holds 2ⁿ complex amplitudes
+(20 qubits ≈ 16 MB, 24 ≈ 256 MB).
+
+---
+
+**[Full documentation, examples and source on GitHub →](https://github.com/InfoTCube/Qubit.NET)**
+
+MIT licensed. Issues and pull requests welcome.
diff --git a/img/qubitnet-icon-512.png b/img/qubitnet-icon-512.png
new file mode 100644
index 0000000..637db7a
Binary files /dev/null and b/img/qubitnet-icon-512.png differ
diff --git a/img/qubitnet-icon.svg b/img/qubitnet-icon.svg
new file mode 100644
index 0000000..2fa2e28
--- /dev/null
+++ b/img/qubitnet-icon.svg
@@ -0,0 +1,16 @@
+
diff --git a/src/Qubit.NET/Qubit.NET.csproj b/src/Qubit.NET/Qubit.NET.csproj
index 68ed256..d463efc 100644
--- a/src/Qubit.NET/Qubit.NET.csproj
+++ b/src/Qubit.NET/Qubit.NET.csproj
@@ -1,8 +1,9 @@
-
- netstandard2.1;net8.0;net10.0
+
+ netstandard2.0;netstandard2.1;net8.0;net10.0latestenableenable
@@ -11,7 +12,7 @@
Qubit.NET
- 1.0.0
+ 1.0.1Tymoteusz MarzecA lightweight quantum computing simulation library for .NET. Build quantum circuits, apply gates, measure results, and draw ASCII circuit diagrams — no dependencies. Works in .NET and Unity.quantum;quantum-computing;qubit;simulator;quantum-circuit;unity;csharp;dotnet
@@ -19,7 +20,7 @@
https://github.com/InfoTCube/Qubit.NEThttps://github.com/InfoTCube/Qubit.NETgit
- qubitnet.png
+ qubitnet-icon-512.pngREADME.mdSee CHANGELOG.md
@@ -34,8 +35,10 @@
-
-
+
+
+
diff --git a/src/Qubit.NET/Utilities/Helpers.cs b/src/Qubit.NET/Utilities/Helpers.cs
index fd7680b..2c8c3f5 100644
--- a/src/Qubit.NET/Utilities/Helpers.cs
+++ b/src/Qubit.NET/Utilities/Helpers.cs
@@ -1,3 +1,4 @@
+using System.Globalization;
using Qubit.NET.Gates;
namespace Qubit.NET.Utilities;
@@ -16,18 +17,38 @@ internal static class Helpers
/// A string representation of the complex number, in the form: "real + imaginary*i" or "real" or "imaginary*i".
internal static string FormatComplex(double real, double imaginary)
{
+ // Applying gates leaves amplitudes like 1e-17 where the exact answer is zero.
+ // Printing those makes state strings unreadable, so round them away.
+ if (System.Math.Abs(real) < Epsilon) real = 0;
+ if (System.Math.Abs(imaginary) < Epsilon) imaginary = 0;
+
if (imaginary == 0 && real == 0)
return String.Empty;
-
+
if (imaginary == 0)
- return real.ToString();
-
+ return Number(real);
+
if (real == 0)
- return $"{imaginary}i";
-
- return $"{real} + {imaginary}i";
+ return $"{Number(imaginary)}i";
+
+ // Keep the sign out of the term itself, so this reads "a - bi" not "a + -bi".
+ string sign = imaginary < 0 ? "-" : "+";
+
+ return $"{Number(real)} {sign} {Number(System.Math.Abs(imaginary))}i";
}
+ ///
+ /// Amplitudes below this are treated as zero when formatting.
+ ///
+ private const double Epsilon = 1e-10;
+
+ ///
+ /// Formats a component to four decimal places using the invariant culture, so output
+ /// does not change with the machine's locale.
+ ///
+ private static string Number(double value) =>
+ value.ToString("0.####", CultureInfo.InvariantCulture);
+
///
/// Returns a string array representation of a quantum gate, where each element corresponds
/// to the symbol that should be displayed on a specific qubit line in a circuit diagram.
diff --git a/tests/Qubit.NET.Tests/FormattingTests.cs b/tests/Qubit.NET.Tests/FormattingTests.cs
new file mode 100644
index 0000000..5753810
--- /dev/null
+++ b/tests/Qubit.NET.Tests/FormattingTests.cs
@@ -0,0 +1,87 @@
+using System.Globalization;
+using System.Numerics;
+using Qubit.NET;
+using Qubit.NET.Circuits;
+using Qubit.NET.Gates;
+
+namespace QubitNet.Tests;
+
+///
+/// State and matrix formatting. These strings are the first thing a user sees, and they
+/// must not change with the machine's locale.
+///
+public class FormattingTests
+{
+ [Fact]
+ public void State_string_is_readable()
+ {
+ Assert.Equal("0.7071|00> + 0.7071|11>", BellStates.PhiPlus().ToString());
+ }
+
+ [Fact]
+ public void Basis_states_drop_the_redundant_coefficient()
+ {
+ QuantumCircuit qc = new(2);
+ qc.X(0);
+
+ Assert.Equal("|01>", qc.ToString());
+ }
+
+ [Fact]
+ public void Negative_amplitudes_keep_their_sign()
+ {
+ Assert.Equal("0.7071|00> + -0.7071|11>", BellStates.PhiMinus().ToString());
+ }
+
+ [Fact]
+ public void Numerical_noise_is_not_printed()
+ {
+ // H twice is the identity, but leaves ~1e-17 in the other amplitude.
+ QuantumCircuit qc = new(1);
+ qc.H(0);
+ qc.H(0);
+
+ Assert.Equal("|0>", qc.ToString());
+ }
+
+ [Fact]
+ public void Imaginary_amplitudes_are_formatted_as_complex_numbers()
+ {
+ QuantumCircuit qc = new(1);
+ qc.H(0);
+ qc.S(0);
+
+ // (|0> + i|1>)/sqrt(2)
+ Assert.Equal("0.7071|0> + 0.7071i|1>", qc.ToString());
+ }
+
+ [Fact]
+ public void A_negative_imaginary_part_reads_as_a_subtraction()
+ {
+ // 0.5 - 0.5i, via the SX gate's off-diagonal entry.
+ string formatted = QuantumGates.Format(QuantumGates.SX);
+
+ Assert.Contains("0.5 - 0.5i", formatted);
+ Assert.DoesNotContain("+ -", formatted);
+ }
+
+ [Theory]
+ [InlineData("pl-PL")] // comma decimal separator
+ [InlineData("de-DE")]
+ [InlineData("en-US")]
+ public void Output_does_not_depend_on_the_current_culture(string culture)
+ {
+ CultureInfo original = CultureInfo.CurrentCulture;
+ CultureInfo.CurrentCulture = new CultureInfo(culture);
+
+ try
+ {
+ Assert.Equal("0.7071|00> + 0.7071|11>", BellStates.PhiPlus().ToString());
+ Assert.DoesNotContain(",", QuantumGates.Format(QuantumGates.H));
+ }
+ finally
+ {
+ CultureInfo.CurrentCulture = original;
+ }
+ }
+}