def evaluateAccuracy(data: list, network: LSTM, seq_length: int, sign_to_int):
    #network.eval()

    hidden = network.initHidden()
    memory = network.initMemory()
    hidden = hidden.to(device)
    memory = memory.to(device)
    print(len(data))
    right = 0
    total = 0

    with torch.no_grad():
        for i in range(0, len(data), seq_length):
            in_seq = convert_to_one_hot_matrix(data[i:i + seq_length],
                                               sign_to_int)
            out_seq = target_tensor(data[i + 1:i + seq_length + 1],
                                    sign_to_int)
            in_seq = in_seq.to(device)
            out_seq = out_seq.to(device)
            out_seq.unsqueeze_(-1)
            if i % 100000 == 0:
                print(i)
            for j in range(out_seq.size()[0]):
                output, hidden, memory = network(in_seq[j], hidden, memory)
                _, guess = output.max(1)
                if guess == out_seq[j]:
                    right = right + 1
                total = total + 1
        print("finished eval loop")
        print(total)
        print(right)
        res = right / total
        print("finished calculating accuracy")
        print(res)
    return
def synthesize_notes(network: LSTM, inputs, n: int, sign_to_int: dict,
                     int_to_sign: dict):
    seq = []
    hidden = network.initHidden()
    memory = network.initMemory()
    inputs = convert_to_one_hot_matrix([inputs] * 2, sign_to_int)

    with torch.no_grad():
        for i in range(n):
            p, hidden, memory = network(inputs, hidden, memory)

            p = p.numpy()[0][0][:]

            ind = np.random.choice((p.shape[0]), 1, p=p / sum(p))[0]
            inputs = torch.zeros(1, 1, len(sign_to_int))
            inputs[0][0][ind] = 1

            seq.append(int_to_sign[str(ind)])

    return seq
def train(network: LSTM, criterion, input_seq, follow_seq,
          optimizer: optim.Optimizer, scheduler):
    follow_seq.unsqueeze_(-1)
    hidden = network.initHidden()
    memory = network.initMemory()
    hidden = hidden.to(device)
    memory = memory.to(device)
    loss = 0

    network.zero_grad()
    for i in range(input_seq.size()[0]):
        output, hidden, memory = network(input_seq[i], hidden, memory)
        l = criterion(output, follow_seq[i])
        #TODO: smooth loss here
        loss += l

    loss.backward()

    optimizer.step()
    scheduler.step()

    return output, loss.item() / input_seq.size()[0]