<jupyter_start><jupyter_text>0. Python WorkshopWelcome to the HumanEd Python workshop!If you have any questions, please let us know and we will try to help.Here are some additional useful resources:- https://learnxinyminutes.com/docs/python/- https://www.w3schools.com/python/  1. Basic TypesPython supports many data types. In this section you will get familiar with the basic data types within python. 1.1 NumbersIn python numbers can be stored in different formats:1. Integers2. Floats (Decimal numbers)3. Complex numbersAll these types support various operations: addition (+), subtraction (-), multiplication (*), division (/), etc.<jupyter_code>5 # Example of an integer in python
5.5 # Example of a float in python
5+5j # Example of a complex number in python
# Here we present some examples of how calculations are performed in python, the print() function is used
# to display the result
print(5 + 5.2)     # Addition
print(5 * (2+3j))  # Multiplication
print(5 / 2.5)     # Division
print(7 // 2)      # Integer division
print(14 % 3)      # Modulo
print(2 ** 4)      # Exponential<jupyter_output><empty_output><jupyter_text>Exercise 1Up to this point we have used python as if it was a basic calculator. The first exercise consists on computing the time that a ball takes to fall 30 metres. Assume no air resistance, g = 9.8 and the initial velocity of the ball is zero.Remember to print your result in the screen using print(result) where result is the number that you got.<jupyter_code>#Your code goes here, when you complete the exercise deleat the raise NotImplementedError statement to run the code
raise NotImplementedError<jupyter_output><empty_output><jupyter_text>1.2 BooleansThis type can only take two values, False or True. It's the type used for logic operations.This type supports different operations:1. and2. or3. notAdditionally, operations of different types can give booleans as result:1. Equality operator (==)2. Not equal operator (!=)3. Greater than operator (>)4. Less than operator (<)5. Greater than or equal operator (>=)6. Less than or equal operator (<=)<jupyter_code>print(True and True)        # And operator
print(True and False)       # And operator
print(not(True) or False)   # Or, not operators
print(2 == 3)               # Equality operator
print(2 != 3)               # Not equal operator
print(2 < 3)                # Less than operator
print(3 <= 3)               # Less than or equal operator<jupyter_output><empty_output><jupyter_text>Exercise 2Try to evalate the following expression in your head and code it in python to test your solution:$$(\neg(\top \lor \bot))\lor(\neg(\top \land \bot))$$<jupyter_code>#Your code goes here, when you complete the exercise deleat the raise NotImplementedError statement to run the code
raise NotImplementedError<jupyter_output><empty_output><jupyter_text>1.3 StringsIn python strings represent words and sentences. Each string is made up from a collection of ordered characters. For example, the string "Hello" is composed of the characters 'H','e','l','l','o'. Each of these characters has a position in the string ('H' is in position 0, 'e' in position 1 and so on).Strings can be enclosed in single or double quotes 'Hello' or "Hello" are the same thing.They support different operators:1. (+) for concatenation2. (*) for repeteition3. ([i]) for accessing individual characters of the string.Strings are immutable. This means that they cannot be modified once they are created. Trying to modify a substring results in an error.This means that the code "Hello"[0] = 'k' will give an error (you can try this yourself).<jupyter_code>print('Hello ' + 'world' + '!!!')              # Strings can be concatenated using the (+) operator

print('Hello World 5 times '*5)                # Strings can be repeated multiple times using the (*) operator

print('This is a very long sentence'[15:19])   # You can extract substrings using slices ([i:j]).
                                               # This extracts the substring starting at i and ending at j-1.
                                               # Remember that the index starts at 0.<jupyter_output><empty_output><jupyter_text>1.4 ListsThere are different types of compound structures in Python. The most versatile is the list.This type allows you to store together different types and objects in one structure.Like strings, list items can also be accessed using indices. Similarly, they can be sliced and concatenated. This is because both strings and lists (and tuples and a few others we will notmention here) are what Python calls sequence types.Operations like verifying membership, concatenation, indexing, slicing and measuring the length of asequence can be performed on any sequence type.Unlike strings, lists are mutable. Items can be added at the end of a list usingthe .append(item) method of the list object.<jupyter_code>print(['Monday','Tuesday','Wednesday','Thursday','Friday']) # A simple list of strings 
print(['Monday', 2.3, True, 4, [[2,3], [4,5]]])             # Lists in python can contain elements of multiple types
print([0,1,2,3,4][1])                                       # Access an individual element
print([0,1,2,3,4][1:4])                                     # Extract the sublist starting at position 1 and ending at position 3
print([0,1,2,3,4][1:])                                      # Extract the sublist starting at position 1
print([0,1,2,3,4][-1:])                                     # Try to figure out what this means
print([0,1,2,3,4][:3])                                      # Extract the sublist ending at position 2
print([0,1] + [2,3,4])                                      # Lists can be concatenated using the (+) operator
print(2 in [1,2,3])                                         # You can check if an element is in an array using the (in) operator<jupyter_output><empty_output><jupyter_text>2. Variables and Functions 2.1 Variables:So far we have just used python as an interpreter but that is of no real use, let's say that at one point we perform a difficult calculation and then we want to use it again and again over our code. It makes little sense to perform that calculation over and over again. That's why variables exist. basically a variable is a way of referencing an object that is stored in memory.In python it is very easy to declare a variable, let's say that we want to create a variable x that holds the value 5, then we can just say x = 5. Now if we want to get the value of x we can just call print(x).<jupyter_code>x = 5
print(x)
x = [0,1,2,3]
y = 99
x[3] = y   # We can perform operations with variables as we would expect
print(x)<jupyter_output><empty_output><jupyter_text>2.2 Functions:The mathematical definition of a function holds for python. A function is just a mathematical object that takes some input variables (x,y,...) and returns a new value. Functions are essential in programming as they allow you to structure your code. So far we have been writting everything outside functions, this is not a good practice. For example consider the exercise 1, let's say that you want to compute the time that the ball took to fall a height of h (instead of 30). If you wanted to do it for many h's then without functions you would need to repeat the code over and over again. With functions, you can make one general function that takes an input h and that returns the time for that h.An example of how to define and call a function in python is given below<jupyter_code>def my_addition(x,y):    # Function header - defines the function name and the input variables
    result = x + y       # Function body - contains all the operations performed by the function 
    return result        # Function output - specifies the output of the function

print(my_addition(5,5))<jupyter_output><empty_output><jupyter_text>Exercise 3Write a function that solves the problem of exercise 1 for any given height h<jupyter_code>#Your code goes here, when you complete the exercise deleat the raise NotImplementedError statement to run the code
raise NotImplementedError<jupyter_output><empty_output><jupyter_text>Exercise 4Write a Python program to calculate radius of a sphere given its volume (V) in $\text{metres}^3$.To represent the number pi use math.pi. A useful function is math.pow(x,n) that computes $x^n$ even if n is rational<jupyter_code>import math
#Your code goes here, when you complete the exercise deleat the raise NotImplementedError statement to run the code
raise NotImplementedError<jupyter_output><empty_output><jupyter_text>3. Conditional StatementsIn order to start making a computer program do more than simple pre-determined calculations we have to introduce the idea of conditional statements. These make the execution path though the code depend on the values of the variables. This is called Flow Control and is the first real step in programming. The general structure of a conditional statement is as follows:```pythonif condition:    code```where condition is an expression that evaluates to a boolean (either true or false). If the condition is false then code is not executed (those line are ignored), while if the condition is true then code is executed.If statements are usually used in combination of else statements:```pythonif condition:    codeelse:    other_code```In this case the first part is exaclty the same as before, if the condition is false it won't execute code and it it is true it will; however other_code will only be executed if code is not executed. Basically if the condition is not true, then Python won't go inside the if statement but will go into the else statement.Some times we want to check for multiple conditions we can do:```pythonif condition_one and condition_two:    codeelse:    other_code```and so on.Maybe we want to do different things for different conditions, then we have two possibilities: either we want to check each condition independently and do one thing for each condition (example 1), or we want only to check the different conditionals if the one before hasn't been met (example 2):Example 1:```pythonif condition_one:    code_oneif condition_two:    code_twoif condition_three:    code_threeif condition_four:    code_four```In this case, python will check condition_one, if it is met it will execute code_one, and if it is not met it will not execute code_one. Then, independenlty of the evaluation of condition_one, it will check condition two and if it's met then it will execute code_two and so on for the different if's. Note that each if statement could be accompanied with an else statement that executes some code_i if condition_i is not met.Example 2:```pythonif condition_one:    code_oneelif condition_two:    code_twoelif condition_three:    code_threeelif condition_four:    code_fourelse:    code_five```In this case python will check if condition_one is True or False, if it is true then it will execute code_one and that's it, it will not execute any other code_i no matter if condition_i is true. However, if condition_one is not true it will check condition_two and if it is true then it will execute code_two and that's it. This will go on until it finds some condition that is true or until it reaches the else statement (it will run code_five if and only if all the previous conditions have not been met). Note that if the else statement was omited, the code will just go on if none of the conditions are met. Also, note that you cannot include an else statement associated to an elif statement. This syntax is known as nested conditionals and the name elif comes from the contraction of else and if.<jupyter_code>import random               # Allows us to use the functionalities in the random library
x = random.randint(0,10)    # Generates a random number between 0 and 10
y = random.randint(0,10)    # Generates a random number between 0 and 10

if x > y:
  print('x is greater than y')
elif x < y:
  print('x is less than y')
else:
  print('x is equal to y')<jupyter_output><empty_output><jupyter_text>Exercise 5Write a Python function that takes three arguments a,b,c as parameters and returns the solution(s) of the equation:$$ax^2+bx+c=0$$The program is expected to deal with conditions of    1. two real roots    2. two complex roots    3. single real rootReturn the solution as a list<jupyter_code>#Your code goes here, when you complete the exercise deleat the raise NotImplementedError statement to run the code
raise NotImplementedError<jupyter_output><empty_output><jupyter_text>4. For LoopThe For Loop is a control flow statement used to iterate over lists (or other kinds of sequences). The general structure of a for loop is as follows:```pythonx = [1,2,3,4,5]for i in x:    print(i)```When this code is executed, each element in ```x``` would be printed to the console. Since strings are also sequence data types, we can use a for loop to iterate over Strings:```pythonmy_string = 'HumanEd is awesome'for c in my_string:    print(c)```This code iterates over every character in ```my_string```, printing the character.We can use the ```break``` statement to exit out of a for loop when a particular condition is met:```pythonx = [178, 34, 12, 98, 21, 45, 87]for i in x:    if (i%7 == 0):        print(i)        break```This code iterates over the elements in ```x``` to find the first element that is divisible by 7. Once this element is found, we exit the for loop. Additionally, we can use the ```continue``` statement to skip to the next loop iteration:```pythonx = [1,2,3,4,5,6,7,8,9,10]for i in x:    if (i%2 == 0):        continue    print(i)```This code would print all the odd elements of x, skipping the even ones.Finally, it is often useful to iterate over a large quantity of consecutive numbers. This can easily be achieved using the ```range()``` function:```pythonfor i in range(1000):    print(i)```This code prints every number from 0 to 999. Internally, ```range(a,b)``` constructs a list of consicutive numbers from a to b - 1, where could be omited and it will be assumed that ```a=0```. Note that the resulting list is a different datatype than the lists we have previously encontered. You can convert ```range(a,b)``` to a traditional list as follows ```list(range(a,b))```. Finally, if you wanted to iterate over numbers: $a, a + 2, a + 4, ..., b-1$, you could simply use ```range(a,b, 2)```.<jupyter_code>for i in range(5, 100):
    if (i%7 == 0):
        print(i)<jupyter_output><empty_output><jupyter_text>Exercise 6Write a function ```isPrime(n)``` that behaves as follows:- if n is a prime number: return 1- if n is not a prime number: return the smallest divisor of n that is greater than 1  Challenge 1Write a function ```romanToInteger(s)``` that takes a roman numeral ```s``` as a string and returns the integer that it corresponds to. For example: ```romanToInteger('VIII')``` should return ```8```, and ```romanToInteger('MCMXCIV')``` should return ```1994```.<jupyter_code>#Your code goes here, when you complete the exercise deleat the raise NotImplementedError statement to run the code
raise NotImplementedError<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07295456048680468, 'fraction_numerical': 0.015609497982670811, 'mean_word_length': 4.024925224327019, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 60, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '313125', 'license': 'Apache-2.0', 'n_tokens_mistral': 4113, 'n_tokens_neox': 3884, 'n_words': 2104, 'path': '02-python/.ipynb_checkpoints/python workshop-checkpoint.ipynb', 'repo_name': 'HumanED/workshops-2021', 'size': '15119'}