<jupyter_start><jupyter_text>In this demo, we will experiment with different sets of parameters, and how this affects the number of slots available for SIMD operations, and the serialized size of encrypted inputs.<jupyter_code>import os
if "SHEEP_HOME" in os.environ.keys():
  SHEEP_HOME = os.environ["SHEEP_HOME"]
else:
  print("Please set environment variable SHEEP_HOME to point to the location of SHEEP/frontend")
import sys
sys.path.append(SHEEP_HOME)
from pysheep import sheep_client
from pysheep.database import upload_ciphertext_result
import matplotlib.pyplot as plt
import pandas as pd
sheep_client.new_job()<jupyter_output><empty_output><jupyter_text>Lets use HElib_F2 and vary the BaseParamSet parameter (which in turn chooses pre-set values for other parameters):<jupyter_code>sheep_client.set_context("HElib_F2")
sheep_client.set_input_type("int8_t")
sheep_client.get_parameters()<jupyter_output><empty_output><jupyter_text>With BaseParamSet=0, how many slots for SIMD operations do we get?<jupyter_code>num_slots = sheep_client.get_nslots()['content']['nslots']
num_slots<jupyter_output><empty_output><jupyter_text>And how big is the ciphertext if we encrypt one input (which is a vector of 4 values since we have 4 slots)?<jupyter_code>size=sheep_client.encrypt_and_serialize([1,2,3,4])["content"]["size"]
size<jupyter_output><empty_output><jupyter_text>We can do a scan for HElib, seeing how things vary with the "BaseParamSet" parameter, which in turn chooses a set of preconfigured values for the other parameters.<jupyter_code>for i in range(5):
    try:
        sheep_client.set_parameters({"BaseParamSet": i})
        param_dict = sheep_client.get_parameters()["content"]
        num_slots = sheep_client.get_nslots()['content']['nslots']
        ciphertext_size = sheep_client.encrypt_and_serialize([1,2,3,4])['content']['size']
        upload_ciphertext_result("HElib_F2","int8_t",num_slots, ciphertext_size, param_dict)
    except:
        print("Problem setting BaseParamSet to {}".format(i))
        pass<jupyter_output><empty_output><jupyter_text>Querying the database and plotting resultsThe previous cell should have uploaded some results to the "ciphertext" table in our SQLite database.  We can query this using some SQLAlchemy shortcuts, and put the results into a dataframe<jupyter_code>from pysheep.database import session, CiphertextMeasurement
rows = session.query(CiphertextMeasurement).all()
df_dict = {"context": [], "input_bitwidth": [], "BaseParamSet": [], "nslots": [], "ctsize": []}
for row in rows:
    for param in row.parameters:
        if param.param_name == "BaseParamSet" and param.param_value not in df_dict["BaseParamSet"]:
            df_dict["context"].append(row.context)
            df_dict["input_bitwidth"].append(row.input_bitwidth)
            df_dict["nslots"].append(row.num_slots)
            df_dict["ctsize"].append(row.ciphertext_size)
            df_dict["BaseParamSet"].append(param.param_value)
df = pd.DataFrame(df_dict)
df
axis = plt.subplot(121)
df.plot(ax=axis, use_index=False,x='BaseParamSet', y='nslots',kind='bar',figsize=(15, 5))
axis = plt.subplot(122)
df.plot(ax=axis, use_index=False,x='BaseParamSet', y='ctsize',kind='bar',figsize=(15, 5))
plt.tight_layout()
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25,
                    wspace=0.35)
plt.show()<jupyter_output><empty_output><jupyter_text>Other contextsTFHE and libpaillier by default only offer one slot.   Lets compare their serialized ciphertext sizes:<jupyter_code>for context in ["TFHE","LP"]:
    for input_type in ["bool","int8_t","int16_t","int32_t"]:
        sheep_client.set_context(context)
        sheep_client.set_input_type(input_type)
        param_dict = sheep_client.get_parameters()["content"]
        num_slots = sheep_client.get_nslots()["content"]["nslots"]
        ciphertext_size = sheep_client.encrypt_and_serialize([1])['content']['size']
        upload_ciphertext_result(context,input_type,num_slots, ciphertext_size, param_dict)
    
from sqlalchemy import or_
rows = session.query(CiphertextMeasurement).filter(or_(CiphertextMeasurement.context == 'TFHE', 
                                                       CiphertextMeasurement.context == 'LP')).all()
df_dict = {"context": [], "input_bitwidth": [], "ctsize": []}
for row in rows:
        df_dict["context"].append(row.context)
        df_dict["input_bitwidth"].append(row.input_bitwidth)
        df_dict["ctsize"].append(row.ciphertext_size)
df = pd.DataFrame(df_dict)
df<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11877058177826565, 'fraction_numerical': 0.01163556531284303, 'mean_word_length': 5.354253835425384, 'pattern_counts': {'":': 9, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '600223', 'license': 'MIT', 'n_tokens_mistral': 1527, 'n_tokens_neox': 1486, 'n_words': 319, 'path': 'frontend/notebooks/Parameters_vs_slots_and_serialized_ciphertext_sizes.ipynb', 'repo_name': 'MarbleHE/SHEEP', 'size': '4555'}