myint = 7
print myint
print type(myint)

"""
Explanation: <p style="text-align:right;color:red;font-weight:bold;font-size:16pt;padding-bottom:20px">Please, rename this notebook before editing!</p>

The Programming Language Python
Introduction
Python is meant to be a simple, readable high-level language that is easily extensible. Well-written python code should be easy for a collaborator to understand, provided they have a good grasp of the python language. 
One of the pitfalls of python is that whitespace matters. In a for/while/if statement, the relevant lines must be indented. This is good for readability, but can cause some hard-to-catch debugging errors!
Python uses dynamic typing. This means that you don't have to declare your variables and types like in C/C++/Java; but that does not mean that you can stop thinking about type. For example, a=3 sets a to an integer (int), while and a=3.0 (or a=3.) makes it a floating-point number (float). Ints and floats are treated differently; for example, in python 2.7, b=3/5 will set b to 0, while b=3./5. will set it to 0.6!
You may find python somewhat quirky to use. Don't worry, you will get used to it, and you will find that it is a very flexible and powerful tool to have.
References
Here are some references to freshen up on concepts:
- Self-paced online tutorials
    - CodeAcademy (13h estimated time) https://www.codecademy.com/tracks/python
    - Brief overview with live examples https://www.learnpython.org/en/Welcome

Books
Python for Everybody (HTML, PDF, Kindle) https://www.py4e.com/book
Python Practice Book http://anandology.com/python-practice-book/index.html
Learning Python (free, requires registration to download) https://www.packtpub.com/packt/free-ebook/learning-python



Python 2 vs Python 3
While there are a number of major differences between the versions the majority of libraries and tools that we are concerned with operate on both. Most changes in Python 3 concern the internal workings and performance. Though, there are some syntax changes, and some operations behave differently. This pages offers a comprehensive look at the key changes: http://sebastianraschka.com/Articles/2014_python_2_3_key_diff.html
We provide both versions on our cluster: the binaries python and python2 for Python 2.7, and python3 for version 3.4.
All assignments are expected to run on Python 2.7
Resources &amp; and Important Links

Official web-site of the Python Software Foundation https://www.python.org/
API Refernce https://docs.python.org/2.7/
StackOverflow https://stackoverflow.com/questions/tagged/python

The following has been adopted from https://www.learnpython.org/
Variables and Types
One of the conveniences and pit-falls is that Python does not require to explicitly declare variables before using them. This is common in many other programming languages. Python is not statically typed, but rather follows the object oriented paradigm. Every variable in Python is an object.
However, the values that variables hold have a designated data type.
This tutorial will go over a few basic types of variables.
Numbers
Python supports two types of numbers - integers and floating point numbers. Basic arithmetic operations yield different results for integers and floats. Special attention needs to be given when mixing values of different types within expressions the results might be unexpected.
To define an integer, use the following syntax:
End of explanation
"""


myfloat = 7.0
print myfloat, type(myfloat)
myfloat = float(42)
print myfloat, type(myfloat)

print 7/2
print 7./2

"""
Explanation: To define a floating point number, you may use one of the following notations:
End of explanation
"""


import math as ma

ma.log10(100)

(numerator, denominator) = 3.5.as_integer_ratio()
print numerator, denominator, numerator/denominator, float(numerator)/float(denominator)

"""
Explanation: Arithmetic operations
We can arithmetic operations that are common in many programing languages.
- +, -, *, /
- // is a special integer division even if the operands aren't
- x**y is used for $x^y$
- n % k calculates the remainder (modulo) of the integer division of n by k
Try it out!
End of explanation
"""


mystring = 'hello'
print(mystring)
mystring = "hello"
print(mystring)

"""
Explanation: Strings
Strings are defined either with a single quote or a double quotes. Many other languages interpret them differently.
End of explanation
"""


mystring = "Don't worry about apostrophes"
print(mystring)

"""
Explanation: The difference between the two is that using double quotes makes it easy to include apostrophes (whereas these would terminate the string if using single quotes)
End of explanation
"""


mystring = 'You still don\'t have to worry about apostrophes'
print(mystring)

"""
Explanation: As a side note, you can use "\" to "escape" special characters. Here's another way to deal with apostrophes:
End of explanation
"""


# Practice adding some strings!

name = 'Joe'
hobby = 'skydiving'

print('Hi, my name is '+name+' and I like '+hobby+'!')

# In-class exercise: 
# Append a line to finish this limmerick, then print it twice!

