!pip install qiskit

from IPython.display import clear_output
clear_output()

from qiskit import *
import math
import numpy as np
import random
import itertools

teas = ['black', 'green']

mild_spices = ['cardamom (elaichi)', 'fennel seeds (saunf)', 'star anise',  'bay leaves', 'cloves (laung)', 'cinnamon', 'nutmeg', 'saffron (kesar)', 'vanilla bean/extract', 'holy basil (tulsi)']

zesty_spices = [ 'ginger (adrak)', 'black peppercorns', 'white peppercorns',  'cumin seeds (zeera)',  'allspice', 'carom seeds (ajwain)', 'turmeric (haldi)', 'paprika  (lal mirch)']

herbs = ['peppermint', 'lemongrass', 'licorice root', 'chamomile', 'spearmint', 'coriander', 'lavender' ]

misc_flavors = ['orange peel', 'rose petals', 'lemon', 'almond shavings/extract', 'cocoa', 'coconut butter', 'jasmine']



def which_tea():
    # creates the Bell state (|01> + |10>)/sqrt(2) to choose between black and green tea
    circ = QuantumCircuit(2,2) # create a quantum circuit with 2 qubits and 2 classical bits
    circ.h(0) # Hadamard gate on qubit 0
    circ.cx(0,1) # controlled x with qubit 0 as control and qubit 1 as target
    circ.x(0) # x on qubit 0
    circ.measure([0,1],[0,1]) # each qubit is measured, and the total outcome is either 01 or 10
    job = qiskit.execute(circ, qiskit.BasicAer.get_backend('qasm_simulator') ) # run on qasm_simulator
    result = job.result().get_counts() # result is a dict, with key = classical bit outcomes, value = number of counts
    max_res = max(result, key=result.get) # find the result with the highest count
    return teas[int(max_res,2)-1] #convert to decimal

def run_QuantumCirc(n): # creates and runs a quantum circuit with a Hadamard operating on each qubit
    qr = qiskit.QuantumRegister(n) # create quantum register with n qubits
    cr = qiskit.ClassicalRegister(n) # create classical register with n bits
    circ  = qiskit.QuantumCircuit(qr, cr) # create circuit with the two registers
    circ.h(qr) # perform Hadamard  on each qubit
    circ.measure(qr,cr) # each qubit is measured, and the outcome for one qubit is either 0 or 1
    job = qiskit.execute(circ, qiskit.BasicAer.get_backend('qasm_simulator') ) 
    result = job.result().get_counts() 
    return result

def select_ingredients(category): # runs a quantum circuit to select the number of ingredients in a category
    num_choices = len(category)
    if math.log(num_choices,2)%int(math.log(num_choices,2)) == 0: # checks whether log(num_choices) to the base 2 is a whole number
        n = int(math.log(num_choices,2)) # n = number of qubits
        result = run_QuantumCirc(n)
        max_res = max(result, key=result.get) 
    else: 
        n = int(math.log(num_choices,2))+1 # adds 1 to log(N) to the base 2 to get total number of qubits needed
        result = run_QuantumCirc(n)
        max_res = max(result, key=result.get)
        while(int(max_res,2) > num_choices-1): # find max that is less than num_choices
            result.pop(str(max_res))
            max_res = max(result, key=result.get)
    selections = []
    random.shuffle(category) # randomly shuffles the category list
    for i in range(int(max_res,2)+1): # int(max_res,2)+1 is in decimal; it's the number of ingredients in the category that you will be using 
        selections.append(category[i]) # returns the first int(max_res,2)+1 entries in the shuffled list
    return selections

def ingredient_compatibilities(final_ingredients): # removes what I feel are flavor incomptibilities. This is solely my opinion. comment out any you don't agree with!
        if tea == 'green' and 'cocoa' in final_ingredients: 
            final_ingredients.remove('cocoa')
        if tea == 'black' and 'chamomile' in final_ingredients:  
            final_ingredients.remove('chamomile')
        if tea == 'black' and 'jasmine' in final_ingredients: 
            final_ingredients.remove('jasmine')
        if 'paprika' and 'jasmine' in final_ingredients: 
            final_ingredients.remove('jasmine')
        return final_ingredients

def choose_categories(tea): # chooses which ingredient categories your ingredients will come from, we use simple qubit superposition state |0>+|1>
    n = 4 #There are 4 ingredient categories
    categories_dict = {'0': select_ingredients(mild_spices), '1': select_ingredients(herbs), '2': select_ingredients(misc_flavors), '3': select_ingredients(zesty_spices)}
    max_res = '0000'
    final_ingredients = []
    while len(final_ingredients) == 0: # to make sure we don't return an empty list
        while max_res == '0000': # run it until we get SOME ingredients! No one wants 0 ingredients. That'd be utterly boring.
            result = run_QuantumCirc(n)
            max_res = max(result, key=result.get)  
        for ind in range(n):
            if max_res[ind] == '1':
                final_ingredients.append(categories_dict[str(ind)])
    
        final_ingredients = list(itertools.chain.from_iterable(final_ingredients))
        final_ingredients = ingredient_compatibilities(final_ingredients)

    return final_ingredients

tea = which_tea()
print(f"""
Your quantum chai is {tea} tea with the following ingredients:
{choose_categories(tea)}

Happy drinking!""")



