示例#1
0
def _fetchResult(token, taskId):
    """
    Fetch the result files from the taskId
    """

    params = {"token": token, "taskId": taskId}

    ret = invokeBackend("task/getTaskInfo", params)

    result = ret["result"]

    originUrl = result["originUrl"]
    # originSize = result["originSize"]
    try:
        originFile, downSize = _downloadToFile(originUrl, f"./Output/{taskId}.origin.json")
    except Exception:
        # TODO split the disk write error
        raise Error.NetworkError(traceback.format_exc())
    if outputInfo:
        print(f"Download result success {originFile} size = {downSize}")

    measureUrl = result["measureUrl"]
    # measureSize = result["measureSize"]
    try:
        measureFile, downSize = _downloadToFile(measureUrl, f"./Output/{taskId}.measure.json")
    except Exception:
        # TODO split the disk write error
        raise Error.NetworkError(traceback.format_exc())
    if outputInfo:
        print(f"Download result success {measureFile} size = {downSize}")
    # pprint(result)

    return originFile, measureFile
示例#2
0
def _contract1_2(matrix_parking, matrix_floating, up_or_down, left_or_right):
    """
    Matrix_parking is like 1010.
    The first half of the indicators are outputs,
    and the second half are inputs.
    """
    if matrix_floating.shape != (2, 2):
        raise Error.ParamError("Floating gate not a 1-qubit gate")
    if matrix_parking.shape == (4, 4):
        matrix_parking = numpy.reshape(matrix_parking, [2, 2, 2, 2])
    elif matrix_parking.shape != (2, 2, 2, 2):
        raise Error.ParamError("Parking gate not a 2-qubit gate")
    if left_or_right == 0:
        if up_or_down == 0:
            new_array = numpy.einsum("abcd,de->abce", matrix_parking,
                                     matrix_floating)
        elif up_or_down == 1:
            new_array = numpy.einsum("abcd,ce->abed", matrix_parking,
                                     matrix_floating)
    elif left_or_right == 1:
        if up_or_down == 0:
            new_array = numpy.einsum("eb,abcd->aecd", matrix_floating,
                                     matrix_parking)
        elif up_or_down == 1:
            new_array = numpy.einsum("ea,abcd->ebcd", matrix_floating,
                                     matrix_parking)
    return numpy.reshape(new_array, [4, 4])
示例#3
0
def _contract1_1(matrix_parking, matrix_floating):
    """
    The first indicator of the gate is the output,
    and the latter indicator is the input,
    just like writing matrix vector multiplication, U{ket0}
    """
    if matrix_floating.shape != (2, 2):
        raise Error.ParamError("Floating gate not a 1-qubit gate")
    if matrix_parking.shape != (2, 2):
        raise Error.ParamError("Parking gate not a 1-qubit gate")
    new_array = numpy.einsum(
        'ab,bc->ac', matrix_parking, matrix_floating
    )  # v is a vector, A B is a matrix, we must count ABv, here we count AB
    return new_array
    def convertToProcedure(self, name, env):
        """
        Convert to sub-procedure

        Self env will be destroyed

        Example:

        procedure0 = env.makeProcedure('procedure0')

        :param name: name of sub procedure(not allow duplication)
        :param env: env of sub procedure
        :return: QuantumProcedure
        """

        procedure = QuantumProcedure(name, self.params, self.Q, self.circuit)

        # insert it into quantum programming environment
        if env.procedureMap.get(name) != None:
            raise Error.ParamError(f'same procedure name "{name}"')
        env.procedureMap[name] = procedure

        # self destroy
        self.__dict__.clear()

        return procedure
示例#5
0
def initState_1_0(matrixType, n):
    """
    Generate an n-qubit state
    """

    if matrixType == MatrixType.Dense:
        return initStateDense_1_0(n)
    else:
        raise Error.RuntimeError('Not implemented')
示例#6
0
def invokeBackend(target, params):
    """
    Invoke the Backend Functions
    """

    try:
        ret = requests.post(
            f"{quantumHubAddr}/{target}", json=params).json()
    except Exception:
        raise Error.NetworkError(traceback.format_exc())

    if ret["error"] > 0:
        errCode = ret["error"]
        errMsg = ret["message"]
        if errCode == 401:
            raise Error.TokenError(errMsg)
        else:
            raise Error.LogicError(errMsg)

    return ret["data"]
示例#7
0
def _waitTask(token, taskId, fetchMeasure=False, downloadResult=True):
    """
    Wait for a task from the taskId
    """

    task = {
        "token": token,
        "taskId": taskId
    }

    stepStatus = "waiting"
    while True:
        try:
            time.sleep(pollInterval)
            ret = invokeBackend("task/checkTask", task)
            if ret["status"] in ("success", "failed", "manual_term"):
                if outputInfo:
                    print(f"status changed {stepStatus} => {ret['status']}")
                stepStatus = ret["status"]
                result = {"status": ret["status"]}

                if ret["status"] == "success" and "originUrl" in ret.get("result", {}):
                    if downloadResult:
                        originFile, measureFile = _fetchResult(token, taskId)
                        result["origin"] = originFile
                        if fetchMeasure:
                            result["counts"] = _fetchMeasureResult(taskId)
                        else:
                            result["measure"] = measureFile
                    break
                elif ret["status"] == "failed":
                    result = ret["reason"]
                    break
                elif ret["status"] == "manual_term":
                    break
                else:
                    # go on loop
                    # pprint(ret)
                    pass
            else:
                if ret["status"] == stepStatus:
                    continue

                if outputInfo:
                    print(f"status changed {stepStatus} => {ret['status']}")
                stepStatus = ret["status"]

        except Error.Error as err:
            raise err

        except Exception:
            raise Error.RuntimeError(traceback.format_exc())

    return result
示例#8
0
def gate_from_circuitLine(circuitLine):  # do not support sparse
    if circuitLine.HasField('rotationGate'):
        if circuitLine.rotationGate != RotationGateEnum.U:
            raise Error.ParamError(
                f'unsupported operation {RotationGateEnum.Name(circuitLine.rotationGate)}')
        uGate = U(*circuitLine.paramValues)
        matrix = uGate.matrix
        return matrix
    if circuitLine.HasField('fixedGate'):
        operationDict = {}
        operationDict[FixedGateEnum.X] = X.matrix
        operationDict[FixedGateEnum.Y] = Y.matrix
        operationDict[FixedGateEnum.Z] = Z.matrix
        operationDict[FixedGateEnum.H] = H.matrix
        operationDict[FixedGateEnum.CX] = CX.matrix.reshape(2, 2, 2, 2)
        matrix = operationDict.get(circuitLine.fixedGate)
        if matrix is None:
            raise Error.ParamError(f'unsupported operation {FixedGateEnum.Name(circuitLine.fixedGate)}')
        return matrix
    if circuitLine.HasField('customizedGate'):
        return _protobufMatrixToNumpyMatrix(circuitLine.customizedGate.matrix)
示例#9
0
def loadGates(matrixType, operationDict):
    """
    Load the matrix of the gate
    """

    if matrixType == MatrixType.Dense:
        operationDict[FixedGateEnum.X] = X.matrix
        operationDict[FixedGateEnum.Y] = Y.matrix
        operationDict[FixedGateEnum.Z] = Z.matrix
        operationDict[FixedGateEnum.H] = H.matrix
        operationDict[FixedGateEnum.CX] = CX.matrix.reshape(2, 2, 2, 2)
    else:
        raise Error.RuntimeError('Not implemented')
示例#10
0
    def __init__(self, matrixType, algorithm, measureMethod):
        """
        To choose the algorithms by the parameters.
        """

        if measureMethod == MeasureMethod.Probability:
            if matrixType == MatrixType.Dense:
                self.proc = self.measureDenseByProbability
            else:
                raise Error.RuntimeError('Not implemented')
        else:
            self.Transfer = TransferProcessor(matrixType, algorithm)
            self.proc = self.measureBySingleAccumulation