beginning = """There once was a man named Crocket
Who put his foot in a socket
When along came a witch,
Who turned on the switch,\n""" # "\n" insterts a newline
# source: Jeremy Diamond on http://home.earthlink.net/~kristenaa/nice/lims2f.html

end = "And rattled the change in his pocket.\n\n" # enter a line that rhymes with line 1 

#print (beginning+end)*2
print ("%s%s" % (beginning, end))*2
# your code goes here!

"""
Explanation: Operators
Some the arithmetic operators can be applied to strings, though they have a different interpretation
- + will concatenate two strings
- * multiplies a string with an integer, i.e. the result is that many copies of the original string.
- % has a very special purpose to fill in values into strings
Python provides a large number of operations to manipulate text strings. Examples are given at https://www.tutorialspoint.com/python/python_strings.htm
For the complete documentation refer to https://docs.python.org/2/library/string.html
End of explanation
"""


7./13.

print "The magic number is %.2f!" % (7.0/13.0)

# In-class exercise:
# Define output_str so that calling myadd(3, 5) displays a text "3 plus 5 is 8". 

def myadd(a,b):
    c = a+b
    output_str = "%f plus %f is %f" % (a,b,c) # yay, done!
    print(output_str)
    
myadd(3, 5)

"""
Explanation: String Formatting
Python uses C-style string formatting to create new, formatted strings. The "%" operator is used to format a set of variables enclosed in a "tuple" (a fixed size list), together with a format string, which contains normal text together with "argument specifiers", special symbols like "%s" and "%d".
Some basic argument specifiers you should know:
%s - String (or any object with a string representation, like numbers)
%d - Integers
%f - Floating point numbers
%.&lt;number of digits&gt;f - Floating point numbers with a fixed amount of digits to the right of the dot.
%x/%X - Integers in hex representation (lowercase/uppercase)
End of explanation
"""


mylist = [1, 2, "three", ("a", 7)]
print len(mylist)
print mylist

mylist[3]

mylist[0]

mylist[-2]

mylist + [7]

mylist * 2

"""
Explanation: Lists
Lists are construct for holding multiple objects or values of different types (if this makes sense). We can dynamically add, replace, or remove elements from a list.
Usually we iterate through list in order to perform some operations, though, we can also address a specific element by its position (index) in the list.
The + and * operators work on lists in a similar way as they do on strings. 
Complete documentation at https://docs.python.org/2/tutorial/datastructures.html
End of explanation
"""


x = list(xrange(0,10))
print x

# # One way to get y = 2^x:
x = xrange(0,10)
y1 = []
for element in x:
    y1.append(2**element) # note the indent here! whitespace matters!
print "y1 = "+str(y1)

# a more "pythonic way"
y2 = [2**element for element in x]
print "y2 = "+str(y2)

[(i,j) for i in xrange(1,4) for j in xrange(1,4)]

[ [(i,j) for i in xrange(1,4) ] for j in xrange(1,4)]

# in-class exercise:
# complete the code below to plot y = 3*sin(x/3):

import math as ma
import matplotlib.pyplot as plt
% matplotlib inline

x = xrange(-20,20)
y = [3.*ma.sin(xi/3.) for xi in x] # your code goes here!
plt.plot(x,y)

# plt.plot(*zip(*[(x,3.*ma.sin(x/3.)) for x in xrange(-20,20)]))

"""
Explanation: List Comprehension
List comprehension can be thought of as a more "pythonic" way to loop over a list. It is a technique that comes in handy and is often used.
End of explanation
"""


x = 2
print(x == 2) # prints out True
print(x == 3) # prints out False
print(x <= 3) # prints out True
print(x >= 3) # prints out True

"""
Explanation: Conditions
Python uses boolean variables to evaluate conditions. The boolean values True and False are returned when an expression is compared or evaluated. 
Notice that variable assignment is done using a single equals operator "=", whereas comparison between two variables is done using the double equals operator "==". The "not equals" operator is marked as "!=".
End of explanation
"""


name = "John"
age = 23
if name == "John" and age == 23:
    print("Your name is John, and you are also 23 years old.")
else:
    print("You are not John.")
    
if name == "John" or name == "Rick":
    print("Your name is either John or Rick.")

"""
Explanation: The "and", "or" and "not" boolean operators allow building complex boolean expressions, for example:
End of explanation
"""


name = "John"
if name in ["John", "Rick"]:
    print("Your name is either John or Rick.")

