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

Add CQCHandler abstract class, make CQCConnection subclass of it, add CQCToFile class for writing commands to file #39

Merged
merged 25 commits into from
Feb 23, 2020

Conversation

lgvacanti
Copy link
Contributor

Main changes:

  • New abstract class CQCHandler. This has some common functionality that is needed in both CQCConnection and CQCToFile. It also defines some abstractmethods that they must replace.

  • CQCConnection has been made a subclass of CQCHandler

  • New class CQCToFile. It is a subclass of CQCHandler. It allows writing the CQC commands to a file.

cqc/pythonLib.py Outdated
self.pending_messages = []

# Set an app ID
self._appID = 6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why six? I think the functionality for increasing the appID could be moved to the abstract class

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was just a number that made it easier to recognize in the printed out commands. There is no real reason for it.

@AckslD
Copy link
Member

AckslD commented Oct 16, 2019

Hi @shyadow! Nice work :) I think it would be better as we talked about to instead have subclasses implement the sending and reaceiving of messages. In this way most things can go the the abstract class, such as sendCommand, sendXtra etc. What do you think?

@lgvacanti
Copy link
Contributor Author

Hi @shyadow! Nice work :) I think it would be better as we talked about to instead have subclasses implement the sending and reaceiving of messages. In this way most things can go the the abstract class, such as sendCommand, sendXtra etc. What do you think?

@AckslD. So you mean sendCommand would for example do:

self.construct_command()
self.send()

and send() would be the method that the subclasses have to replace. It would be sending over socket for CQCConnection and writing to file for CQCToFile?

I like the idea. I only wonder if there is a better name than send?

@AckslD
Copy link
Member

AckslD commented Oct 16, 2019

@shyadow Yes, exactly. There might be a better name, forward? execute? transmit? push? Feel free to choose a name you think is suitable.

@lgvacanti
Copy link
Contributor Author

@AckslD Alright, I'll work on implementing that.

@lgvacanti
Copy link
Contributor Author

@AckslD sendCommand. sendCmdXtra, and sendSimple have been moved to CQCHandler and commit() is now an abstract method that needs to be replaced by the subclasses.

I feel like you can generally say "I'm committing this message" and it can then mean committing to send it or committing to write it depending on what you are doing.

@lgvacanti
Copy link
Contributor Author

@AckslD The construct commands have been merged. Also noticed sendCommand and sendCmdXtra could then be merged too, so those have been replaced by commit_command().

@AckslD
Copy link
Member

AckslD commented Oct 17, 2019

@shyadow Let me know when you want me to take another look

@lgvacanti
Copy link
Contributor Author

@AckslD It should be good now.

- Add CQCHandler abstract class

- Make CQCConnection a subclass of CQCHandler

- Add CQCWriteToFile class, which is a subclass of CQCHandler

- Add tests for CQCWriteToFile
@lgvacanti lgvacanti force-pushed the develop-CQCConnection-replace branch from 30c3137 to 2e62090 Compare October 31, 2019 15:29
@lgvacanti
Copy link
Contributor Author

@AckslD I brought this pull request up to date with the Develop branch

@AckslD
Copy link
Member

AckslD commented Nov 15, 2019

@lgvacanti There are now tests and the docs are updated with the changes Victor did. So you can know rebase on Develop again and we can now prepare to merge this. Btw, it would be great if you can update the docs as well on how to use the CQCToFile.

@lgvacanti
Copy link
Contributor Author

@AckslD It should be good to start reviewing now.

Copy link
Member

@AckslD AckslD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @lgvacanti! I had a few comments, see below

another file with the same name, but with 'binary' appended, which will contain
the commands in binary form (which is easier to process later).

:meth:`cqc.pythonLib.CQCToFile` does not support sending or receiving
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there other commands not supported, like get-creation-time etc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added sendGetTime(), allocate_qubits(), sendFactory(), create_qubits(),
tomography(), test_preparation() to the list.

There are some more methods in CQCConnection which are not available in CQCToFile, but they are things that usually only get used internally, I think, such as startClassicalServer() and some others.

with open(filename) as f:
contents = f.read()
print(contents)
assert contents[6:10] == "\\x00"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if you instanciate the headers here (from cqcHeader) and check the command w.r.t the variable in the same file. Otherwise, if we cange the headers we also need to change these tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe with these tests it would be better to just use and read the binary files. In that case it's much easier to extract the numbers. With the text file it would be a bit more complicated to translate "\x00" to a number of to have to struct.pack() the number, convert it to text and then compare. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lgvacanti I'm not sure I fully understand. I think it would still be good to instanciate the headers using cqcHeader

cqc/pythonLib.py Outdated
@@ -380,7 +623,19 @@ def close(self, release_qubits=True):
self.flush()

if release_qubits:
self.release_all_qubits()
if len(self.active_qubits[:]) != 0:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not call release_all_qubits?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sequence with release_all_qubits went like this:

