import numpy as np
import torch
import torch
from torch_scatter import scatter
import time


def create_window(event,stacking_type="SBN"):
    windows = []
    num_of_events = event.shape[0] // 3
    equispaced_factor = 1 / 3
    cur_num_of_events = len(event[0])
    windows.append(event)

    if stacking_type == "SBN":
        for i in range(3):
            event_=event[i * num_of_events: (i + 1) * num_of_events,:]
            windows.append(event_.copy())

        # [1/2,1],[3/4,1],[7/8,1]
        for _ in range(3):
            cur_num_of_events = cur_num_of_events // 2
            event=event[cur_num_of_events:,:]
            windows.append(event.copy())

    elif stacking_type == "SBT":
        for i in range(3):
            event_=event[(event[:,2]<=(i + 1) * equispaced_factor)&(event[:,2]>= i * equispaced_factor)]
            windows.append(event_.copy())

        factor = 1
        for _ in range(4):
            factor = factor / 2
            event=event[(event[:,2]<=factor)]
            windows.append(event.copy())

    return windows


def run(src, index,aggregation,height,width):
    if aggregation == "variance":
        event_surface = scatter(
            src=src, index=index, dim_size=height * width, reduce="mean"
        )
        event_surface_squared = scatter(
            src=src ** 2,
            index=index,
            dim_size= height * width,
            reduce="mean",
        )
        result = event_surface_squared - event_surface ** 2
        event_surface = result
    else:
        event_surface = scatter(
            src=src,
            index=index,
            dim_size= height * width,
            reduce= aggregation,
        )
    event_surface = event_surface.reshape(height, width)

    return event_surface

def get_processed_stack_event(window,func,aggregation,height,width):
    index=torch.tensor(window[:,0]+window[:,1]*width,dtype=torch.int64)
    # print("event:{}".format(window[936]))
    # print("index:{}".format(np.where(index>684800)))


    if  func== "timestamp":
        event_surface=run(torch.tensor(window[:,2]), index,aggregation=aggregation,height=height,width=width)
    elif func == "polarity":
        event_surface = run(torch.tensor(window[:,3]), index,aggregation=aggregation,height=height,width=width)
    elif func == "count":
        event_surface = run(
            torch.tensor(window).new_ones([window.shape[0]]), index, aggregation=aggregation,height=height,width=width 
        )
    elif func == "timestamp_pos":
        positive_events = window[window[:, 3] == 1]
        positive_index = torch.tensor(
            positive_events[:, 0] + positive_events[:, 1] * width
        ).to(torch.int64)
        event_surface = run(
            torch.tensor(positive_events[:, 2]), positive_index, aggregation=aggregation,height=height,width=width
        )
    elif func == "timestamp_neg":
        negative_events = window[window[:, 3] == -1]
        if len(list(negative_events)) == 0:
            negative_events = window[window[:, 3] == 0]
        negative_index = torch.tensor(
            negative_events[:, 0] + negative_events[:,1] * width
        ).to(torch.int64)
        event_surface = run(
            torch.tensor(negative_events[:, 2]), negative_index, aggregation=aggregation,height=height,width=width
        )
    elif func == "count_pos":
        positive_events = window[window[:, 3] == 1]
        positive_index = torch.tensor(
            positive_events[:, 0] + positive_events[:, 1] * width
        ).to(torch.int64)
        event_surface = run(
            torch.tensor(positive_events).new_ones([positive_events.shape[0]]),
            positive_index, aggregation=aggregation,height=height,width=width
        )
    elif func == "count_neg":
        negative_events = window[window[:, 3] == -1]
        if len(list(negative_events)) == 0:
            negative_events = window[window[:, 3] == 0]
        negative_index = torch.tensor(
            negative_events[:, 0] + negative_events[:, 1] * width
        ).to(torch.int64)
        event_surface = run(
            torch.tensor(negative_events).new_ones([negative_events.shape[0]]),
            negative_index, aggregation=aggregation,height=height,width=width
        )

    return event_surface

def get_optimized_representation(event,height,width,num_bins):
    
    torch.cuda.synchronize()
    start_time = time.time()
    
    window_indexes = [0, 3, 2, 6, 5, 6, 2, 5, 1, 0, 4, 1]
    functions = [
        "polarity",
        "timestamp_neg",
        "count_neg",
        "polarity",
        "count_pos",
        "count",
        "timestamp_pos",
        "count_neg",
        "timestamp_neg",
        "timestamp_pos",
        "timestamp",
        "count",
    ]
    aggregations = [
        "variance",
        "variance",
        "mean",
        "sum",
        "mean",
        "sum",
        "mean",
        "mean",
        "max",
        "max",
        "max",
        "mean",
    ]


    event[:,2] = event[:,2]-event[0,2]

    delta_t=event[-1,2]-event[0,2]
    if delta_t!=0:
        event[:,2]=event[:,2]/delta_t
    else:
        event[:,2] = event[:,2]

    # event=event[(event[:,0]<width)&(event[:,1]<height)]
    #get event window
    windows=create_window(event)

    # stacked_event_list=[]
    representation=torch.zeros([num_bins,height,width]) 

    for i in range(len(aggregations)):
        stacked_event=get_processed_stack_event(window=windows[window_indexes[i]],func=functions[i],
                                                aggregation=aggregations[i],height=height,width=width)
        representation[i]=stacked_event
    
    
    torch.cuda.synchronize()
    end_time = time.time()

    process_time = end_time - start_time
    print("representation:{}".format(representation.shape))

    return process_time

Based on the above code, I would like to pass in a sheet of .npz data, call the get_optimized_representation function to process it to get the representation, and then visualise the representation. Write out the code for this process.