"""
Explanation: The "in" operator could be used to check if a specified object exists within an iterable object container, such as a list:
End of explanation
"""


x = 2
if x == 2:
    print("x equals two!")
else:
    print("x does not equal to two.")

"""
Explanation: Python uses indentation to define code blocks, instead of brackets. The standard Python indentation is 4 spaces, although tabs and any other space size will work, as long as it is consistent. Notice that code blocks do not need any termination.
Here is an example for using Python's "if" statement using code blocks:
if &lt;statement is true&gt;:
    &lt;do something&gt;
    ....
    ....
elif &lt;another statement is true&gt;: # else if
    &lt;do something else&gt;
    ....
    ....
else:
    &lt;do another thing&gt;
    ....
    ....
End of explanation
"""


# In-class exercise:
# Modify the following code to produce a function "is_even" that takes an argument x and prints
# "x is even" if it is even, and "x is not even" otherwise.
# If you call is_even(1), you should see "1 is not even"

def is_even(x):
    if x % 2==0:
        str2 = ""
    else:
        str2 = "not"
    outstr = "%d is %s even" % (x, str2)
    print outstr
    
def is_even2(x)
    print "%d is " % x +("" if x % 2 == 0 else "not ")+"even"
    

is_even(121)
is_even(4)

"""
Explanation: A statement is evaulated as true if one of the following is correct: 
    1. The "True" boolean variable is given, or calculated using an expression, such as an arithmetic comparison. 
    2. An object which is not considered "empty" is passed.
Here are some examples for objects which are considered as empty: 
    1. An empty string: "" 
    2. An empty list: [] 
    3. The number zero: 0 
    4. The false boolean variable: False
End of explanation
"""


for x in ['bob','mary','joe']:
    print x

# Prints out the numbers 0,1,2,3,4
for x in range(5):
    print(x)

print('--------------')

# Prints out 3,4,5
for x in range(3, 6):
    print(x)

print('--------------')
    
# Prints out 3,5,7
for x in range(3, 8, 2):
    print(x)

"""
Explanation: Loops
There are two types of loops in Python, for and while.
The "for" loop
For loops iterate over a given sequence. Here is an example:
    primes = [2, 3, 5, 7]
    for prime in primes:
        print(prime)
For loops can iterate over a sequence of numbers using the range and xrange functions. The difference between range and xrange is that the range function returns a new list with numbers of that specified range, whereas xrange returns an iterator, which is more efficient. (Python 3 uses the range function, which acts like xrange). Note that the range function is zero based.
End of explanation
"""


count = 0
while count < 5:
    print(count)
    count += 1  # This is the same as count = count + 1
    
print 'done!'

## compute the Greatest Common Denominator (GCD)
a = 15
b = 12

while a!=b:
    # put smaller number in a
    (a, b) = (a, b) if a<b else (b, a)
    b = b - a

print "The GCD is %d"%a

def fac(n):
    f = 1
    for m in range(1,n+1):
        f *= m 
    print "%d! is %d" % (n,f)
    
fac(5)

"""
Explanation: "while" loops
While loops repeat as long as a certain boolean condition is met. For example:
End of explanation
"""


# Prints out 0,1,2,3,4

# count = 0
# while True:
#     print(count)
#     count += 1
#     if count >= 5:
#         break

# Prints out only odd numbers - 1,3,5,7,9
for x in range(10):
    # Check if x is even
    if x % 2 == 0:
        continue
    print(x)

"""
Explanation: "break" and "continue" statements
break is used to exit a for loop or a while loop, whereas continue is used to skip the current block, and return to the "for" or "while" statement. A few examples:
End of explanation
"""


# Prints out 0,1,2,3,4 and then it prints "count value reached 5"

count=0
while(count<5):
    print(count)
    count +=1
else:
    print("count value reached %d" %(count))

# Prints out 1,2,3,4
for i in range(1, 10):
    if(i%5==0):
        break
    print(i)
else:
    print("this is not printed because for loop is terminated because of break but not due to fail in condition")

"""
Explanation: can we use "else" clause for loops?
End of explanation
"""


def my_function():
    pass
    print("Hello From My Function!")


my_function()