def close(self, release_qubits=True):
        """Handle closing actions.
        Flushes remaining headers, releases all qubits, closes the 
        connections, and removes the app ID from the used app IDs.
        """

        # Flush all remaining commands
        if self._pending_headers:
            self.flush()

        if release_qubits:
            self.release_all_qubits()
        self._s.close()
        self._pop_app_id()

        self.closeClassicalServer()

        for name in list(self._classicalConn):
            self.closeClassicalChannel(name)
def release_all_qubits(self):
        """
        Releases all qubits off this connection
        """
        return self.release_qubits(self.active_qubits[:])
def release_qubits(self, qubits, notify=True, block=True, action=False):
        """
        Release qubits so backend can free them up for other uses
        :param qubits: a list of qubits to be released
        :param notify:     Do we wish to be notified when done.
        :param block:         Do we want the qubit to be blocked
        :param action:     Execute the releases recursively or sequencely
        """

        if isinstance(qubits, qubit):
            qubits = [qubits]
        assert isinstance(qubits, list)
        n = len(qubits)

        if n == 0:  # then we don't need to do anything
            return

        logging.debug("App {} tells CQC: Release {} qubits".format(self.name, n))
        if action:
            hdr_length = CQCCmdHeader.HDR_LENGTH + CQCSequenceHeader.HDR_LENGTH
        else:
            hdr_length = CQCCmdHeader.HDR_LENGTH
        hdr = CQCHeader()
        hdr.setVals(CQC_VERSION, CQC_TP_COMMAND, self._appID, hdr_length * n)
        cqc_msg = hdr.pack()

        release_messages = b""

        for i in range(n):
            q = qubits[i]
            try:
                q.check_active()
            except QubitNotActiveError as e:
                raise QubitNotActiveError(
                    str(e) + ". Qubit {} is not active. None of the qubits are released".format(q._qID)
                )
            q._set_active(False)
            cmd_hdr = CQCCmdHeader()
            cmd_hdr.setVals(q._qID, CQC_CMD_RELEASE, int(notify), int(block), int(action))
            release_messages += cmd_hdr.pack()
            if action:
                seq_hdr = CQCSequenceHeader()
                # After this one we are sending n-i-1 more releases
                seq_hdr.setVals(hdr_length * (n - i - 1))
                release_messages += seq_hdr.pack()

        self._s.send(cqc_msg + release_messages)

        if notify:
            msg = self.readMessage()
            self.check_error(msg[0])
            if msg[0].tp != CQC_TP_DONE:
                raise CQCUnsuppError(
                    "Unexpected message sent back from the server. Message: {}".format(msg[0].printable())
                )
            self.print_CQC_msg(msg)

So release_all_qubits() isn't really needed, since you might as well just do release_qubits(self.active_qubits[:])

release_qubits() has been replaced by construct_release(), commit(), and the if notify: block. This fits better in the model of first constructing a message and then sending it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok!

self.commit(msg)

@abstractmethod
def new_qubitID(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both here and in the subclass it is not fully clear what this method is supposed to do. I think it would be good to have a bit more explanation in the doc-string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated them. See this commit 0a292d2

@@ -218,6 +467,9 @@ def __init__(self, name, socket_address=None, appID=None, pend_messages=False,
:param network_name: None or str
Used if simulaqron is used to load socket addresses for the backend
"""

super().__init__(pend_messages=pend_messages)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setting of self._opened_with_with below should probably move to the abstract class since it it checked when creating a qubit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 89842ae

cqc/pythonLib.py Outdated
class CQCToFile(CQCHandler):
"""Handler to be used when writing the CQC commands to a file."""

def __init__(self, filename='CQC_File', pend_messages=False,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also provide the option to specify the binary file path. Or maybe there can be an argument for if we should output text or binary and there is only one file. Also, I think the argument should instead be filepath such that the user can specify a file in another folder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added an argument where you choose to have binary output or text, so there's only one file.

Still to do: absolute path instead of relative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 8e0e607


if release_qubits and self.active_qubits:

msg = self.construct_release(self.active_qubits[:], notify=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of these calls can be unified in this class and CQCConnection.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the check for active qubits in CQCConnection to be the same as here. 9b094c5

But as for unifying, CQCConnection has a if notify: block which this doesn't. Also in CQCConnection's close() the classical servers also get closed

block=True, action=False)
self.commit(msg)

def createEPR(self, name, remote_appID=0, notify=True, block=True):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above, I think we don't need to have this logic in both of the subclasses. Or maybe we do but I cannot see why at this point

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the whole createEPR method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, for createEPR, recvEPR, sendQubit, recvQubit and flush_factory the code is mostly the same for the two classes. It would be better to avoid this.

@lgvacanti
Copy link
Contributor Author

@AckslD You can take another look at this. For all your comments I have either solved them or left a question/remark for you to look at.

@AckslD AckslD merged commit 8e0e607 into SoftwareQuTech:Develop Feb 23, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants