In [1]:
import numpy as np
In [2]:
# %%
class QSVCWineClassifier:
    """Quantum Support Vector Classifier for wine quality classification"""
    
    def __init__(self, num_features=4, feature_map='ZZ', reps=2):
        self.num_features = num_features
        self.reps = reps
        self.feature_map_type = feature_map
        self.model = None
        self.quantum_kernel = None
        self.scaler = StandardScaler()
        self.label_encoder = LabelEncoder()
        self.pca = PCA(n_components=num_features)
        self.original_features = 11  # Number of original features
        
        # Quantum components
        self.feature_map = None
        self.sampler = Sampler()
        
        self._setup_quantum_components()
        print(f"QSVC classifier initialized with {num_features} features")
    
    def predict(self, X):
        """Prediction using QSVC or VQC"""
        if self.model is None:
            raise ValueError("Model is not trained! Call fit() first.")
        
        # If we have 11 features (original), transform them
        if X.shape[1] == self.original_features:
            X_scaled = self.scaler.transform(X)
            X_reduced = self.pca.transform(X_scaled)
        else:
            X_reduced = X
        
        y_pred_encoded = self.model.predict(X_reduced)
        
        # Ensure correct format
        y_pred_encoded = np.atleast_1d(y_pred_encoded)
        
        # Clip predictions to valid class range
        y_pred_encoded = np.clip(y_pred_encoded, 0, len(self.label_encoder.classes_) - 1)
        
        try:
            y_pred = self.label_encoder.inverse_transform(y_pred_encoded.astype(int))
        except ValueError as e:
            print(f"Warning: Prediction issue - {e}")
            # Fallback - return most frequent class
            y_pred = np.array([self.label_encoder.classes_[0]])
        
        return y_pred
    
    def score(self, X, y):
        """Calculate accuracy score"""
        y_pred = self.predict(X)
        return accuracy_score(y, y_pred)
In [3]:
import pickle
import ipywidgets as widgets
from IPython.display import display, clear_output
import warnings
warnings.filterwarnings('ignore')

print("Loading model...")

# Load model
loaded_qwc = None
try:
    with open('qsvc_wine_model.pkl', 'rb') as f:
        loaded_data = pickle.load(f)
    loaded_qwc = loaded_data['quantum_classifier']
    print("Model successfully loaded!")
except FileNotFoundError:
    print("File 'qsvc_wine_model.pkl' not found!")
except Exception as e:
    print(f"Error loading model: {e}")

print()
print("=" * 50)
print("     WINE QUALITY CLASSIFIER")  
print("=" * 50)
print()

# Create sliders
fixed_acidity_slider = widgets.FloatSlider(
    value=7.4, min=4.6, max=15.0, step=0.1,
    description='Fixed Acidity (g/L):',
    style={'description_width': '170px'}
)

volatile_acidity_slider = widgets.FloatSlider(
    value=0.7, min=0.21, max=1.33, step=0.01,
    description='Volatile Acidity (g/L):',
    style={'description_width': '170px'}
)

citric_acid_slider = widgets.FloatSlider(
    value=0.0, min=0.0, max=1.0, step=0.01,
    description='Citric Acid (g/L):',
    style={'description_width': '170px'}
)

residual_sugar_slider = widgets.FloatSlider(
    value=1.9, min=1.2, max=10.7, step=0.1,
    description='Residual Sugar (g/L):',
    style={'description_width': '170px'}
)

chlorides_slider = widgets.FloatSlider(
    value=0.076, min=0.039, max=0.610, step=0.001,
    description='Chlorides (g/L):',
    style={'description_width': '170px'}
)

free_sulfur_dioxide_slider = widgets.FloatSlider(
    value=11.0, min=3.0, max=52.0, step=1.0,
    description='Free SO₂ (mg/L):',
    style={'description_width': '170px'}
)

total_sulfur_dioxide_slider = widgets.FloatSlider(
    value=34.0, min=8.0, max=153.0, step=1.0,
    description='Total SO₂ (mg/L):',
    style={'description_width': '170px'}
)

density_slider = widgets.FloatSlider(
    value=0.9978, min=0.992, max=1.000, step=0.0001,
    description='Density (g/cm³):',
    style={'description_width': '170px'}
)

pH_slider = widgets.FloatSlider(
    value=3.51, min=2.74, max=3.90, step=0.01,
    description='pH (-):',
    style={'description_width': '170px'}
)

sulphates_slider = widgets.FloatSlider(
    value=0.56, min=0.33, max=2.0, step=0.01,
    description='Sulphates (g/L):',
    style={'description_width': '170px'}
)

alcohol_slider = widgets.FloatSlider(
    value=12.0, min=9.0, max=14.0, step=0.1,
    description='Alcohol (% vol):',
    style={'description_width': '170px'}
)

# Buttons
predict_button = widgets.Button(
    description='Evaluate Wine Quality',
    button_style='danger',
    layout=widgets.Layout(width='200px', height='40px')
)

reset_button = widgets.Button(
    description='Reset to Default',
    button_style='info',
    layout=widgets.Layout(width='150px', height='40px')
)

# Output for results
output = widgets.Output()

def predict_wine_quality(button):
    """Function for wine quality prediction"""
    with output:
        clear_output(wait=True)
        
        if loaded_qwc is None:
            print("Model is not loaded!")
            return
        
        # Get values from all sliders
        test_sample = [
            fixed_acidity_slider.value,
            volatile_acidity_slider.value,
            citric_acid_slider.value,
            residual_sugar_slider.value,
            chlorides_slider.value,
            free_sulfur_dioxide_slider.value,
            total_sulfur_dioxide_slider.value,
            density_slider.value,
            pH_slider.value,
            sulphates_slider.value,
            alcohol_slider.value
        ]
        
        try:
            # Prediction
            prediction = loaded_qwc.predict(np.array([test_sample]))
            quality_score = prediction[0]
            
            print("=" * 50)
            print(f"   WINE QUALITY: {quality_score} points")
            
            # Interpretation
            if quality_score >= 8:
                print("   EXCELLENT QUALITY!")
                rating = "★★★★★"
                desc = "This wine is truly exceptional!"
            elif quality_score >= 7:
                print("   VERY GOOD QUALITY!")
                rating = "★★★★☆"
                desc = "High-quality wine with excellent characteristics"
            elif quality_score >= 6:
                print("   GOOD QUALITY")
                rating = "★★★☆☆"
                desc = "Solid wine with pleasant properties"
            elif quality_score >= 5:
                print("   AVERAGE QUALITY")
                rating = "★★☆☆☆"
                desc = "Standard wine for everyday consumption"
            elif quality_score >= 4:
                print("   BELOW AVERAGE QUALITY")
                rating = "★☆☆☆☆"
                desc = "Wine with some deficiencies"
            else:
                print("   POOR QUALITY")
                rating = "☆☆☆☆☆"
                desc = "Wine with significant problems"
            
            print(f"   {rating}")
            print(f"   {desc}")
            print("=" * 50)
            
            print()
            print("Input parameters:")
            print(f"  Fixed Acidity: {test_sample[0]:.2f}")
            print(f"  Volatile Acidity: {test_sample[1]:.3f}")
            print(f"  Citric Acid: {test_sample[2]:.3f}")
            print(f"  Residual Sugar: {test_sample[3]:.1f}")
            print(f"  Chlorides: {test_sample[4]:.3f}")
            print(f"  Free SO₂: {test_sample[5]:.0f}")
            print(f"  Total SO₂: {test_sample[6]:.0f}")
            print(f"  Density: {test_sample[7]:.4f}")
            print(f"  pH: {test_sample[8]:.2f}")
            print(f"  Sulphates: {test_sample[9]:.2f}")
            print(f"  Alcohol: {test_sample[10]:.1f}%")
            
        except Exception as e:
            print(f"ERROR: {e}")