"""
Explanation: Functions and methods
Functions are a convenient way to divide your code into useful blocks, allowing us to order our code, make it more readable, reuse it and save some time. Also functions are a key way to define interfaces so programmers can share their code.
As we have seen on previous tutorials, Python makes use of blocks.
A block is a area of code of written in the format of:
    block_head:
        1st block line
        2nd block line
Where a block line is more Python code (even another block), and the block head is of the following format: block_keyword block_name(argument1,argument2, ...) Block keywords you already know are "if", "for", and "while".
Functions in python are defined using the block keyword "def", followed with the function's name as the block's name. For example:
End of explanation
"""


def my_function_with_args(username, greeting):
    print("Hello, %s , From My Function!, I wish you %s"%(username, greeting))

my_function_with_args("Peter", "a wonderful day")

"""
Explanation: Functions may also receive arguments (variables passed from the caller to the function). For example:
End of explanation
"""


def sum_two_numbers(a, b=1):
    print "a = "+str(a)
    print "b = "+str(b)
    return a + b

x = sum_two_numbers(b=5,a=19)

x

def my_fun(xi, yi):
    xi[4] = 0
    return yi*2

x = range(10)
y = 2
print x
print y

print "running my_fun"

my_fun(x,y)

print(x)
print(y)

"""
Explanation: Functions may return a value to the caller, using the keyword- 'return' . For example:
End of explanation
"""


def my_function():
    print("Hello From My Function!")

def my_function_with_args(username, greeting):
    print("Hello, %s , From My Function!, I wish you %s"%(username, greeting))

def sum_two_numbers(a, b):
    return a + b

# print(a simple greeting)
my_function()

#prints - "Hello, John Doe, From My Function!, I wish you a great year!"
my_function_with_args("John Doe", "a great year!")

# after this line x will hold the value 3!
x = sum_two_numbers(1,2)

def my_fun2(x):
    return x, x**2, x**3

y1, y2, y3 = my_fun2(5)
print y1
print y2
print y3

"""
Explanation: How to call functions
End of explanation
"""


# Modify this function to return a list of strings as defined above
def list_benefits():
    pass

# Modify this function to concatenate to each benefit - " is a benefit of functions!"
def build_sentence(benefit):
    pass

def name_the_benefits_of_functions():
    list_of_benefits = list_benefits()
    for benefit in list_of_benefits:
        print(build_sentence(benefit))

name_the_benefits_of_functions()

"""
Explanation: In this exercise you'll use an existing function, 
and while adding your own to create a fully functional program.


Add a function named list_benefits() that returns the following list of strings: "More organized code", "More readable code", "Easier code reuse", "Allowing programmers to share and connect code together"


Add a function named build_sentence(info) which receives a single argument containing a string and returns a sentence starting with the given string and ending with the string " is a benefit of functions!"


Run and see all the functions work together!
End of explanation
"""


s = "Hello WORLD"
s.lower()

3.75.as_integer_ratio()

"""
Explanation: Methods
Methods are very similar to functions with the difference that, typically, a method associated with an objects.
End of explanation
"""


# These two lines are critical to using matplotlib within the noteboook
%matplotlib inline
import matplotlib.pyplot as plt

x = range(10)
x

x = [float(i-50)/50.0 for i in range(100)]

# from math import *

y = [ xx**2 for xx in x]
y2 = [xx**3 for xx in x]

plt.plot(x, y, label="x^2")
plt.plot(x, y2, label="x^3")
plt.legend(loc="best")
plt.title("Exponential Functions")
plt.show()

theta = [ ma.pi*0.02*float(t-50) for t in range (100)]
theta[:10]

x = [ma.sin(t) for t in theta]
y = [ma.cos(t) for t in theta]

x,y = zip(*[(ma.sin(t), ma.cos(t)) for t in theta])

plt.figure(figsize=(6,6))
plt.plot(x,y)

"""
Explanation: Hint: while typing in the notebook or at the ipython prompt use the [TAB]-key after adding a "." (period) behind an object to see available methods:

Type the name of an already defined object: s
Add a period "." and hit the [TAB]-key: s.  $\leftarrow$ This should show a list of available methods to a string.


Plotting something

Let's put some of our knowledge about lists and functions to use.
The following examples will create list of values, and then graph them.
We use a module of the Matplotlib library https://matplotlib.org/ The web-site provides detailed documentation and a wealth of examples. 
<img src="https://matplotlib.org/_static/logo2.svg" style="top:5px;width:200px;right:5px;position:absolute" />
End of explanation
"""


%

"""
Explanation: Some Fun
Let's draw a picture of a bear in matplotlib. (Watch on YouTube https://www.youtube.com/watch?v=Jt1fSndR2bY)
End of explanation
"""