示例#11
0
def runSimulator(args, program):
    """
    Initialization process
    """

    parser = argparse.ArgumentParser()
    parser.add_argument('-mt', default='dense', type=str)
    parser.add_argument('-a', default='matmul', type=str)
    parser.add_argument('-mm', default='probability', type=str)
    parser.add_argument('-s', default=None, type=int)
    parser.add_argument('-shots', default=None, type=int)
    parser.add_argument('-inputFile', default=None, type=str)

    args = parser.parse_args(args=args)
    matrixType = args.mt.lower()
    algorithm = args.a.lower()
    measureMethod = args.mm.lower()
    seed = args.s
    shots = args.shots
    inputFile = args.inputFile

    if matrixType == 'dense':
        matrixType = MatrixType.Dense

    else:
        raise Error.ParamError(f'Invalid MatrixType {matrixType}')

    if algorithm == 'matmul':
        algorithm = Algorithm.Matmul
    elif algorithm == 'einsum':
        algorithm = Algorithm.Einsum
    else:
        raise Error.ParamError(f'Invalid Algorithm {algorithm}')

    if measureMethod == 'probability':
        measureMethod = MeasureMethod.Probability
    elif measureMethod == 'accumulation':
        measureMethod = MeasureMethod.Accumulation
    else:
        raise Error.ParamError(f'Invalid MeasureMethod {measureMethod}')

    if seed is not None:
        if isinstance(seed, int):
            if seed < 0 or seed > 2147483647:
                raise Error.ParamError(f'Invalid Seed {seed}')
        else:
            raise Error.ParamError(f'Invalid Seed {seed}')

    if shots <= 0:
        raise Error.ParamError(f'invalid shots {shots}')

    if inputFile is not None:
        with open(inputFile, "rt") as fObj:
            jsonStr = fObj.read()
        program = Parse(jsonStr, Program())

    return core(program, matrixType, algorithm, measureMethod, shots, seed)
    def commit(self, shots, **kwargs):
        """
        Switch local/cloud commitment by prefix of backend name

        Example:

        env.commit(1024)

        env.commit(1024, fetchMeasure=True)

        env.commit(1024, downloadResult=False)

        :param shots: experiment counts
        :param fetchMeasure: named param, default is False, means 'Extract data from measurement results', downloadResult must be True
        :param downloadResult: named param, default is True, means 'Download experiment results from the server'
        :return: local or cloud commit result

        Successful:

        {status: 'success', origin: resultFilePath, measure: measureDict}  # fetchMeasure=True

        {status: 'success', origin: resultFilePath, counts: 1024}  # fetchMeasure=False

        {status: 'success'}  # downloadResult=False

        failed:

        {status: 'error', reason: ''}

        {status: 'failed', reason: ''}
        """

        if self.backendName.startswith('local_'):
            return self._localCommit(shots, **kwargs)
        elif self.backendName.startswith('cloud_'):
            return self._cloudCommit(shots, **kwargs)
        elif self.backendName.startswith('agent_'):
            return self._agentCommit(shots, **kwargs)
        else:
            raise Error.ParamError(
                f"invalid backendName => {self.backendName}")
示例#13
0
def _getSTSToken():
    """
    Get the token to upload the file

    :return:
    """

    if not Define.hubToken:
        raise Error.ParamError("please provide a valid token")

    config = invokeBackend("circuit/genSTS", {"token": Define.hubToken})

    bosClient = BosClient(
        BceClientConfiguration(
            credentials=BceCredentials(
                str(
                    config['accessKeyId']),
                str(
                    config['secretAccessKey'])),
            endpoint='http://bd.bcebos.com',
            security_token=str(
                config['sessionToken'])))

    return [Define.hubToken, bosClient, config['dest']]