def reset_values(button):
    """Reset to original values"""
    with output:
        clear_output(wait=True)
        print("Resetting to default values...")
    
    # Set original values from test_sample
    fixed_acidity_slider.value = 7.4
    volatile_acidity_slider.value = 0.7
    citric_acid_slider.value = 0.0
    residual_sugar_slider.value = 1.9
    chlorides_slider.value = 0.076
    free_sulfur_dioxide_slider.value = 11.0
    total_sulfur_dioxide_slider.value = 34.0
    density_slider.value = 0.9978
    pH_slider.value = 3.51
    sulphates_slider.value = 0.56
    alcohol_slider.value = 12.0

# Connect functions to buttons
predict_button.on_click(predict_wine_quality)
reset_button.on_click(reset_values)

# Display interface
print("Set parameters and click 'Evaluate Wine Quality':")
print()

# Display sliders in groups
print("Acidity:")
display(fixed_acidity_slider)
display(volatile_acidity_slider)
display(citric_acid_slider)
display(pH_slider)

print()
print("Sugar and Salts:")
display(residual_sugar_slider)
display(chlorides_slider)
display(sulphates_slider)

print()
print("Sulfur Dioxide:")
display(free_sulfur_dioxide_slider)
display(total_sulfur_dioxide_slider)

print()
print("Physical Properties:")
display(density_slider)
display(alcohol_slider)

print()
print("Controls:")
display(widgets.HBox([predict_button, reset_button]))

print()
print("Results:")
display(output)

# Initial message
with output:
    print("Wine classifier is ready!")
    print("Adjust slider values and click 'Evaluate Wine Quality'")
    if loaded_qwc is not None:
        print("Model is loaded and functional")
    else:
        print("WARNING: Model was not loaded!")

print()
print("Wine classifier is ready to use!")
Loading model...
Model successfully loaded!

==================================================
     WINE QUALITY CLASSIFIER
==================================================

Set parameters and click 'Evaluate Wine Quality':

Acidity:
FloatSlider(value=7.4, description='Fixed Acidity (g/L):', max=15.0, min=4.6, style=SliderStyle(description_wi…
FloatSlider(value=0.7, description='Volatile Acidity (g/L):', max=1.33, min=0.21, step=0.01, style=SliderStyle…
FloatSlider(value=0.0, description='Citric Acid (g/L):', max=1.0, step=0.01, style=SliderStyle(description_wid…
FloatSlider(value=3.51, description='pH (-):', max=3.9, min=2.74, step=0.01, style=SliderStyle(description_wid…
Sugar and Salts:
FloatSlider(value=1.9, description='Residual Sugar (g/L):', max=10.7, min=1.2, style=SliderStyle(description_w…
FloatSlider(value=0.076, description='Chlorides (g/L):', max=0.61, min=0.039, step=0.001, style=SliderStyle(de…
FloatSlider(value=0.56, description='Sulphates (g/L):', max=2.0, min=0.33, step=0.01, style=SliderStyle(descri…
Sulfur Dioxide:
FloatSlider(value=11.0, description='Free SO₂ (mg/L):', max=52.0, min=3.0, step=1.0, style=SliderStyle(descrip…
FloatSlider(value=34.0, description='Total SO₂ (mg/L):', max=153.0, min=8.0, step=1.0, style=SliderStyle(descr…
Physical Properties:
FloatSlider(value=0.9978, description='Density (g/cm³):', max=1.0, min=0.992, step=0.0001, style=SliderStyle(d…
FloatSlider(value=12.0, description='Alcohol (% vol):', max=14.0, min=9.0, style=SliderStyle(description_width…
Controls:
HBox(children=(Button(button_style='danger', description='Evaluate Wine Quality', layout=Layout(height='40px',…
Results:
Output()
Wine classifier is ready to use!
In [5]:
#with ipywidgets like this
from IPython.display import Image
Image(url='https://raw.githubusercontent.com/bluemoondom/quantum_qsvc_train_red_wine_classifier/refs/heads/main/wine_classifier.png')
Out[5]:
No description has been provided for this image
In [ ]: