Skip to content

Commit

Permalink
Merge pull request #164 from madcpf/board
Browse files Browse the repository at this point in the history
[Quantum Chinese Chess] Add class Jump(QuantumEffect).
  • Loading branch information
madcpf authored Oct 30, 2023
2 parents dd269b5 + a69abd7 commit ab75eb3
Show file tree
Hide file tree
Showing 12 changed files with 669 additions and 161 deletions.
21 changes: 21 additions & 0 deletions unitary/alpha/quantum_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,27 @@ def _interpret_result(self, result: Union[int, Iterable[int]]) -> int:
return result_list[0]
return result

def unhook(self, object: QuantumObject) -> None:
"""Replace all usages of the given `object` in the circuit with a new ancilla,
so that
- all former operations on `object` will be applied on the new ancilla;
- future operations on `object` start with its new reset value.
Note that we don't do force measurement on it, since we don't care about its
current value but just want to reset it.
"""
# Create a new ancilla.
new_ancilla = self._add_ancilla(object.name)
# Replace operations of the given `object` with the new ancilla.
qubit_remapping_dict = {
object.qubit: new_ancilla.qubit,
new_ancilla.qubit: object.qubit,
}
self.circuit = self.circuit.transform_qubits(
lambda q: qubit_remapping_dict.get(q, q)
)
return

def force_measurement(
self, obj: QuantumObject, result: Union[enum.Enum, int]
) -> None:
Expand Down
22 changes: 21 additions & 1 deletion unitary/alpha/quantum_world_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ def test_pop(simulator, compile_to_qubits):
compile_to_qubits=compile_to_qubits,
)
alpha.Split()(light, light2, light3)
results = board.peek([light2, light3], count=200)
results = board.peek([light2, light3], count=200, convert_to_enum=False)
assert all(result[0] != result[1] for result in results)
assert not all(result[0] == 0 for result in results)
assert not all(result[0] == 1 for result in results)
Expand All @@ -189,6 +189,26 @@ def test_pop(simulator, compile_to_qubits):
assert all(result[1] != popped for result in results)


@pytest.mark.parametrize("compile_to_qubits", [False, True])
@pytest.mark.parametrize("simulator", [cirq.Simulator, alpha.SparseSimulator])
def test_unhook(simulator, compile_to_qubits):
light = alpha.QuantumObject("l1", Light.GREEN)
light2 = alpha.QuantumObject("l2", Light.RED)
light3 = alpha.QuantumObject("l3", Light.RED)
board = alpha.QuantumWorld(
[light, light2, light3],
sampler=simulator(),
compile_to_qubits=compile_to_qubits,
)
alpha.Split()(light, light2, light3)
board.unhook(light2)
results = board.peek([light2, light3], count=200, convert_to_enum=False)
print(results)
assert all(result[0] == 0 for result in results)
assert not all(result[1] == 0 for result in results)
assert not all(result[1] == 1 for result in results)


# TODO: Consider moving to qudit_effects.py if this can be broadly useful.
class QuditSwapEffect(alpha.QuantumEffect):
def __init__(self, dimension):
Expand Down
24 changes: 16 additions & 8 deletions unitary/examples/quantum_chinese_chess/board.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def from_fen(cls, fen: str = _INITIAL_FEN) -> "Board":
FEN rule for Chinese Chess could be found at https://www.wxf-xiangqi.org/images/computer-xiangqi/fen-for-xiangqi-chinese-chess.pdf
"""
chess_board = {}
row_index = 9
row_index = 0
king_locations = []
pieces, turns = fen.split(" ", 1)
for row in pieces.split("/"):
Expand All @@ -74,15 +74,11 @@ def from_fen(cls, fen: str = _INITIAL_FEN) -> "Board":
name, SquareState.OCCUPIED, piece_type, color
)
col += 1
row_index -= 1
row_index += 1
board = alpha.QuantumWorld(chess_board.values())
# Here 0 means the player RED while 1 the player BLACK.
current_player = 0 if "w" in turns else 1
# TODO(): maybe add check to make sure the input fen itself is correct.
if len(king_locations) != 2:
raise ValueError(
f"We expect two KINGs on the board, but got {len(king_locations)}."
)
return cls(board, current_player, king_locations)

def __str__(self):
Expand All @@ -92,7 +88,7 @@ def __str__(self):
for col in "abcdefghi":
board_string.append(f" {col}")
board_string.append("\n")
for row in range(num_rows):
for row in range(num_rows - 1, -1, -1):
# Print the row index on the left.
board_string.append(f"{row} ")
for col in "abcdefghi":
Expand Down Expand Up @@ -165,7 +161,7 @@ def path_pieces(self, source: str, target: str) -> Tuple[List[str], List[str]]:
elif abs(dy) == 2 and abs(dx) == 1:
pieces.append(f"{chr(x0)}{y0 + dy_sign}")
else:
raise ValueError("Unexpected input to path_pieces().")
raise ValueError("The input move is illegal.")
for piece in pieces:
if self.board[piece].is_entangled:
quantum_pieces.append(piece)
Expand All @@ -188,3 +184,15 @@ def flying_general_check(self) -> bool:
# If there are no pieces between two KINGs, the check successes. Game ends.
return True
# TODO(): add check when there are quantum pieces in between.

def sample(self, repetitions: int) -> List[int]:
"""Sample the current board by the given `repetitions`.
Returns a list of 90-bit bitstring, each corresponding to one sample.
"""
samples = self.board.peek(count=repetitions, convert_to_enum=False)
# Convert peek results (in List[List[int]]) into List[int].
samples = [
int("0b" + "".join([str(i) for i in sample[::-1]]), base=2)
for sample in samples
]
return samples
76 changes: 38 additions & 38 deletions unitary/examples/quantum_chinese_chess/board_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ def test_init_with_default_fen():
board.__str__()
== """
a b c d e f g h i
0 r h e a k a e h r 0
1 . . . . . . . . . 1
2 . c . . . . . c . 2
3 p . p . p . p . p 3
4 . . . . . . . . . 4
5 . . . . . . . . . 5
6 P . P . P . P . P 6
7 . C . . . . . C . 7
9 r h e a k a e h r 9
8 . . . . . . . . . 8
9 R H E A K A E H R 9
7 . c . . . . . c . 7
6 p . p . p . p . p 6
5 . . . . . . . . . 5
4 . . . . . . . . . 4
3 P . P . P . P . P 3
2 . C . . . . . C . 2
1 . . . . . . . . . 1
0 R H E A K A E H R 0
a b c d e f g h i
"""
)
Expand All @@ -47,21 +47,21 @@ def test_init_with_default_fen():
board.__str__()
== """
 abcdefghi
0車馬相仕帥仕相馬車0
1.........1
2.砲.....砲.2
3卒.卒.卒.卒.卒3
4.........4
5.........5
6兵.兵.兵.兵.兵6
7.炮.....炮.7
9車馬相仕帥仕相馬車9
8.........8
9车马象士将士象马车9
7.砲.....砲.7
6卒.卒.卒.卒.卒6
5.........5
4.........4
3兵.兵.兵.兵.兵3
2.炮.....炮.2
1.........1
0车马象士将士象马车0
 abcdefghi
"""
)

assert board.king_locations == ["e9", "e0"]
assert board.king_locations == ["e0", "e9"]


def test_init_with_specified_fen():
Expand All @@ -71,16 +71,16 @@ def test_init_with_specified_fen():
board.__str__()
== """
a b c d e f g h i
0 . . . A K . . . c 0
1 . . . . A p . r . 1
2 . . . . . . . . . 2
3 . . . . . . . . . 3
4 . . . . . . . . . 4
9 . . . A K . . . c 9
8 . . . . A p . r . 8
7 . . . . . . . . . 7
6 . . . . . . . . . 6
5 . . . . . . . . . 5
6 . . . . . . . H . 6
7 . . . h R . . . . 7
8 . . . . a . . . . 8
9 . . . . k a R . . 9
4 . . . . . . . . . 4
3 . . . . . . . H . 3
2 . . . h R . . . . 2
1 . . . . a . . . . 1
0 . . . . k a R . . 0
a b c d e f g h i
"""
)
Expand All @@ -90,21 +90,21 @@ def test_init_with_specified_fen():
board.__str__()
== """
 abcdefghi
0...士将...砲0
1....士卒.車.1
2.........2
3.........3
4.........4
9...士将...砲9
8....士卒.車.8
7.........7
6.........6
5.........5
6.......马.6
7...馬车....7
8....仕....8
9....帥仕车..9
4.........4
3.......马.3
2...馬车....2
1....仕....1
0....帥仕车..0
 abcdefghi
"""
)

assert board.king_locations == ["e9", "e0"]
assert board.king_locations == ["e0", "e9"]


def test_path_pieces():
Expand Down
Loading

0 comments on commit ab75eb3

Please sign in to comment.