# -*- coding: iso-8859-15 -*-


from __future__ import division  # want 3 / 2 == 1.5
import re
import math
import random  # regexes, math functions, random numbers
import matplotlib.pyplot as plt  # pyplot
from collections import defaultdict, Counter
from functools import partial


v = [1, 2]
w = [2, 1]


def vector_add(v, w):
    """ Soma elementos correspondentes """
    return [v_i + w_i for v_i, w_i in zip(v, w)]


def vector_subtract(v, w):
    """ Subtrai elementos correspondentes """
    return [v_i - w_i for v_i, w_i in zip(v, w)]


def vector_sum(vectors):
    """ Soma todos os elementos correspondentes """
    result = vectors[0]
    for vector in vectors[1:]:
        result = vector_add(result, vector)
    return result


def vector_sum2(vectors):
    return reduce(vector_add, vectors)


def scalar_multiply(c, v):
    """ c eh um numero, v eh um vetor """
    return [c * v_i for v_i in v]


def vector_mean(vectors):
    """ computar o vetor cujo i-esimo elemento seja a media dos 
    i-esimos elementos dos vetores inclusos """
    n = len(vectors)
    return scalar_multiply(1/n, vector_sum(vectors))


def dot(v, w):
    """ v_1 * w_1 + ... + v_n * w_n 
    Produto escalar: soma de sues produtos componente a componente.
    Mede a distancia a qual o vetor v se estende na direcao de w """
    return sum(v_i * w_i for v_i, w_i in zip(v, w))


def sum_of_squares(v):
    """ v_1 * v_1 + ... + v_n * v_n 
    Soma dos quadrados de um vetor """
    return dot(v, v)


def magnitude(v):
    return math.sqrt(sum_of_squares(v))


def squared_distance(v, w):
    """ (v_i - w_i) ** 2 + ... + (v_n - w_n) ** 2"""
    return sum_of_squares(vector_subtract(v, w))


def distance(v, w):
    return math.sqrt(squared_distance(v, w))


def distance2(v, w):
    return magnitude(vector_subtract(v, w))


def shape(A):
    num_rows = len(A)
    num_cols = len(A[0]) if A else 0  # n de elementos da primeira linha
    return num_rows, num_cols


def get_row(A, i):
    return A[i]


def get_column(A, j):
    return [A_i[j] for A_i in A]


def make_matrix(num_rows, num_cols, entry_fn):
    """ retorna a matriz num_rows X num_cols
    cuja entrada (i, j)th eh entry_fn(i, j) """
    return [[entry_fn(i, j)  # dato i, cria uma lista
             for j in range(num_cols)]  # [entry_fn(i, 0), ...]
            for i in range(num_rows)]  # cria uma lista para cada i

def is_diagonal(i, j):
    """ 1's na diagonal, 0's nos demais lugares """
    return 1 if i == j else 0

def make_graph_dot_product_as_vector_projection(plt):

    v = [2, 1]
    w = [math.sqrt(.25), math.sqrt(.75)]
    c = dot(v, w)
    vonw = scalar_multiply(c, w)
    o = [0, 0]

    plt.arrow(0, 0, v[0], v[1],
              width=0.002, head_width=.1, length_includes_head=True)
    plt.annotate("v", v, xytext=[v[0] + 0.1, v[1]])
    plt.arrow(0, 0, w[0], w[1],
              width=0.002, head_width=.1, length_includes_head=True)
    plt.annotate("w", w, xytext=[w[0] - 0.1, w[1]])
    plt.arrow(0, 0, vonw[0], vonw[1], length_includes_head=True)
    plt.annotate(u"(v•w)w", vonw, xytext=[vonw[0] - 0.1, vonw[1] + 0.1])
    plt.arrow(v[0], v[1], vonw[0] - v[0], vonw[1] - v[1],
              linestyle='dotted', length_includes_head=True)
    plt.scatter(*zip(v, w, o), marker='.')
    plt.axis('equal')
    plt.show()


print(vector_add(v, w))
print(vector_subtract(v, w))
print(scalar_multiply(2, v))
print(dot(v, w))

make_graph_dot_product_as_vector_projection(plt)
