Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic custom matrix input #5

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bloch sphere visualizer</title>
Expand All @@ -13,12 +13,12 @@

<!-- Favicon -->
<link rel="icon" type="image/x-icon" href="logo_v1.svg">

<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="description" content="Simulate the evolution of a qubit or spin on the Bloch sphere. This tool is ideal to understand quantum operations and to generate plots for presentations or publications.">
<link rel="canonical" href="https://bloch.kherb.io/" />

<link rel="canonical" href="https://bloch.kherb.io/" />

</head>

Expand All @@ -30,7 +30,7 @@
$('.collapsible').collapsible();
});
</script>

<div class="row lighten-5 grey">
<nav>
<div class="nav-wrapper indigo">
Expand All @@ -41,7 +41,7 @@
<li ><a href="https://github.com/kherb27/Blochy" target="_blank">GitHub &#8599;</a></li>
</ul>
</div>

</nav>
<div class="col s12 indigo"></div>
<div class="col s12" style="margin-top:1em;"><a class="waves-effect waves-light btn-small" onclick="restart()">Init</a>
Expand All @@ -53,8 +53,8 @@

<div id='myDiv' class='card' style='padding-bottom: 100%;'><noscript>Javascript necessary</noscript></div>
<a class="waves-effect waves-light btn-small" onclick="export_png()" style="margin-bottom: 1em;">Download</a>


</div>
<div class="col s6">

Expand Down Expand Up @@ -105,7 +105,7 @@
<a class="waves-effect waves-light btn-small blue-grey" onclick="rotate_state('z',document.getElementById('z_angle').value/180*math.PI);">+</a>
</td>
</tr></table>

</div>
</li>
<li>
Expand Down Expand Up @@ -158,6 +158,24 @@
</div>

</li>
<li>
<div class="collapsible-header"><i class="material-icons">clear</i>Custom Quantum gate</div>
<div class="collapsible-body">
<table>
<tr>
<td><input id="custom_m00" style="width:8em;margin-left:0.5em;" value="1.0" onblur="on_update_complex(event);"></td>
<td><input id="custom_m01" style="width:8em;margin-left:0.5em;" value="0.0" onblur="on_update_complex(event);"></td>
</tr>
<tr>
<td><input id="custom_m10" style="width:8em;margin-left:0.5em;" value="0.0" onblur="on_update_complex(event);"></td>
<td><input id="custom_m11" style="width:8em;margin-left:0.5em;" value="1.0" onblur="on_update_complex(event);"></td>
</tr>
<tr>
<td><a class="waves-effect waves-light btn-small blue-grey" onclick="apply_custom_matrix();">Apply</a></td>
</tr>
</table>
</div>
</li>
<li>
<div class="collapsible-header"><i class="material-icons">rss_feed</i>Pulses</div>
<div class="collapsible-body">
Expand Down Expand Up @@ -208,9 +226,9 @@
</div>
</li>
</ul>



</div>
</div>
</div></main>
Expand All @@ -220,22 +238,21 @@
</div>
</footer>
<!--JavaScript at end of body for optimized loading-->

<!-- Load plotly.js into the DOM -->
<!-- <script src='https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js'></script> -->
<!-- <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> -->
<script src="plotly-2.16.1.min.js"></script>



<!--Math-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/11.2.1/math.js" integrity="sha512-47N5yVdAeXJ+9qstVMTH2Z0EpX618sjYZcswRwhpldSTD0IbW6yQPtzg4RLrPp/2+TIgEF1elT68/ZBu82nqJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="helper.js"></script>
<script src="quantum.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script type="text/javascript" src="plot.js"></script>
<script type="text/javascript" src="ui.js"></script>

</body>
</html>

12 changes: 12 additions & 0 deletions quantum.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ function rot_phosphor(axis_op, angle, state, divider=10) {
PHOSPHOR.push(hist);
}

function apply_custom_op(custom_op, state) {
let transformed = math.multiply(custom_op, state);
// We have no guarantee the custom_op is unitary; make sure the state stays unit length
let length_sum = 0.0;
for (var i = 0; i < transformed.size()[0]; i++) {
let abs = transformed.get([i]).abs();
length_sum += abs * abs;
}

return math.multiply(1.0 / math.sqrt(length_sum), transformed);
}

function rabi_plot(data=null) {
time = document.getElementById('pulselength').value;
if (data === null) {
Expand Down
123 changes: 117 additions & 6 deletions ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ function pulse_apply(axis){
}



function export_png() {
var currentdate = new Date();
var datetime = currentdate.getFullYear() + "-" + (currentdate.getMonth()+1) + "-" + currentdate.getDate() + "_" + currentdate.getHours() + '- ' + currentdate.getMinutes() + '-' + currentdate.getSeconds();
Expand All @@ -40,7 +39,6 @@ function hadamard(){
rotate_state(rot_op,math.PI);
}


function custom_rotate_state(){
opX = math.matrix([[0,math.complex(0.5,0)],[math.complex(0.5,0),0]]);
opY = math.matrix([[0,math.complex(0,-0.5)],[math.complex(0,0.5),0]]);
Expand All @@ -53,13 +51,126 @@ function custom_rotate_state(){
rotate_state(rot_op,document.getElementById('custom_axis_rot_angle').value/180*math.PI);
}

function apply_custom_matrix() {
let op = math.matrix([[parse_complex_field('custom_m00'), parse_complex_field('custom_m01')], [parse_complex_field('custom_m10'), parse_complex_field('custom_m11')]]);

QMSTATEVECTOR.push(apply_custom_op(op, QMSTATEVECTOR[QMSTATEVECTOR.length-1]));
update_state_plot();
}

function on_update_complex(event) {
let parsed = parse_complex(event.target.value);
event.target.value = parsed.format(4);
}

function parse_complex_field(field_id) {
return parse_complex(document.getElementById(field_id).value);
}

function parse_complex(string) {
string = string.trim();
if (string.startsWith('e^')) {
// parse e^complex
string = string.slice(2);
if (string.startsWith('(')) {
string = string.slice(1);
}
if (string.endsWith(')')) {
string = string.slice(0, -1);
}
let c = parse_complex(string);
return math.Complex.fromPolar(Math.exp(c.re), c.im);
} else {
// Remove the first sign and store its value
let beginSign = '+';
if (string.startsWith('-')) {
beginSign = '-';
string = string.slice(1).trim();
} else if (string.startsWith('+')) {
string = string.slice(1).trim();
}

// split by + or - sign to seperate real and imaginary number
let split = string.split(/[\+\-]/);
if (split.length == 1) {
// we only have a real or imaginary part
let trimmed_value = split[0].trim();
if (trimmed_value.endsWith('i')) {
// only imaginary
if (trimmed_value.length == 1) {
// catch i (without any number)
return math.complex(0, parseFloat(beginSign + '1'));
}
let parsed = parseFloat(beginSign + trimmed_value.slice(0, -1));
if (isNaN(parsed)) {
return math.complex(0, 0);
}
return math.complex(0, parsed);
} else {
// only real
let parsed = parseFloat(beginSign + trimmed_value);
if (isNaN(parsed)) {
return math.complex(0, 0);
}
return math.complex(parsed, 0);
}

} else if (split.length == 2) {

let trimmed1 = split[0].trim();
let trimmed2 = split[1].trim();
let re, im;

// reappend signedness
trimmed1 = beginSign + trimmed1;

if (string.includes('-')) {
trimmed2 = '-' + trimmed2;
}

// find which part is real and which imaginary
if (trimmed2.endsWith('i') && !trimmed1.endsWith('i')) {
re = trimmed1;
im = trimmed2;
} else if (!trimmed2.endsWith('i') && trimmed1.endsWith('i')) {
re = trimmed2;
im = trimmed1;
} else {
return math.complex(0, 0);
}

let re_parsed = parseFloat(re);
let im_parsed;

// catch +i or -i
if (im.length == 1 || (im.length == 2 && im[0] == '+')) {
im_parsed = 1;
} else if (im.length == 2 && im[0] == '-') {
im_parsed = -1;
} else {
im_parsed = parseFloat(im.slice(0, -1));
}

if (isNaN(re_parsed)) {
re_parsed = 0.0;
}
if (isNaN(im_parsed)) {
im_parsed = 0.0;
}

return math.complex(re_parsed, im_parsed);
} else {
return math.complex(0, 0);
}
}
}

function undo() {
if (QMSTATEVECTOR.length> 1){
QMSTATEVECTOR.pop();
PHOSPHOR.pop();
update_state_plot();
}
QMSTATEVECTOR.pop();
PHOSPHOR.pop();
update_state_plot();
}

}

Expand Down