示例#1
0
def getNode(data):

    newNode = Node(data)
    newNode.data = data
    newNode.left = None
    newNode.right = None
    return newNode
示例#2
0
    def fit(self, dfForDTree, verbose):

        #INPUT: Training dataset

        #OUTPUT: Trained Decision Tree

        # inizio algo per nodo radice
        returnList = self.findBestSplit(dfForDTree, False)
        indexChosenAttribute = returnList[0]
        attributeValue = returnList[1]
        Dleft = returnList[2]
        Dright = returnList[3]
        self.attributeList.append(int(indexChosenAttribute))
        root = Node(int(indexChosenAttribute))
        numPattern = len(dfForDTree)
        entropy = self.computeEntropy(dfForDTree)

        # memorizzo nel nodo l'attributo, il valore e altre info ottenute dallo split

        nodeInfo = list()
        nodeInfo.append(attributeValue)
        nodeInfo.append(numPattern)
        nodeInfo.append(entropy)
        root.data = nodeInfo

        root.left = Node(int(indexChosenAttribute))
        root.right = Node(int(indexChosenAttribute))

        if (verbose):
            print('DLEFT & DRIGHT INIZIALMENTE')
            print(Dleft)
            print(Dright)

        if (self.useClustering):

            # APPLY K-MEDOIDS FOR DLEFT------------------------------------------------------

            TsIndexLeft = Dleft['TsIndex']  # TsIndex contenute in Dleft

            # Retrieve medoids among all candidates
            CandidatesListLeft = self.OriginalCandidatesListTrain['IdTs'].isin(
                TsIndexLeft
            )  #  setta a True gli indici dei candidati che sono stati generati dalle Ts contenute in Dleft

            CandidateToCluster = self.OriginalCandidatesListTrain[
                CandidatesListLeft]  # estraggo i candidati da OriginalCandidatesListTrain, che sono generati dalle Ts in Dleft

            CandidateToCluster = CandidateToCluster.reset_index(drop=True)

            indexChoosenMedoids = reduceNumberCandidates(
                self, CandidateToCluster, returnOnlyIndex=True
            )  # indici di OriginalCandidatesListTrain conteneti candidati da mantenere

            CandidateToCluster = CandidateToCluster.iloc[indexChoosenMedoids]

            if (verbose):
                print('CANDIDATI RIMASTI IN FIT')
                print(CandidateToCluster)

            # Compute distances btw Ts and chosen medoids
            Dleft = computeSubSeqDistance(self, TsIndexLeft,
                                          CandidateToCluster, self.window_size)

            # APPLY K-MEDOIDS FOR DRIGHT------------------------------------------------------

            TsIndexRight = Dright['TsIndex']  # TsIndex contenute in Dleft

            # Retrieve medoids among all candidates
            CandidatesListRight = self.OriginalCandidatesListTrain['IdTs'].isin(
                TsIndexRight
            )  #  setta a True gli indici dei candidati che sono stati generati dalle Ts contenute in Dright

            CandidateToCluster = self.OriginalCandidatesListTrain[
                CandidatesListRight]  # estraggo i candidati da OriginalCandidatesListTrain, che sono generati dalle Ts in Dleft
            CandidateToCluster = CandidateToCluster.reset_index(drop=True)

            indexChoosenMedoids = reduceNumberCandidates(
                self, CandidateToCluster, returnOnlyIndex=True
            )  # indici di OriginalCandidatesListTrain conteneti candidati da mantenere

            CandidateToCluster = CandidateToCluster.iloc[indexChoosenMedoids]

            if (verbose):
                print('CANDIDATI RIMASTI IN FIT')
                print(CandidateToCluster)

            # Compute distances btw Ts and chosen medoids
            Dright = computeSubSeqDistance(self, TsIndexRight,
                                           CandidateToCluster,
                                           self.window_size)

            if (verbose):
                print('DLEFT & DRIGHT DOPO IL CLUSTERING')
                print(Dleft)
                print(Dright)

        # Recursive call
        if (len(Dleft) > 0):
            self.buildTree(root.left, Dleft, 1, verbose)
        if (len(Dright) > 0):
            self.buildTree(root.right, Dright, 1, verbose)
        Tree.Root = root
    def sample(self, n_shots: int, seed: Optional[int] = None) -> np.ndarray:
        """Sample from the final classical distribution.
        For each sample, will pick a branch for each internal measurement and traverse
        the simulation tree until the end-of-circuit measurements are reached.
        The tree caches the state of the simulation for each branch to reuse for later shots.

        :param n_shots: The number of samples to take
        :type n_shots: int
        :param seed: Seed for the random sampling, defaults to None
        :type seed: Optional[int], optional
        :return: Shot table with each row corresponding to a shot. Columns correspond to Bits in
        decreasing lexicographical order, i.e. [0, 1] corresponds to {Bit(0) : 1, Bit(1) : 0}
        :rtype: np.ndarray
        """
        if seed is not None:
            np.random.seed(seed)
        table = np.zeros((n_shots, len(self.bits)), dtype=int)
        for s in range(n_shots):
            # Uniformly select a random point from the measurement distribution
            point = np.random.uniform(0.0, 1.0)

            # Traverse the tree until we reach the end-of-circuit measurements
            current_node = self.tree
            # The range of values `point` could take to end up in the current node
            current_lower = 0.0
            current_upper = 1.0
            while not isinstance(current_node.data, CompleteNode):
                if isinstance(current_node.data, IncompleteNode):
                    # When at an IncompleteNode, there are no future branches already considered
                    # but we still have computation to simulate on this branch
                    # Simulate new gates until either a mid-circuit measurement
                    # or we reach the end of the internal gates
                    while True:
                        try:
                            next_gate = next(current_node.data.gate_iter)
                        except StopIteration:
                            # There are no more internal gates, so cumulative probabilities for
                            # the final measurements of every qubit
                            cum_probs = (
                                current_node.data.qstate
                                * current_node.data.qstate.conjugate()
                            ).cumsum()
                            current_node.data = CompleteNode(
                                cum_probs, current_node.data.cstate
                            )
                            break

                        # Skip the gate if the classical condition is not met
                        if next_gate.condition:
                            condition_met = True
                            for b, v in next_gate.condition.items():
                                bi = self.bits.index(b)
                                if current_node.data.cstate[bi] != v:
                                    condition_met = False
                                    break
                            if not condition_met:
                                continue

                        if isinstance(next_gate, Rotation):
                            # Apply the rotation to the quantum state and continue to the next gate
                            pauli_tensor = next_gate.qps.to_sparse_matrix(self.qubits)
                            exponent = -0.5 * next_gate.angle
                            current_node.data.qstate = np.cos(
                                exponent
                            ) * current_node.data.qstate + 1j * np.sin(
                                exponent
                            ) * pauli_tensor.dot(
                                current_node.data.qstate
                            )
                        else:
                            # Otherwise, we have a measurement
                            # Compute the states after a 0-outcome and a 1-outcome and make a branch

                            # Project into measurement subspaces
                            identity = QubitPauliString().to_sparse_matrix(self.qubits)
                            z_op = QubitPauliString(
                                next_gate.qubit, Pauli.Z
                            ).to_sparse_matrix(self.qubits)
                            zero_proj = 0.5 * (identity + z_op)
                            one_proj = 0.5 * (identity - z_op)
                            zero_state = zero_proj.dot(current_node.data.qstate)
                            one_state = one_proj.dot(current_node.data.qstate)

                            # Find probability of measurement and normalise
                            zero_prob = np.vdot(zero_state, zero_state)
                            if zero_prob >= 1e-10:  # Prevent divide-by-zero errors
                                zero_state *= 1 / np.sqrt(zero_prob)
                            if 1 - zero_prob >= 1e-10:
                                one_state *= 1 / np.sqrt(1 - zero_prob)

                            # Update the classical state for each outcome
                            bit_index = self.bits.index(next_gate.bit)
                            zero_cstate = copy(current_node.data.cstate)
                            zero_cstate[bit_index] = 0
                            one_cstate = current_node.data.cstate
                            one_cstate[bit_index] = 1

                            # Replace current node in the tree by a branch, with each outcome as children
                            zero_node = Node(0)
                            zero_node.data = IncompleteNode(
                                zero_state,
                                zero_cstate,
                                copy(current_node.data.gate_iter),
                            )
                            one_node = Node(0)
                            one_node.data = IncompleteNode(
                                one_state, one_cstate, current_node.data.gate_iter
                            )
                            current_node.data = InternalNode(zero_prob)
                            current_node.left = zero_node
                            current_node.right = one_node
                            break
                else:
                    # Reached an internal measurement, so randomly pick a branch to traverse
                    current_decision = (
                        current_lower
                        + (current_upper - current_lower) * current_node.data.zero_prob
                    )
                    if point < current_decision:
                        current_node = current_node.left
                        current_upper = current_decision
                    else:
                        current_node = current_node.right
                        current_lower = current_decision
            # Finally reached the end of the circuit
            # Randomly sample from the final measurements
            index = np.searchsorted(
                current_node.data.cum_probs, point / (current_upper - current_lower)
            )
            bitstring = bin(index)[2:].zfill(len(self.qubits))

            # Update the classical state with final measurement outcomes
            table[s] = current_node.data.cstate
            for g in self.end_measures:
                if g.condition:
                    # If final measurements are conditioned, the classical state may not be updated
                    condition_met = True
                    for b, v in g.condition.items():
                        bi = self.bits.index(b)
                        if current_node.data.cstate[bi] != v:
                            condition_met = False
                            break
                    if not condition_met:
                        continue
                qi = self.qubits.index(g.qubit)
                bi = self.bits.index(g.bit)
                table[s, bi] = int(bitstring[qi])
        return table