示例#14
0
    def _unrollProcedure(self, circuit, qRegsMap, paramValues):
        # fill in the circuit
        for circuitLine in circuit:
            if circuitLine.HasField('fixedGate'):  # fixed gate
                fixedGateClass = getattr(
                    FixedGate, FixedGateEnum.Name(
                        circuitLine.fixedGate))  # get gate class
                qRegList = []
                for qReg in circuitLine.qRegs:  # quantum register lists
                    qRegList.append(qRegsMap[qReg])
                self._circuitOut.append(fixedGateClass._toPB(*qRegList))
            elif circuitLine.HasField('rotationGate'):  # rotation gate
                rotationGateClass = getattr(
                    RotationGate,
                    RotationGateEnum.Name(
                        circuitLine.rotationGate))  # get gate class
                qRegList = []
                for qReg in circuitLine.qRegs:  # quantum register lists
                    qRegList.append(qRegsMap[qReg])
                params = []
                if len(circuitLine.paramIds) > 0:
                    for index, paramId in enumerate(
                            circuitLine.paramIds):  # check procedure params
                        if paramId == -1:
                            params.append(
                                circuitLine.paramValues[index])  # from angles
                        else:
                            params.append(
                                paramValues[paramId])  # from procedure params
                else:
                    params = circuitLine.paramValues

                self._circuitOut.append(
                    rotationGateClass(*params)._toPB(*qRegList))
            elif circuitLine.HasField('customizedGate'):  # customized gate
                raise Error.ParamError('unsupported operation customizedGate')
                # todo it is not implemented
            elif circuitLine.HasField('procedureName'):  # procedure
                qProcedureRegsMap = {
                    index: qRegsMap[qReg]
                    for index, qReg in enumerate(circuitLine.qRegs)
                }

                paramIdsLen = len(circuitLine.paramIds)
                paramValuesLen = len(circuitLine.paramValues)
                procedureParamLen = paramIdsLen if paramIdsLen > paramValuesLen else paramValuesLen
                procedureParamValues = [None] * procedureParamLen
                for i in range(procedureParamLen):
                    if i < paramIdsLen:
                        paramId = circuitLine.paramIds[i]
                        if paramId != -1:
                            procedureParamValues[i] = paramValues[paramId]
                            continue
                    procedureParamValues[i] = circuitLine.paramValues[i]

                procedure = self._procedureMap[circuitLine.procedureName]
                self._unrollProcedure(procedure.circuit, qProcedureRegsMap,
                                      procedureParamValues)
            elif circuitLine.HasField('measure'):  # measure
                if circuitLine.measure.type == PBMeasure.Type.Z:  # only Z measure is supported
                    pass
                else:  # unsupported measure types
                    raise Error.ParamError(
                        f'unsupported operation measure {PBMeasure.Type.Name(circuitLine.measure.type)}'
                    )
                qRegList = []
                for qReg in circuitLine.qRegs:  # quantum register list
                    qRegList.append(qRegsMap[qReg])
                self._circuitOut.append(
                    MeasureZ._toPB(qRegList, circuitLine.measure.cRegs))
            elif circuitLine.HasField('barrier'):  # barrier
                qRegList = []
                for qReg in circuitLine.qRegs:  # quantum register list
                    qRegList.append(qRegsMap[qReg])
                self._circuitOut.append(Barrier()._toPB(*qRegList))
            else:  # unsupported operation
                raise Error.ParamError('unsupported operation')
    def _agentCommit(self, shots, **kwargs):
        """
        Agent commitment

        :return: task result
        """

        if noLocalTask is not None:
            raise Error.RuntimeError(
                'Agent tasks are not allowed in the online environment')

        try:
            self.publish()  # circuit in Protobuf format

            # import the agent plugin according to the backend name
            module = _loadPythonModule(f'QCompute.Agent.{self.backendName}')
            if module is None:
                raise Error.ParamError(
                    f"invalid agent backend => {self.backendName}")
            simulatorClass = getattr(module, 'Backend')

            # configure the parameters
            agent = simulatorClass()
            agent.program = self.program
            agent.shots = shots
            agent.backendParam = self.backendParam
            # execution
            agent.commit()

            # wrap taskResult
            output = agent.result.output
            if agent.result.code != 0:
                return {"status": "error", "reason": output}

            if agent.result.counts:
                cRegCount = max(self.program.head.usingCRegs) + 1
                agent.result.counts = _formatMeasure(agent.result.counts,
                                                     cRegCount)

                originFd, originFn = tempfile.mkstemp(suffix=".json",
                                                      prefix="local.",
                                                      dir="./Output")
                with os.fdopen(originFd, "wt") as fObj:
                    fObj.write(output)
                taskResult = {"status": "success", "origin": originFn}

                if kwargs.get("fetchMeasure", False):
                    taskResult["counts"] = agent.result.counts
                else:
                    measureFd, measureFn = tempfile.mkstemp(suffix=".json",
                                                            prefix="local.",
                                                            dir="./Output")
                    with os.fdopen(measureFd, "wt") as fObj:
                        fObj.write(json.dumps(agent.result.counts))
                    taskResult["measure"] = measureFn

                return taskResult

            return {"status": "failed", "reason": output}
        except Exception:
            raise Error.RuntimeError(traceback.format_exc())
示例#16
0
def core(program, matrixType, algorithm, measureMethod, shots, seed):
    """
    Simulaton process
        Check if the argument is available. The accepted ones are:

        1)DENSE-EINSUM-SINGLE

        2)DENSE-EINSUM-PROB

        3)DENSE-MATMUL-SINGLE

        4)DENSE-MATMUL-PROB

        
    """

    compositeGate = CompositeGate()
    program = compositeGate(program)

    unrollProcedure = UnrollProcedure()
    program = unrollProcedure(program)

    unrollCircuit = UnrollCircuit()
    program = unrollCircuit(
        program
    )  # must unrollProcedure before, because of paramIds to paramValues

    if doCompressGate:
        compressGate = CompressGate()
        program = compressGate(program)

    qRegsMap = {
        qReg: index
        for index, qReg in enumerate(program.head.usingQRegs)
    }
    qRegCount = len(qRegsMap)

    operationDict = {}
    loadGates(matrixType, operationDict)

    if seed is None:
        seed = numpy.random.randint(0, 2147483647 + 1)
    numpy.random.seed(seed)

    state = initState_1_0(matrixType, qRegCount)
    transfer = TransferProcessor(matrixType, algorithm)
    measurer = Measurer(matrixType, algorithm, measureMethod)

    # collect the result to simulator for the subsequent invoking
    result = QuantumResult()
    result.startTimeUtc = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')

    measured = False
    counts = {}
    measuredQRegsToCRegsBidict = bidict()
    for circuitLine in program.body.circuit:  # Traverse the circuit
        if measured and not circuitLine.HasField('measure'):
            raise Error.ParamError('measure must be the last operation')

        qRegs = []
        for qReg in circuitLine.qRegs:
            qRegs.append(qRegsMap[qReg])

        if circuitLine.HasField('fixedGate'):  # fixed gate
            matrix = operationDict.get(circuitLine.fixedGate)
            if matrix is None:
                raise Error.ParamError(
                    f'unsupported operation {FixedGateEnum.Name(circuitLine.fixedGate)}'
                )
            state = transfer(state, matrix, qRegs)
        elif circuitLine.HasField('rotationGate'):  # rotation gate
            if circuitLine.rotationGate != RotationGateEnum.U:
                raise Error.ParamError(
                    f'unsupported operation {RotationGateEnum.Name(circuitLine.rotationGate)}'
                )
            uGate = U(*circuitLine.paramValues)
            if matrixType == MatrixType.Dense:
                matrix = uGate.matrix
            else:
                raise Error.RuntimeError('Not implemented')
            state = transfer(state, matrix, qRegs)
        elif circuitLine.HasField('customizedGate'):  # customized gate
            if matrixType == MatrixType.Dense:
                matrix = _protobufMatrixToNumpyMatrix(
                    circuitLine.customizedGate.matrix)
            else:
                raise Error.RuntimeError('Not implemented')
            state = transfer(state, matrix, qRegs)
        elif circuitLine.HasField('procedureName'):  # procedure
            Error.ParamError(
                'unsupported operation procedure, please flatten by UnrollProcedureModule'
            )
            # it is not implemented, flattened by UnrollProcedureModule
        elif circuitLine.HasField('measure'):  # measure
            if circuitLine.measure.type != PBMeasure.Type.Z:  # only Z measure is supported
                raise Error.ParamError(
                    f'unsupported operation measure {PBMeasure.Type.Name(circuitLine.measure.type)}'
                )
            if not measured:
                counts = measurer(state, shots)
                measured = True
            cRegs = []
            for cReg in circuitLine.measure.cRegs:
                cRegs.append(cReg)
            for i in range(len(cRegs)):
                if measuredQRegsToCRegsBidict.get(qRegs[i]) is not None:
                    raise Error.ParamError('measure must be once on a QReg')
                if measuredQRegsToCRegsBidict.inverse.get(
                        cRegs[i]) is not None:
                    raise Error.ParamError('measure must be once on a CReg')
                measuredQRegsToCRegsBidict[qRegs[i]] = cRegs[i]
        elif circuitLine.HasField('barrier'):  # barrier
            pass
            # unimplemented operation
        else:  # unsupported operation
            raise Error.ParamError('unsupported operation')
    measuredCRegsList = list(measuredQRegsToCRegsBidict.keys())

    result.endTimeUtc = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')
    result.shots = shots
    result.counts = _filterMeasure(counts, measuredCRegsList)
    result.seed = int(seed)
    return result
示例#17
0
    def _compress(self, circuitOut, circuitIn, QRegs):
        """
        Compress the circuit.
        Contract all one-qubit gates into two-qubit gates, and output a circuit with only two-qubit gates.

        :param circuitOut: Output circuit.
        :param circuitIn: Input circuit.
        :param circuitMap: A 'note' of circuitlines, classify the circuitlines by qRegs. A dict with lists as values.
                            In the list, different circuitlines are stored according to the sequence,
                                    and they are marked with different types.
                            str: 'Start' or 'End' mark.
                            int: the index of a one-qubit gate
                            dict: marking a two-qubit gate
                            list: inrelavent operations, and will output directly into circuitOut.
        :param circuitIn_copy: A list constructed by copying circuitlines from circuitIn.
                When a one-qubit gate is contracted into another gate, its position in circuitIn_copy will be None.
                The other position will be a CustomizedGate.
        """
        QRegs = list(QRegs)
        n = len(QRegs)
        circuitMap = dict(zip(QRegs, n*[['Start']]))

        for num, circuitLine in enumerate(circuitIn):  # separate operations in circuitIn and note them in circuitMap
            if circuitLine.HasField('rotationGate') or circuitLine.HasField('fixedGate'):
                if len(circuitLine.qRegs) == 2:
                    qregs = circuitLine.qRegs
                    for i in range(2):
                        twobit_gate = {}
                        twobit_gate['num'] = num
                        twobit_gate['up_or_down'] = i
                        list_tmp = list(circuitMap[qregs[i]])
                        list_tmp.append(twobit_gate)
                        circuitMap[qregs[i]] = list_tmp

                elif len(circuitLine.qRegs) == 1:
                    qregs = circuitLine.qRegs[0]
                    list_tmp = list(circuitMap[qregs])
                    list_tmp.append(num)
                    circuitMap[qregs] = list_tmp

            elif circuitLine.HasField('measure'):
                qregs = circuitLine.qRegs
                for qreg in qregs:
                    list_tmp = list(circuitMap[qreg])
                    list_tmp.append([num])
                    circuitMap[qreg] = list_tmp

            elif circuitLine.HasField('barrier'):
                pass
            else:
                raise Error.ParamError('unsupported operation at compress')

        for key, value in circuitMap.items():
            value.append("End")

        circuitIn_copy = []  # Storage of circuitLines. Copy from circuitIn, revise and then output.
        for circuitLine in circuitIn:
            circuitIn_copy.append(circuitLine)

        for key, value in circuitMap.items():  # separate operations in circuitMap and deal with them
            for tag_num, tag in enumerate(value):
                if type(tag) is int:  # This is a one-qubit gate. Check the next one. If str occurs, check backward.
                    tag_next = value[tag_num+1]
                    if type(tag_next) is int:  # The next one is a one-qubit gate.
                        floating = gate_from_circuitLine(circuitIn_copy[tag])
                        parking = gate_from_circuitLine(circuitIn_copy[tag_next])
                        new_gate_matrix = _contract1_1(matrix_floating=floating, matrix_parking=parking)
                        new_circuitline = CustomizedGate(new_gate_matrix)._toPB(*circuitIn[tag_next].qRegs)
                        circuitIn_copy[tag_next] = new_circuitline
                        circuitIn_copy[tag] = None
                        circuitMap[key][tag_num] = None
                        pass
                    elif type(tag_next) is dict:  # The next one is a two-qubit gate.
                        floating = gate_from_circuitLine(
                            circuitIn_copy[tag])  # Floating describes a gate to be absorbed.
                        parking = gate_from_circuitLine(
                            circuitIn_copy[tag_next['num']])  # Parking describes a gate that will stay there.
                        new_gate_matrix = _contract1_2(matrix_floating=floating, matrix_parking=parking,
                                                       left_or_right=0, up_or_down=tag_next['up_or_down'])
                        new_circuitline = CustomizedGate(new_gate_matrix)._toPB(*circuitIn_copy[tag_next['num']].qRegs)
                        circuitIn_copy[tag_next['num']] = new_circuitline
                        circuitIn_copy[tag] = None
                        circuitMap[key][tag_num] = None
                        pass
                    elif type(tag_next) is str or type(tag_next) is list:  # Blocked. Check backward.
                        tag_bef_num = tag_num - 1
                        while tag_bef_num >= 0:  # Check backward as checking forward, until the very beginning
                                                 # if not interrupted. ('Start', when tag_bef_num==0).
                            tag_bef = value[tag_bef_num]
                            if tag_bef is None:  # No gate here
                                pass
                            elif type(tag_bef) is dict:
                                floating = gate_from_circuitLine(circuitIn_copy[tag])
                                parking = gate_from_circuitLine(circuitIn_copy[tag_bef['num']])
                                new_gate_matrix = _contract1_2(matrix_floating=floating, matrix_parking=parking,
                                                               left_or_right=1, up_or_down=tag_bef['up_or_down'])
                                new_circuitline = CustomizedGate(new_gate_matrix)._toPB(*circuitIn_copy[tag_bef['num']].qRegs)
                                circuitIn_copy[tag_bef['num']] = new_circuitline
                                circuitIn_copy[tag] = None
                                circuitMap[key][tag_num] = None
                                break
                            elif type(tag_bef) is str or list:
                                break
                            else:
                                raise Error.NetworkError('Wrong compression of gate')
                            tag_bef_num -= 1
                    else:
                        raise Error.NetworkError('Wrong construction of circuitMap')
                elif type(tag) is dict or str or list:
                    pass
                else:
                    raise Error.NetworkError('Wrong construction of circuitMap')

        for circuitLine in circuitIn_copy:  # get the compressed gates and other circuitLines
            if circuitLine is not None:
                circuitOut.append(circuitLine)
        return circuitOut