diff --git a/A1/Cours.md b/A1/Cours.md index 2009089..a882f3b 100644 --- a/A1/Cours.md +++ b/A1/Cours.md @@ -1,6 +1,71 @@ # Cours A1 +## Cours/TP 12/10 + +Injection de fautes, exploiter les failles. +Mecanismes cryptographiques, algo mathematiquement robustes. Quand on veut les implémenter, ils peuvent êtres soumis à différentes attaques. + +Attaque par injection de code. (Injecter des données, qui peuvent correspondre à du code donné, exploitation de bug dans le code logiciel) +Attaque par canaux auxiliaires. (temps d'execution, consommation elec, connexion) + +Raison d'optimisation (multiplication), multiplier par 0 -> pas de calcul, temps de calcul très long donc si secret = 0, temps de calcul court. +Attaque physique. (Ouvrir le circuit, sonder (microprobing) entre la mémoire et le processeur, FIB ?) + +Certaines attaques nécessitent le composant physique, d'autres à distances (marron et bleu p4) +Tirs lasers pour modifier la mémoire, injecter des fautes. + + +p9. nécessite une précision en cycle processeur très grande. Il faut cibler une ou quelques cycles. +p10. Algo plus connus/utilisé. + +Evaluation : QCM sur toutes les parties. (qu'est-ce qu'une attaque etc... Contres mesures et classification) Dans quel cas on utilise certaines contre mesure et dans cette attaque là quelle contre mesure utiliser ? + +p12. CRC pour protéger les CSP (critical security parameters) pour éviter de changer les p,q qui sont premiers. + +p14. On faute l'exposant d_i de proche en proche pour obtenir les m_i +p15. Contre mesure = rajouter un produit avec un nombre aléatoire (Stratégie Résilience) + +Vérification de valeur -> Stratégie détection + +p19. On déplace l'instant d'exécution de l'instruction sensible -> Observation de la consommation électrique +On peut rajouter des capteurs (lumière pour l'ouverture de la puce, f_clk pour le downclocking pour observer les signaux) + +### TD + +Q1 Donner l'équation de R_16 en fonction de R_15 et L_15 +R_16 = L_15 ^ f(R_15,K_16) #f(.,.) p40 +f(R_15,K_16) = P(S_1-8(E(R_15) ^ K_16)) + +Q2 Entrée R_15 fautée : R_15' +R_16' = L_15' ^ P(S_1-8(E(R_15') ^ K_16)) + +Q3 Delta(R_16) = R_16 ^ R_16' += Delta(L_15) ^ P(a) ^ P(b) += Delta(L_15) ^ P(S_1-8(E(R_15) ^ K_16) ^ S_1-8(E(R_15') ^ K_16)) + +Q4 +Connues : R_16, R_15 = L_16 et R_15' = L_16' +Inconnues : Delta(L_15) et K_16 + +On veut Delta(L_15) = 0 donc ne pas toucher L_15 lors de la faute. + +Q5 +P⁻¹(Delta(R_16)) = S_1-8(E(R_15) ^ K_16) ^ S_1-8(E(R_15') ^ K_16) + +On teste les clés K_16 pour avoir égalité des deux côtés, si elle c'est vérifié, la clé est une candidate. + +Défi 4 : + +Q1 +P⁻¹_1(Delta(R_16)) = S_1(E(R_15) ^ K_16,1) ^ S_1(E(R_15') ^ K_16,1) + + ## 19/10 Side-Channel Analysis -p9: ce qu'on attaque, c'est pas l'algo, c'est l'implémentation de celui-ci +p9: ce qu'on attaque, c'est pas l'algo, c'est l'implémentation de celui-ci. + +p10: 10000 essais en force brute, 40 avec canal auxiliaire en regardant le temps d'exécution et sa variation pour chaque digit. + +p15: le pic de courant indique le nombre de portes logiques qui ont changé d'état +p58: Si on a pas de connaissances à priori sur le système, on regarde une fenetre temporelle élevée pour déterminer la trace. On réduit la fenêtre quand on cible l'attaque. diff --git a/B1/WCET-CACHE-STREC-18.pdf b/B1/WCET-CACHE-STREC-18.pdf new file mode 100644 index 0000000..8b2982e Binary files /dev/null and b/B1/WCET-CACHE-STREC-18.pdf differ diff --git a/B1/cours3.md b/B1/cours3.md index 8cfa408..f88f900 100644 --- a/B1/cours3.md +++ b/B1/cours3.md @@ -2,3 +2,6 @@ Niveau de criticalité : tolérance de fautes, fautes critiques +# Cours 26/10 + +Boundaries of a tasks time \ No newline at end of file diff --git a/B1/strec-ipet.tar_ b/B1/strec-ipet.tar_ new file mode 100644 index 0000000..ac485f5 Binary files /dev/null and b/B1/strec-ipet.tar_ differ diff --git a/B1/strec-ipet/Makefile b/B1/strec-ipet/Makefile new file mode 100644 index 0000000..c56e06b --- /dev/null +++ b/B1/strec-ipet/Makefile @@ -0,0 +1,13 @@ + +export PATH := $(PATH):/infres/ir600/users/brandner/patmos-misc/local/bin/ + +OWCET=owcet + +.PHONY: analyse clean + +analyse: heli heli.ff patmos_wcet.osx patmos_wcet/caches.xml patmos_wcet/memory.xml patmos_wcet/pipeline.xml + @mkdir -p out + $(OWCET) -f heli.ff -s patmos_wcet.osx heli + +clean: + rm -rf out diff --git a/B1/strec-ipet/heli b/B1/strec-ipet/heli new file mode 100755 index 0000000..eea12f8 Binary files /dev/null and b/B1/strec-ipet/heli differ diff --git a/B1/strec-ipet/heli.ff b/B1/strec-ipet/heli.ff new file mode 100644 index 0000000..00192cc --- /dev/null +++ b/B1/strec-ipet/heli.ff @@ -0,0 +1,29 @@ +//**** jumptable (source: llvm) +// TODO: find corresponding C and assembly code (Exercise 1). +multibranch 0x20b00 to "processSensorData"+0x70, + "processSensorData"+0x1b0, + "processSensorData"+0x320, + "processSensorData"+0x460; + +//**** +loop "main"+0x4c 32; +loop "main"+0x150 10; // assumed bound + +//**** +// TODO: find tighter loop bound, later, specify loop bounds depending on +// calling context (Exercise 2). +loop "fixFilter"+0x24 10000; + +//**** +loop "calibrateArom"+0x48 128; +loop "calibrateArom"+0xf0 128; +loop "calibrateArom"+0x190 128; + +//**** +loop "processSensorData"+0xb8 8; +loop "processSensorData"+0x214 32; +loop "processSensorData"+0x384 32; +loop "processSensorData"+0x4c0 32; + +//**** +loop "runFlightPlan"+0x1bc 1; // watchdog loop diff --git a/B1/strec-ipet/patmos_env b/B1/strec-ipet/patmos_env new file mode 100644 index 0000000..90d4440 --- /dev/null +++ b/B1/strec-ipet/patmos_env @@ -0,0 +1,5 @@ +#!/bin/bash + + +export PATH=$PATH:/infres/ir600/users/brandner/patmos-misc/local/bin/ +export LD_LIBRARY_PATH=$LD_LIBARY_PATH:/infres/ir600/users/brandner/patmos-misc/local/lib/ \ No newline at end of file diff --git a/B1/strec-ipet/patmos_wcet.osx b/B1/strec-ipet/patmos_wcet.osx new file mode 100644 index 0000000..d5719f9 --- /dev/null +++ b/B1/strec-ipet/patmos_wcet.osx @@ -0,0 +1,35 @@ + + + + + + + + + + + + + diff --git a/B1/strec-ipet/patmos_wcet/caches.xml b/B1/strec-ipet/patmos_wcet/caches.xml new file mode 100644 index 0000000..7065fac --- /dev/null +++ b/B1/strec-ipet/patmos_wcet/caches.xml @@ -0,0 +1,15 @@ + + + + 5 + 2 + 9 + 25 + + + 5 + 2 + 9 + 25 + + diff --git a/B1/strec-ipet/patmos_wcet/memory.xml b/B1/strec-ipet/patmos_wcet/memory.xml new file mode 100644 index 0000000..7a26bfe --- /dev/null +++ b/B1/strec-ipet/patmos_wcet/memory.xml @@ -0,0 +1,14 @@ + + + + + RAM +
0x00000000
+ 0x1fffffff + DRAM + 25 + true + true +
+
+
diff --git a/B1/strec-ipet/patmos_wcet/pipeline.xml b/B1/strec-ipet/patmos_wcet/pipeline.xml new file mode 100644 index 0000000..b2852ca --- /dev/null +++ b/B1/strec-ipet/patmos_wcet/pipeline.xml @@ -0,0 +1,54 @@ + + + patmos + patmos + + + + + FE + 2 + FETCH + + + + DE + 2 + LAZY + + + + EX + 2 + EXEC + true + + + ALU + 2 + 1 + + + + + + + + + + + + + MEM + 2 + LAZY + + + + CM + 2 + COMMIT + + + + diff --git a/B1/strec-ipet/src/heli.c b/B1/strec-ipet/src/heli.c new file mode 100644 index 0000000..726eee0 --- /dev/null +++ b/B1/strec-ipet/src/heli.c @@ -0,0 +1,416 @@ +// helico.c +// this code is inspired from: http://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/s2006/rg242/webpage/ece%20476.htm + +#include "io.h" + +// define sensor channels +#define GYRO_CHANNEL 0 +#define AROMX_CHANNEL 1 +#define AROMY_CHANNEL 2 +#define AROMZ_CHANNEL 3 +char currentChannel = GYRO_CHANNEL; + +// define Helicopter states +#define GROUND 0 +#define LANDING 1 +#define TAKEOFF 2 +#define HOVER 3 +char heliState = GROUND; + +// define flight phases +#define TAKEOFF_START 5 +#define HOVER_START 23 +#define LANDING_START 299 +#define LANDING_END 400 +#define GROUNDED_START 410 + +// define motor speeds +#define MINIMUM_PWM_VALUE 0 +#define MAXIMUM_ROTOR_PWM_VALUE (100<<8) +#define MARKS_PER_SEC 1600 +int pwm_ticks = 0; +int marks = 0; +volatile int sec = 0; + +#define MAX_TAKEOFF_MOTOR_SPEED (95<<8) +#define TAKEOFF_ROTOR_SPEED_INCR 16 +#define ROTOR_SPEED_INCR 8 +#define HOVER_ROTOR_SPEED_INCR_HIGH 2 +#define HOVER_ROTOR_SPEED_INCR_LOW 5 +#define MAX_STAB_MOTOR_SPEED (60<<8) +#define MIN_STAB_MOTOR_SPEED 0 +#define STAB_SPEED_INCR 256 +#define MIN_LANDING_ROTOR_SPEED (50<<8) +#define LANDING_ROTOR_SPEED_INCR 1 + +int topRotorSpeed = 0; +int bottomRotorSpeed = 0; +int stabMotorSpeed1 = 0; +int stabMotorSpeed2 = 0; +int stabMotorSpeed3 = 0; + +// ADC +char data_in; +#define ADMUX_GYRO 0b01100000 +#define ADMUX_AROMX 0b01100001 +#define ADMUX_AROMY 0b01100010 +#define ADMUX_AROMZ 0b01100011 + +// Sensors +uint8_t gyroCalibrateThresholdLow; +uint8_t gyroCalibrateThresholdHigh; +uint8_t aromXCalibrateThresholdLow; +uint8_t aromXCalibrateThresholdHigh; +uint8_t aromYCalibrateThresholdLow; +uint8_t aromYCalibrateThresholdHigh; +uint8_t aromZCalibrateThresholdLow; +uint8_t aromZCalibrateThresholdHigh; +uint8_t gyro[32]; +uint8_t aromX[128]; +uint8_t aromY[128]; +uint8_t aromZ[128]; + + +void updatePWM(void); +void processSensorData(void) __attribute__((noinline)); +void runFlightPlan(void) __attribute__((noinline)); +void calibrateGyro(void); +void calibrateArom(void); +uint8_t fixFilter(uint8_t *f, int size) __attribute__((noinline)); +void addSample(uint8_t *f, int size, uint8_t value); + + +void timer_interrupt(void){ + pwm_ticks++; + marks++; + if (marks == MARKS_PER_SEC){ + sec++; + marks = 0; + } + updatePWM(); +} + +void updatePWM(void){ + char command = 0; + int ticks = pwm_ticks << 8; + // generate PWM command for the 5 motors + if (ticks <= topRotorSpeed) + command |= PIN0; + if (ticks <= bottomRotorSpeed) + command |= PIN1; + if (ticks <= stabMotorSpeed1) + command |= PIN2; + if (ticks <= stabMotorSpeed2) + command |= PIN3; + if (ticks <= stabMotorSpeed3) + command |= PIN4; + PORTC = command; + if (ticks == MAXIMUM_ROTOR_PWM_VALUE) + pwm_ticks = 0; +} + + +int main(void){ + calibrateGyro(); + calibrateArom(); + + // start + topRotorSpeed = 0; + bottomRotorSpeed = 0; + stabMotorSpeed1 = 0; + stabMotorSpeed2 = 0; + stabMotorSpeed3 = 0; + + sec = 0; + + static volatile int x = 1; + __llvm_pcmarker(31); + while (x) { + __llvm_pcmarker(32); + if ( (ADCSR & PIN6) == 0) { // end of ADC conversion + processSensorData(); + __llvm_pcmarker(33); + } + runFlightPlan(); + } +} + +void runFlightPlan(void){ + // take off + if (sec <= TAKEOFF_START){ + heliState = TAKEOFF; + topRotorSpeed += TAKEOFF_ROTOR_SPEED_INCR; + if (topRotorSpeed > MAX_TAKEOFF_MOTOR_SPEED) + topRotorSpeed = MAX_TAKEOFF_MOTOR_SPEED; + bottomRotorSpeed += TAKEOFF_ROTOR_SPEED_INCR; + if (bottomRotorSpeed > MAX_TAKEOFF_MOTOR_SPEED) + bottomRotorSpeed = MAX_TAKEOFF_MOTOR_SPEED; + } + + // hover + if (sec == HOVER_START) + heliState = HOVER; + + // landing + if (sec == LANDING_START){ + heliState = LANDING; + stabMotorSpeed1 = 0; + stabMotorSpeed2 = 0; + stabMotorSpeed3 = 0; + } + + if ( (sec > LANDING_START) && (sec <= LANDING_END) ){ + topRotorSpeed -= LANDING_ROTOR_SPEED_INCR; + if (topRotorSpeed < MIN_LANDING_ROTOR_SPEED) + topRotorSpeed = MIN_LANDING_ROTOR_SPEED; + bottomRotorSpeed -= LANDING_ROTOR_SPEED_INCR; + if (bottomRotorSpeed < MIN_LANDING_ROTOR_SPEED) + bottomRotorSpeed = MIN_LANDING_ROTOR_SPEED; + } + + // grounded + if(sec >= GROUNDED_START){ + heliState = GROUND; + WDTCR = 0x08; //enable watchdog + while (1) ; //just wait for watchdog to reset machine + } +} + +void processSensorData(void){ + char filtered_data; + char data_in_last; + + data_in_last = data_in; + data_in = ADCH; + + switch (currentChannel) { + + case GYRO_CHANNEL: + // start conversion for next channel + currentChannel = AROMX_CHANNEL; + ADMUX = ADMUX_AROMX; + ADCSR = ADCSR | PIN6; + + addSample(gyro, 5, data_in); + filtered_data = fixFilter(gyro,5); + + if (filtered_data < gyroCalibrateThresholdLow) { + topRotorSpeed += ROTOR_SPEED_INCR;; + if (topRotorSpeed > MAXIMUM_ROTOR_PWM_VALUE) + topRotorSpeed = MAXIMUM_ROTOR_PWM_VALUE; + bottomRotorSpeed -= ROTOR_SPEED_INCR; + if (bottomRotorSpeed < MINIMUM_PWM_VALUE) + bottomRotorSpeed = MINIMUM_PWM_VALUE; + } + else + if (filtered_data > gyroCalibrateThresholdHigh) { + topRotorSpeed -= ROTOR_SPEED_INCR; + if (topRotorSpeed < MINIMUM_PWM_VALUE) + topRotorSpeed = MINIMUM_PWM_VALUE; + bottomRotorSpeed += ROTOR_SPEED_INCR; + if (bottomRotorSpeed > MAXIMUM_ROTOR_PWM_VALUE) + bottomRotorSpeed = MAXIMUM_ROTOR_PWM_VALUE; + } + break; + + + case AROMX_CHANNEL: + // start conversion for next channel + currentChannel = AROMY_CHANNEL; + ADMUX = ADMUX_AROMY; + ADCSR |= PIN6; + + if (heliState == HOVER) { + + __llvm_pcmarker(21); + addSample(aromX,7,data_in); + filtered_data = fixFilter(aromX,7); + + if (filtered_data < aromXCalibrateThresholdLow) { + stabMotorSpeed1 -= STAB_SPEED_INCR*2; + if (stabMotorSpeed1 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed1 = MIN_STAB_MOTOR_SPEED; + stabMotorSpeed2 += STAB_SPEED_INCR*2; + if (stabMotorSpeed2 > MAX_STAB_MOTOR_SPEED) + stabMotorSpeed2 = MAX_STAB_MOTOR_SPEED; + stabMotorSpeed3 += STAB_SPEED_INCR*2; + if (stabMotorSpeed3 > MAX_STAB_MOTOR_SPEED) + stabMotorSpeed3 = MAX_STAB_MOTOR_SPEED; + } + else if (filtered_data > aromXCalibrateThresholdHigh) { + stabMotorSpeed1 += STAB_SPEED_INCR*2; + if (stabMotorSpeed1 > MAX_STAB_MOTOR_SPEED) + stabMotorSpeed1 = MAX_STAB_MOTOR_SPEED; + stabMotorSpeed2 -= STAB_SPEED_INCR*2; + if (stabMotorSpeed2 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed2 = MIN_STAB_MOTOR_SPEED; + stabMotorSpeed3 -= STAB_SPEED_INCR*2; + if (stabMotorSpeed3 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed3 = MIN_STAB_MOTOR_SPEED; + } + else { + stabMotorSpeed1 -= STAB_SPEED_INCR*2; + if (stabMotorSpeed1 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed1 = MIN_STAB_MOTOR_SPEED; + } + } + break; + + case AROMY_CHANNEL: + // starting new conversion + currentChannel = AROMZ_CHANNEL; + ADMUX = ADMUX_AROMZ; + ADCSR |= PIN6; + + if (heliState == HOVER){ + + __llvm_pcmarker(22); + addSample(aromY, 7, data_in); + filtered_data = fixFilter(aromY,7); + + if (filtered_data < aromYCalibrateThresholdLow) { + stabMotorSpeed2 += STAB_SPEED_INCR*4; + if (stabMotorSpeed2 > MAX_STAB_MOTOR_SPEED) + stabMotorSpeed2 = MAX_STAB_MOTOR_SPEED; + stabMotorSpeed3 -= STAB_SPEED_INCR*2; + if (stabMotorSpeed3 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed3 = MIN_STAB_MOTOR_SPEED; + } + else if (filtered_data > aromYCalibrateThresholdHigh) { + stabMotorSpeed2 -= STAB_SPEED_INCR*2; + if (stabMotorSpeed2 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed2 = MIN_STAB_MOTOR_SPEED; + stabMotorSpeed3 += STAB_SPEED_INCR*4; + if (stabMotorSpeed3 > MAX_STAB_MOTOR_SPEED) + stabMotorSpeed3 = MAX_STAB_MOTOR_SPEED; + } + else { + stabMotorSpeed2 -= STAB_SPEED_INCR; + if (stabMotorSpeed2 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed2 = MIN_STAB_MOTOR_SPEED; + stabMotorSpeed3 -= STAB_SPEED_INCR; + if (stabMotorSpeed3 < MIN_STAB_MOTOR_SPEED) + stabMotorSpeed3 = MIN_STAB_MOTOR_SPEED; + } + } + break; + + case AROMZ_CHANNEL: + // Starting new conversion + currentChannel = GYRO_CHANNEL; + ADMUX = ADMUX_GYRO; + ADCSR |= PIN6; + + if (heliState == HOVER){ + + __llvm_pcmarker(23); + addSample(aromZ, 7, data_in); + filtered_data = fixFilter(aromZ,8); + + if (filtered_data > aromZCalibrateThresholdHigh){ + topRotorSpeed -= HOVER_ROTOR_SPEED_INCR_HIGH; + if (topRotorSpeed < MINIMUM_PWM_VALUE) + topRotorSpeed = MINIMUM_PWM_VALUE; + bottomRotorSpeed -= HOVER_ROTOR_SPEED_INCR_HIGH; + if (bottomRotorSpeed < MINIMUM_PWM_VALUE) + bottomRotorSpeed = MINIMUM_PWM_VALUE; + } + else if (filtered_data == aromZCalibrateThresholdLow){ + topRotorSpeed += HOVER_ROTOR_SPEED_INCR_LOW; + if (topRotorSpeed > MAXIMUM_ROTOR_PWM_VALUE) + topRotorSpeed = MAXIMUM_ROTOR_PWM_VALUE; + bottomRotorSpeed += HOVER_ROTOR_SPEED_INCR_LOW; + if(bottomRotorSpeed > MAXIMUM_ROTOR_PWM_VALUE) + bottomRotorSpeed = MAXIMUM_ROTOR_PWM_VALUE; + } + } + break; + } +} + +void calibrateGyro(void) { + char gyroCalibrate; + int i; + + ADMUX = ADMUX_GYRO; + ADCSR = 0b11000110; + + for (i=0; i<31; i++){ + gyro[i] = ADCH; + ADCSR |= PIN6;; + } + gyro[31] = ADCH; + + gyroCalibrate = fixFilter(gyro,5); + gyroCalibrateThresholdLow = gyroCalibrate - 1; + gyroCalibrateThresholdHigh = gyroCalibrate + 1; +} + +void calibrateArom(void){ + char aromCalibrate; + int i; + + ADMUX = ADMUX_AROMX; + ADCSR |= PIN6; + + for (i=0; i<127; i++){ + aromX[i] = ADCH; + ADCSR |= PIN6; + } + aromX[127] = ADCH; + aromCalibrate = fixFilter(aromX,7); + aromXCalibrateThresholdLow = aromCalibrate; + aromXCalibrateThresholdHigh = aromCalibrate + 1; + + ADMUX = ADMUX_AROMY; + ADCSR |= PIN6; + + for (i=0; i<127; i++){ + aromY[i] = ADCH; + ADCSR |= PIN6; + } + aromY[127] = ADCH; + aromCalibrate = fixFilter(aromY,7); + aromYCalibrateThresholdLow = aromCalibrate; + aromYCalibrateThresholdHigh = aromCalibrate; + + ADMUX = ADMUX_AROMZ; + ADCSR |= PIN6; + + for (i=0; i<127; i++){ + aromZ[i] = ADCH; + ADCSR |= PIN6; + } + aromZ[127] = ADCH; + aromCalibrate = fixFilter(aromZ,7); + aromZCalibrateThresholdLow = aromCalibrate; + aromZCalibrateThresholdHigh = aromCalibrate + 3; + + ADMUX = ADMUX_GYRO; + ADCSR |= PIN6; + +} + +uint8_t fixFilter(uint8_t *f, int size){ + int i; + int length = 1 << size; + int sum = 0; + for(i = 0; i < length; i++){ + sum = sum + f[i]; + } + // divide by length + sum = sum >> size; + return sum; +} + +void addSample(uint8_t *f, int size, uint8_t value){ + int i; + int length = 1 << size; + for (i = 0;i < length; i++){ + f[i] = f[i+1]; + } + f[length-1] = value; +} + + + diff --git a/B1/strec-ipet/src/io.h b/B1/strec-ipet/src/io.h new file mode 100644 index 0000000..4ddaace --- /dev/null +++ b/B1/strec-ipet/src/io.h @@ -0,0 +1,23 @@ +/**************** io.h **************/ +typedef unsigned char uint8_t; + +#define _SFR_BASE 0xF0000 +#define _SFR_MEM8(mem_addr) (*(volatile uint8_t *)(mem_addr + _SFR_BASE)) + +#define ADCH _SFR_MEM8(0x05) +#define ADCSR _SFR_MEM8(0x06) +#define ADMUX _SFR_MEM8(0x07) +#define PIND _SFR_MEM8(0x10) +#define PORTD _SFR_MEM8(0x12) +#define PORTC _SFR_MEM8(0x15) +#define WDTCR _SFR_MEM8(0x31) + + +#define PIN0 0x1 +#define PIN1 0x2 +#define PIN2 0x4 +#define PIN3 0x8 +#define PIN4 0x10 +#define PIN5 0x20 +#define PIN6 0x40 +#define PIN7 0x80 diff --git a/D3/TP/Cours.ipynb b/D3/TP/Cours.ipynb new file mode 100644 index 0000000..dd486cb --- /dev/null +++ b/D3/TP/Cours.ipynb @@ -0,0 +1,128 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cours D3\n", + "\n", + "## Cours Méthodes d'analyse non supervisées\n", + "\n", + "Exemple de clustering complete linkage :\n", + "On prend 4 singletons avec leur matrice de dissimilarité." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0. 0.3 0.4 0.8 ]\n", + " [0.3 0. 0.5 0.8 ]\n", + " [0.4 0.5 0. 0.45]\n", + " [0.8 0.8 0.45 0. ]]\n" + ] + } + ], + "source": [ + "D = np.array([[0, 0.3, 0.4, 0.7],[0, 0, 0.5, 0.8],[0, 0, 0, 0.45],[0, 0, 0, 0]])\n", + "D += D.T\n", + "print(D)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On link les 2 clusters les plus proches (a,b) donc on prend le max de différence entre (a,b) et c et d." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0. 0.5 0.8 ]\n", + " [0.5 0. 0.45]\n", + " [0.8 0.45 0. ]]\n" + ] + } + ], + "source": [ + "D2 = np.array([[0, 0.5, 0.8],[0.5, 0, 0.45],[0.8, 0.45, 0]])\n", + "print(D2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On coupe au saut le plus important sur le dendrogramme (on continu jusqu'a avoir K-clusters)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0. 0.8]\n", + " [0.8 0. ]]\n" + ] + } + ], + "source": [ + "# (a,b,c) et d\n", + "D3 = np.array([[0, 0.8],[0.8,0]])\n", + "print(D3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.10 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D3/TP/TP1.ipynb b/D3/TP/TP1.ipynb index de44a46..e3dddf9 100644 --- a/D3/TP/TP1.ipynb +++ b/D3/TP/TP1.ipynb @@ -12,25 +12,28 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "import scipy" + "import scipy.spatial" ] }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ + "# mean = [1,2,3,4]\n", + "# sd = [0.25, 0.25, 0.1, 0.2]\n", + "# clusters = 4\n", "mean = [1,2]\n", "sd = [0.25, 0.25]\n", "dim = 2\n", - "nb = 100\n", + "nb = 10\n", "clusters = 2" ] }, @@ -38,79 +41,210 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Fonctions utiles pour le script" + "## Fonctions à utiliser pour le clustering" ] }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def gen_points(mean=1,sd=0.5, nb=100, dim=2, clusters=2):\n", " size = []\n", - " for i in range(0,dim):\n", - " size.append(nb)\n", - " size.append(clusters)\n", - " points = np.random.normal(mean,sd,size=size)\n", + " # for i in range(0,dim):\n", + " size.append(nb)\n", + " size.append(dim)\n", + " points = np.random.normal(mean[0],sd[0],size=size)\n", + " for i in range(1,clusters):\n", + " points = np.concatenate((points,np.random.normal(mean[i],sd[i],size=size)),axis=0)\n", + " \n", " return points" ] }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "def distance(points,dim=2): \n", - " return scipy.spatial.distance.cdist(points)" + "def distance(points,Pc): \n", + " return scipy.spatial.distance.cdist(points[:,:], points[:,:])" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 5, "metadata": {}, + "outputs": [], "source": [ - "## Fonctions à utiliser pour le clustering" + "def kmeans(points = [0,0], K = 1, nb=1, dim=2):\n", + " # Initialisation K prototypes\n", + " Pc_index = []\n", + " for i in range(0,K):\n", + " Pc_index.append(np.random.randint(0,nb*dim))\n", + " Pc = points[Pc_index,:]\n", + "\n", + " return Pc" ] }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ - "def kmeans(points = [0,0], K = 1):\n", - " print(\"hi\")" + "def visualisation(points, Pc=[0,0], dim=2):\n", + " if(dim==2):\n", + " plt.plot(points[:,0], points[:,1], 'o')\n", + " plt.plot(Pc[:,0],Pc[:,1],'r+')\n", + " plt.grid(True)\n", + " plt.axis([min(mean)-1,max(mean)+1,min(mean)-1,max(mean)+1])" ] }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(20, 2)\n" + ] + } + ], "source": [ - "def visualisation(points, pos_cluster=0, dim=2):\n", - " if(dim==2):\n", - " plt.plot(points[0], points[1], 'o')\n", - " plt.grid(True)\n", - " plt.axis([0,3,0,3])" + "points = gen_points(mean,sd,nb,dim,clusters)\n", + "print(points.shape)\n", + "# print(points)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[0. 0.39108103 0.34583518 0.70546644 0.3203134 0.3516725\n", + " 0.67971143 0.12125982 0.61902803 0.25895127 1.56135251 1.16925868\n", + " 0.89449237 1.43352053 1.0743239 0.93510189 1.41988547 1.58011875\n", + " 1.08411331 1.18671248]\n", + " [0.39108103 0. 0.41265824 0.31753789 0.20134828 0.1520557\n", + " 0.29442779 0.48416069 0.32820193 0.29379395 1.92061143 1.55795192\n", + " 1.2792717 1.80777689 1.45979562 1.32616725 1.80571725 1.97050583\n", + " 1.47031622 1.56670796]\n", + " [0.34583518 0.41265824 0. 0.62859739 0.21220435 0.49592519\n", + " 0.67380419 0.31854927 0.73773146 0.51626889 1.8336252 1.37308473\n", + " 1.01281801 1.49334278 1.29787751 1.11001289 1.52748312 1.75952011\n", + " 1.30415796 1.42577374]\n", + " [0.70546644 0.31753789 0.62859739 0. 0.44061757 0.42670666\n", + " 0.13916838 0.7887133 0.38129538 0.58971012 2.2340252 1.87432417\n", + " 1.58220205 2.09814273 1.77707512 1.63872881 2.10818677 2.28550213\n", + " 1.78747095 1.88420608]\n", + " [0.3203134 0.20134828 0.21220435 0.44061757 0. 0.30494113\n", + " 0.46740546 0.36865442 0.52868835 0.37372177 1.88068426 1.46844245\n", + " 1.14902285 1.65807412 1.3803439 1.21975293 1.67330997 1.8710176\n", + " 1.38894595 1.49825024]\n", + " [0.3516725 0.1520557 0.49592519 0.42670666 0.30494113 0.\n", + " 0.35637593 0.46606861 0.27034798 0.16380212 1.81240225 1.48388867\n", + " 1.24193007 1.78456017 1.37947088 1.26763783 1.76514842 1.90097935\n", + " 1.39123292 1.47795072]\n", + " [0.67971143 0.29442779 0.67380419 0.13916838 0.46740546 0.35637593\n", + " 0. 0.77794127 0.24735327 0.51809049 2.16596566 1.83655551\n", + " 1.57217378 2.1022043 1.7339787 1.61275974 2.09839429 2.25219229\n", + " 1.74541605 1.83405921]\n", + " [0.12125982 0.48416069 0.31854927 0.7887133 0.36865442 0.46606861\n", + " 0.77794127 0. 0.73558536 0.38006228 1.52663824 1.09978826\n", + " 0.79543522 1.32585453 1.01264344 0.85309758 1.32192905 1.50347121\n", + " 1.02093103 1.13291852]\n", + " [0.61902803 0.32820193 0.73773146 0.38129538 0.52868835 0.27034798\n", + " 0.24735327 0.73558536 0. 0.38834 1.99112336 1.71317083\n", + " 1.50027904 2.04749497 1.6029451 1.51251266 2.01963574 2.13226014\n", + " 1.61597543 1.69022564]\n", + " [0.25895127 0.29379395 0.51626889 0.58971012 0.37372177 0.16380212\n", + " 0.51809049 0.38006228 0.38834 0. 1.64887732 1.33143897\n", + " 1.11366524 1.66342238 1.22437768 1.12471467 1.63153555 1.74982768\n", + " 1.23666771 1.31925162]\n", + " [1.56135251 1.92061143 1.8336252 2.2340252 1.88068426 1.81240225\n", + " 2.16596566 1.52663824 1.99112336 1.64887732 0. 0.58770443\n", + " 1.02271415 1.15136496 0.58808445 0.83705754 0.94499234 0.6037414\n", + " 0.59102406 0.44614399]\n", + " [1.16925868 1.55795192 1.37308473 1.87432417 1.46844245 1.48388867\n", + " 1.83655551 1.09978826 1.71317083 1.33143897 0.58770443 0.\n", + " 0.44427897 0.64604338 0.12332713 0.27518253 0.47328172 0.41918021\n", + " 0.10638777 0.1741561 ]\n", + " [0.89449237 1.2792717 1.01281801 1.58220205 1.14902285 1.24193007\n", + " 1.57217378 0.79543522 1.50027904 1.11366524 1.02271415 0.44427897\n", + " 0. 0.55487036 0.44065169 0.19125029 0.52649414 0.76267241\n", + " 0.43456127 0.57921824]\n", + " [1.43352053 1.80777689 1.49334278 2.09814273 1.65807412 1.78456017\n", + " 2.1022043 1.32585453 2.04749497 1.66342238 1.15136496 0.64604338\n", + " 0.55487036 0. 0.7423045 0.62079242 0.20929273 0.61317826\n", + " 0.7258323 0.81728057]\n", + " [1.0743239 1.45979562 1.29787751 1.77707512 1.3803439 1.37947088\n", + " 1.7339787 1.01264344 1.6029451 1.22437768 0.58808445 0.12332713\n", + " 0.44065169 0.7423045 0. 0.25088095 0.58359133 0.5339439\n", + " 0.01763323 0.14206747]\n", + " [0.93510189 1.32616725 1.11001289 1.63872881 1.21975293 1.26763783\n", + " 1.61275974 0.85309758 1.51251266 1.12471467 0.83705754 0.27518253\n", + " 0.19125029 0.62079242 0.25088095 0. 0.52473292 0.65180514\n", + " 0.24624553 0.3914113 ]\n", + " [1.41988547 1.80571725 1.52748312 2.10818677 1.67330997 1.76514842\n", + " 2.09839429 1.32192905 2.01963574 1.63153555 0.94499234 0.47328172\n", + " 0.52649414 0.20929273 0.58359133 0.52473292 0. 0.40874924\n", + " 0.56617043 0.63624877]\n", + " [1.58011875 1.97050583 1.75952011 2.28550213 1.8710176 1.90097935\n", + " 2.25219229 1.50347121 2.13226014 1.74982768 0.6037414 0.41918021\n", + " 0.76267241 0.61317826 0.5339439 0.65180514 0.40874924 0.\n", + " 0.51939313 0.48569502]\n", + " [1.08411331 1.47031622 1.30415796 1.78747095 1.38894595 1.39123292\n", + " 1.74541605 1.02093103 1.61597543 1.23666771 0.59102406 0.10638777\n", + " 0.43456127 0.7258323 0.01763323 0.24624553 0.56617043 0.51939313\n", + " 0. 0.14516702]\n", + " [1.18671248 1.56670796 1.42577374 1.88420608 1.49825024 1.47795072\n", + " 1.83405921 1.13291852 1.69022564 1.31925162 0.44614399 0.1741561\n", + " 0.57921824 0.81728057 0.14206747 0.3914113 0.63624877 0.48569502\n", + " 0.14516702 0. ]]\n" + ] + } + ], + "source": [ + "dist = distance(points,Pc=[0,0])\n", + "print(dist)" ] }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[100, 100, 2]\n" + "[[1.2631266 0.8529462 ]\n", + " [1.1325475 1.17318217]]\n" ] - }, + } + ], + "source": [ + "Pc = kmeans(points,K=2,nb=nb,dim=dim)\n", + "print(Pc)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi4AAAGiCAYAAADA0E3hAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAswUlEQVR4nO3df3RU9Z3/8dckhozUJJq4yQw/xBQUDZFA0ODgOQUsMVA225ye41pPKaxVd+XAHtns0YV+e5qmdJu2imiVBT2u5qwsxWK/4Bd/xE4DgaPEzULILiGVVppC184kK9EJhCZOZ+73D0zMmJmQmdxk5k6ej3NydG4+d+aT97kdX72fz+d+bIZhGAIAALCAlHh3AAAAYKQILgAAwDIILgAAwDIILgAAwDIILgAAwDIILgAAwDIILgAAwDIILgAAwDIILgAAwDIILgAAwDKiCi7bt2/X3LlzlZmZqczMTLlcLr355pvDnrNnzx7ddNNNstvtuuWWW/TGG2+MqsMAAGDiiiq4TJs2TT/60Y907NgxHT16VHfeeae++tWv6uTJk2HbHzlyRPfee6/uv/9+HT9+XBUVFaqoqFBra6spnQcAABOLbbSbLGZnZ+uxxx7T/fffP+R399xzj3p6evTaa68NHLv99ts1b9487dixYzQfCwAAJqArYj0xEAhoz5496unpkcvlCtumsbFRlZWVIcfKysq0b9++Yd+7r69PfX19A6+DwaC6urqUk5Mjm80Wa5cBAMA4MgxD58+f15QpU5SSYs602qiDy4kTJ+RyudTb26urrrpKe/fuVUFBQdi2Xq9XeXl5Icfy8vLk9XqH/YyamhpVV1dH2zUAAJCA/vCHP2jatGmmvFfUwWX27NlqaWmRz+fTK6+8ojVr1ujQoUMRw0ssNm3aFHKnxufz6brrrtNvfvMbZWdnm/Y5E43f79fBgwe1dOlSpaWlxbs7lkYtzUMtzUEdzUMtzdPV1aUbb7xRGRkZpr1n1MFl0qRJmjVrliRpwYIF+s///E899dRTevbZZ4e0dTgc6ujoCDnW0dEhh8Mx7Gekp6crPT19yPHs7Gzl5ORE22V8yu/3a/LkycrJyeF/jKNELc1DLc1BHc1DLc1n5jSPUQ84BYPBkPkog7lcLtXX14ccc7vdEefEAAAADCeqOy6bNm3SihUrdN111+n8+fPatWuXGhoa9NZbb0mSVq9eralTp6qmpkaS9PDDD2vx4sXasmWLVq5cqd27d+vo0aN67rnnzP9LAABA0osquHR2dmr16tXyeDzKysrS3Llz9dZbb6m0tFSSdPbs2ZBZw4sWLdKuXbv0ne98R9/+9rd1ww03aN++fSosLDT3rwAAABNCVMHlX//1X4f9fUNDw5Bjd999t+6+++6oOgUAABAOexUBAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLILgAAADLuCLeHQCAsRYIGmpq71Ln+V7lZthVkp+t1BRbvLsFIAYEFwBJra7Vo+r9bfL4egeOObPsqiov0PJCZxx7BiAWDBUBSFp1rR6t3dkcElokyevr1dqdzapr9cSpZwBiRXABkJQCQUPV+9tkhPld/7Hq/W0KBMO1AJCoCC4AklJTe9eQOy2DGZI8vl41tXeNX6cAjBrBBUBS6jwfObTE0g5AYiC4AEhKuRl2U9sBSAwEFwBJqSQ/W84suyIterbp0uqikvzs8ewWgFEiuABISqkpNlWVF0jSkPDS/7qqvIDnuQAWQ3ABkLSWFzq1fVWxHFmhw0GOLLu2ryrmOS6ABfEAOgBJbXmhU6UFDp6cCyQJgguApJeaYpNrZk68uwHABAwVAQAAyyC4AAAAyyC4AAAAyyC4AAAAyyC4AAAAyyC4AAAAyyC4AAAAy4gquNTU1Oi2225TRkaGcnNzVVFRoVOnTg17Tm1trWw2W8iP3c6mZgAAIHpRBZdDhw5p3bp1evfdd+V2u+X3+3XXXXepp6dn2PMyMzPl8XgGfs6cOTOqTgMAgIkpqifn1tXVhbyura1Vbm6ujh07pi996UsRz7PZbHI4HCP+nL6+PvX19Q287u7uliT5/X75/f5ouoxB+mtHDUePWpqHWpqDOpqHWppnLGo4qkf++3w+SVJ29vDbwl+4cEEzZsxQMBhUcXGxfvjDH2rOnDkR29fU1Ki6unrI8YMHD2ry5Mmj6TIkud3u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DIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwDIILAACwjCvi3QFgLAWChprau9R5vle5GXaV5GcrNcUW724BAGJEcEHSqmv1qHp/mzy+3oFjziy7qsoLtLzQGceeAQBixVARklJdq0drdzaHhBZJ8vp6tXZns+paPXHqGQBgNLjjgqQTCBqq3t8mI8zvDEk2SdX721Ra4EioYSOzh7UYJgOQjAguSDpN7V1D7rQMZkjy+HrV1N4l18yc8evYMPqHtf78wR/1jZY39YN5K3TF1CkxD2sxTAYgWTFUhKTTeT5yaIml3VgbPKyVe6FLG975mXIvdMU8rMUwGYBkRnBB0snNsJvabixdblhLujSsFQiGazH27wcAiYahIiSdkvxsObPs8vp6w/4H3CbJkXVpzke8NbV36c8f/FFzLnRJkgo7Tof8U5I6L2SPeFjLisNkABANgguSTmqKTVXlBVq7s1k2KSS89E9NrSovSIiJqp3ne/WNlje14Z2fhRz/cd3TA//+5B33qvP8nSN+PzPbAUCiIbggKS0vdGr7quIhE1QdCTZBNTfDrh/MWyH3rIWSLt1p+XHd0/qn5X+v1ryZkqTOq7L1U5OHvxJhmAwAYkFwQdJaXuhUaYEjoZcEl+Rn64qpU9Tmyw65M9SaN1MnHbOiHtay0jAZAMSCyblIaqkpNrlm5uir86bKNTMnoUKL9NmwlvTZMFa/WIa1zH4/AEg0BBcgzvqHtRxZdnVelX1pTstV2XJk2bV9VXHUw1qD32+wWN8PABIJQ0VAAggd1rpTPx3lsJYVhskAIBYEFyBB9A9rJer7AUAiYKgIAABYBsEFAABYBsEFAABYBsEFAABYBpNzYTmBoMFqGQCYoAgusJS6Vs+Qx/g7E+wx/gCAscNQESyjrtWjtTubh+x+7PX1au3OZtW1euLUMwDAeCG4wBICQUPV+9vC7r/Tf6x6f5sCwXAtAADJguACS2hq7xpyp2UwQ5LH16um9q7x6xQAYNwRXGAJnecjh5ZY2gEArCnq4HL48GGVl5drypQpstls2rdv32XPaWhoUHFxsdLT0zVr1izV1tbG0FWMlUDQUOPpc3q15QM1nj6XkMMt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y7Zt23T99dfLbrdr4cKFampqiti2trZWNpst5MduZ58aAAAQvaiDy8svv6zKykpVVVWpublZRUVFKisrU2dnZ8RzMjMz5fF4Bn7OnDkzqk4DAICJKerg8sQTT+jBBx/Ufffdp4KCAu3YsUOTJ0/WCy+8EPEcm80mh8Mx8JOXlzeqTgMAgIkpqifnfvLJJzp27Jg2bdo0cCwlJUXLli1TY2NjxPMuXLigGTNmKBgMqri4WD/84Q81Z86ciO37+vrU19c38Lq7u1uS5Pf75ff7o+kyBumvHTUcPWppHmppDupoHmppnrGoYVTB5cMPP1QgEBhyxyQvL0/vvfde2HNmz56tF154QXPnzpXP59Pjjz+uRYsW6eTJk5o2bVrYc2pqalRdXT3k+MGDBzV58uRouoww3G53vLuQNKileailOaijeajl6F28eNH09xzzvYpcLpdcLtfA60WLFunmm2/Ws88+q82bN4c9Z9OmTaqsrBx43d3drenTp2vp0qXKyWHvm1j5/X653W6VlpYqLS0t3t2xNGppHmppDupoHmppnnPnzpn+nlEFl2uvvVapqanq6OgIOd7R0SGHwzGi90hLS9P8+fP1/vvvR2yTnp6u9PT0sOdyEY0edTQPtTQPtTQHdTQPtRy9sahfVJNzJ02apAULFqi+vn7gWDAYVH19fchdleEEAgGdOHFCTqczup4CAIAJL+qhosrKSq1Zs0a33nqrSkpK9OSTT6qnp0f33XefJGn16tWaOnWqampqJEnf//73dfvtt2vWrFn6+OOP9dhjj+nMmTN64IEHzP1LAABA0os6uNxzzz363//9X333u9+V1+vVvHnzVFdXNzBh9+zZs0pJ+exGzkcffaQHH3xQXq9X11xzjRYsWKAjR46ooKDAvL8CAABMCDFNzl2/fr3Wr18f9ncNDQ0hr7du3aqtW7fG8jEAAAAh2KsIAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABYBsEFAABY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", "text/plain": [ "
" ] @@ -120,9 +254,7 @@ } ], "source": [ - "points = gen_points(mean,sd,nb,dim,clusters)\n", - "visualisation(points, dim=dim)\n", - "# kmeans()" + "visualisation(points, Pc, dim=dim)" ] } ], diff --git a/Projet/Projet.md b/Projet/Projet.md new file mode 100644 index 0000000..48c1c00 --- /dev/null +++ b/Projet/Projet.md @@ -0,0 +1,9 @@ +# Optimisation robot +Trouver meilleurs compromis performance/consommation. +Répartition sur 5/6 groupes. +On peut commencer dès que les groupes sont faits. + + +## Jetson +Pour optimiser le code, il faut connaître le matériel. +Faire beaucoup de doc et de tests :) \ No newline at end of file diff --git a/T1/Cours.md b/T1/Cours/Cours.md similarity index 81% rename from T1/Cours.md rename to T1/Cours/Cours.md index c3dfef1..569947a 100644 --- a/T1/Cours.md +++ b/T1/Cours/Cours.md @@ -14,5 +14,6 @@ p6. temps exécution = nombre instruction * temps moyen par instruction * temps p8. instructions simples, donc décomposition des instructions complexes en instructions simples. -### T1-C3 Pipeline +### T1-C5 Hiérarchie mémoire +p2: courbe correspondant à une technologie, on ne sait pas laquelle. diff --git a/T1/T1-01-intro.pdf b/T1/Cours/T1-01-intro.pdf similarity index 100% rename from T1/T1-01-intro.pdf rename to T1/Cours/T1-01-intro.pdf diff --git a/T1/T1-02-jeux-instructions.pdf b/T1/Cours/T1-02-jeux-instructions.pdf similarity index 100% rename from T1/T1-02-jeux-instructions.pdf rename to T1/Cours/T1-02-jeux-instructions.pdf diff --git a/T1/T1-03-pipe.pdf b/T1/Cours/T1-03-pipe.pdf similarity index 100% rename from T1/T1-03-pipe.pdf rename to T1/Cours/T1-03-pipe.pdf diff --git a/T1/T1-04-ilp.pdf b/T1/Cours/T1-04-ilp.pdf similarity index 100% rename from T1/T1-04-ilp.pdf rename to T1/Cours/T1-04-ilp.pdf diff --git a/T1/T1-05-cache.pdf b/T1/Cours/T1-05-cache.pdf similarity index 100% rename from T1/T1-05-cache.pdf rename to T1/Cours/T1-05-cache.pdf diff --git a/T1/T1-06-optim.pdf b/T1/Cours/T1-06-optim.pdf similarity index 100% rename from T1/T1-06-optim.pdf rename to T1/Cours/T1-06-optim.pdf diff --git a/T1/T1-C1.pdf b/T1/Cours/T1-C1.pdf similarity index 100% rename from T1/T1-C1.pdf rename to T1/Cours/T1-C1.pdf diff --git a/T1/T1-TD1-corr.pdf b/T1/TD/T1-TD1-corr.pdf similarity index 100% rename from T1/T1-TD1-corr.pdf rename to T1/TD/T1-TD1-corr.pdf diff --git a/T1/T1-TD1.pdf b/T1/TD/T1-TD1.pdf similarity index 100% rename from T1/T1-TD1.pdf rename to T1/TD/T1-TD1.pdf diff --git a/T1/T1-TD2-corr.pdf b/T1/TD/T1-TD2-corr.pdf similarity index 100% rename from T1/T1-TD2-corr.pdf rename to T1/TD/T1-TD2-corr.pdf diff --git a/T1/T1-TD2.pdf b/T1/TD/T1-TD2.pdf similarity index 100% rename from T1/T1-TD2.pdf rename to T1/TD/T1-TD2.pdf diff --git a/T1/TD/[SETI]T1_TD/Bibliographie.bib b/T1/TD/[SETI]T1_TD/Bibliographie.bib new file mode 100644 index 0000000..db51f53 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/Bibliographie.bib @@ -0,0 +1,14 @@ + + + +@article{Ref, + author = "", + title = "", + journal = "", + volume = "", + number = "", + pages = "", + year = "", + DOI = "", + keywords = "" +} \ No newline at end of file diff --git a/T1/TD/[SETI]T1_TD/Content/TD1.tex b/T1/TD/[SETI]T1_TD/Content/TD1.tex new file mode 100644 index 0000000..13c5bfc --- /dev/null +++ b/T1/TD/[SETI]T1_TD/Content/TD1.tex @@ -0,0 +1,232 @@ +\chapter{Processeurs scalaires, superscalaires et VLIW} + +\section{Prédiction de branchement} + +Un branchement a le comportement suivant, où N signifie non pris, P signifie pris et P*k indique une suite de k branchements pris.\\ +PPNP*kNP*kNP*kNP*kNP*k... + +\subsection{Prédiction après phase d'initialisation} + +\subsubsection{a)} + +Pour un prédicteur 1 bit, à chaque mauvaise prédiction la prochaine prédiction sera inversée ou plutôt on ne change pas la prédiction tant qu'elle est bonne. + +- $k=1$ + +\begin{tabular}{l l} + Branchement &: P P N P N P N P N P \\ + Prédicteur &: \color{blue}{X} \color{green}{P} \color{red}{P N P N P N P N} +\end{tabular} + +Prédictions bonnes à $\frac{k-1}{(k-1)+2} = 0 \implies 0\%$ + +- $k=3$ + +\begin{tabular}{l l} + Branchement &: P P N P P P N P P P N P P P N P P P\\ + Prédicteur &: \color{blue}{X} \color{green}{P} \color{red}{P N} \color{green}{P P} \color{red}{P N} \color{green}{P P} \color{red}{P N} \color{green}{P P} \color{red}{P N} \color{green}{P P} +\end{tabular} + +Prédiction bonnes à $\frac{k-1}{(k-1)+2} = \frac{1}{2} \implies 50\%$ + +- $k=5$ + +\begin{tabular}{l l} + Branchement &: P P N P P P P P N P P P P P N P P P P P N P P P P P\\ + Prédicteur &: \color{blue}{X} \color{green}{P} \color{red}{P N} \color{green}{P P P P} \color{red}{P N} \color{green}{P P P P} \color{red}{P N} \color{green}{P P P P} \color{red}{P N} \color{green}{P P P P} +\end{tabular} + +Prédiction bonnes à $\frac{k-1}{(k-1)+2} = \frac{4}{6} \implies 66\%$ + +On a bien la conclusion que plus une boucle est longue et donc une répétition de branchements est importante et plus le prédicteur sera efficace. + +\subsubsection{b)} + +Pour un prédicteur 2 bits, on passe d'un niveau fort (FX) à faible (fx) lors d'une erreur de prédiction avant de changer la prédiction de branchement. Lorsque la prédiction est bonne en revanche, on passe d'un état faible à un état fort. + +FP $\iff$ fp $\iff$ fn $\iff$ FN + +- $k=1$ + +\begin{tabular}{l l} + Branchement &: P ~~~~~P ~~~~N ~~P ~N ~~P ~N ~~P ~N ~P \\ + Prédicteur &: \color{blue}{fx} \color{green}{FP|fp} \color{red}{FP} \color{green}{fp} \color{red}{FP} \color{green}{fp} \color{red}{FP} \color{green}{fp} \color{red}{FP} \color{green}{fp} +\end{tabular} + +Prédictions bonnes de 50\% à condition de ne pas commencer par FNP. + +- $k=3$ + +\begin{tabular}{l l} + Branchement &: P ~~~~~P ~~~~N ~~P ~P ~~P ~~N ~~P ~~P ~~P ~~N ~~P ~~P ~~P ~~N ~~P ~~P ~P\\ + Prédicteur &: \color{blue}{fx} \color{green}{FP|fp} \color{red}{FP} \color{green}{fp FP FP} \color{red}{FP} \color{green}{fp FP FP} \color{red}{FP} \color{green}{fp FP FP} \color{red}{FP} \color{green}{fp FP FP} +\end{tabular} + +Prédictions bonnes à 75\%. Si la première prédiction est à FN, on perd seulement la validité de quelques (4) premiers branchements. + +- $k=5$ + +(FX $\longrightarrow$ X, fx $\longrightarrow$ x) + +\begin{tabular}{l l} + Branchement &: P ~~~~~P ~~~N P P P P P N P P P P P N P P P P P N P P P P P\\ + Prédicteur &: \color{blue}{fx} \color{green}{FP|fp} \color{red}{P} \color{green}{p P P P P} \color{red}{~P} \color{green}{p P P P P} \color{red}{P} \color{green}{p P P P P} \color{red}{~P} \color{green}{p P P P P} +\end{tabular} + +Prédiction bonnes à 83\% avec le même problème que pour $k=3$. + +On remarque cette fois-ci que le taux de bonne prédiction suit $\frac{k}{(k-1)+2}$. +On devient plus résilient aux boucles imbriquées. + +\subsection{Prédicteur un bit et un bit d'historique initialisé à N} +Prédicteur P : si P est une bonne prédiction, le reste de ses prédictions sera à N sinon il sera à P.\\ +Prédicteur N : si N est une bonne prédiction, le reste de ses prédictions sera à N sinon à P. + +- $k=1$ + +\begin{tabular}{llllllllllll} + Branchement &: &P &P &N &P &N &P &N &P &N &P \\ + Historique &: &\color{blue}X &\color{blue}P &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}N \\ + Prédicteur P &: &\color{blue}X &\color{green}\boxed{P} &\color{red}\boxed{P} &\color{red}N &\color{green}\boxed{N} &\color{red}N &\color{green}\boxed{N} &\color{red}N &\color{green}\boxed{N} &\color{red}N \\ + Prédicteur N &: &\color{blue}X &\color{red}N &\color{green}N &\color{red}\boxed{N} &\color{red}P &\color{green}\boxed{P} &\color{red}P &\color{green}\boxed{P} &\color{red}P &\color{green}\boxed{P} +\end{tabular} + +Prédictions bonnes à 100\% car le cycle de répétition (période) est de 2 ce qui est la limite d'historique pour un prédicteur 1 bit ($2^1$). + +- $k=3$ + +\begin{tabular}{llllllllllllllllllll} + Branchement &: &P &P &N &P &P &P &N &P &P &P &N &P &P &P &N &P &P &P\\ + Historique &: &\color{blue}X &\color{blue}P &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}P &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}P &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}P &\color{blue}P &\color{blue}N &\color{blue}P &\color{blue}P \\ + Prédicteur P &: &\color{blue}{X} &\color{green}\boxed{P} &\color{red}\boxed{P} &\color{gray}N &\color{red}\boxed{N} &\color{green}\boxed{P} &\color{red}{\boxed{P}} &\color{gray}N &\color{red}\boxed{N} &\color{green}\boxed{P} &\color{red}{\boxed{P}} &\color{gray}N &\color{red}\boxed{N} &\color{green}\boxed{P} &\color{red}{\boxed{P}} &\color{gray}N &\color{red}\boxed{N} &\color{green}\boxed{P}\\ + Prédicteur N &: &\color{blue}{X} &\color{gray}{N} &\color{gray}{N} &\color{red}\boxed{N} &\color{gray}P &\color{gray}P &\color{gray}{P} &\color{green}\boxed{P} &\color{gray}P &\color{gray}P &\color{gray}{P} &\color{green}\boxed{P} &\color{gray}P &\color{gray}P &\color{gray}{P} &\color{green}\boxed{P} &\color{gray}P &\color{gray}P +\end{tabular} + +Prédiction bonnes à 50\% + +- $k=5$ + +\begin{tabular}{l l} + Branchement &: P P N P P P P P N P P P P P N P P P P P N P P P P P\\ + Historique &: \color{blue}X P P N P P P P P N P P P P P N P P P P P N P P P P \\ + Prédicteur P &: \color{blue}{X} \color{green}{P} \color{red}{P} \color{gray}{N} \color{red}{N} \color{green}{P P P} \color{red}{P} \color{gray}{N} \color{red}{N} \color{green}{P P P} \color{red}{P} \color{gray}{N} \color{red}{N} \color{green}{ P P P} \color{red}{P} \color{gray}{N} \color{red}{N} \color{green}{P P P}\\ + Prédicteur N &: \color{blue}{X} \color{gray}{N N} \color{green}P \color{gray}{ P P P P P} \color{green}{P} \color{gray}{P P P P P} \color{green}{P} \color{gray}{P P P P P} \color{green}{P} \color{gray}{P P P P} +\end{tabular} + +Prédiction bonnes de $\frac{2}{3}$ + +\section{Processeurs scalaires et superscalaires : exécution de boucles} + +\subsection{Version scalaire du processeur et caches parfaits +(aucun cycle d’attente mémoire)} + +Corps du programme en assembleur : + +\begin{minted}[linenos, breaklines, frame = single]{asm} +boucle: +lf f1, (r1) //f1 ← x[i] +lf f2, (r2) //f2 ← y[i] +fmul f1, f1, f0 //f1 ← x[i]*a +NOP*3 +fadd f2, f2, f1 //f2 ← y[i]+x[i]*a +NOP*3 +sf f2, (r2) //y[i] ← f2 +addi r1, r1, 4 //x[i++] +addi r2, r2, 4 //y[i++] +addi r3, r3, -1 //i++ +bne r3, boucle //1000 itérations +\end{minted} + +On part de la valeur i (r3) = 1000 jusqu'à 0 (while(i>0)) et on incrémente les indices en conséquence. +Avec les 6 NOP, on arrive à 15 cycles/opérations. + +On optimise les latences en modifiant les chargements et incrémentation d'indices. + +\begin{minted}[linenos, breaklines, frame = single]{asm} +boucle: +lf f1, (r1) //f1 ← x[i] +lf f2, (r2) //f2 ← y[i] +fmul f1, f1, f0 //f1 ← x[i]*a +addi r1, r1, 4 //x[i++] +addi r2, r2, 4 //y[i++] +addi r3, r3, -1 //i-- +fadd f2, f2, f1 //f2 ← y[i]+x[i]*a +NOP*3 +sf f2, -4(r2) //y[i-1] ← f2 +bne r3, boucle //1000 itérations +\end{minted} +On gagne 3 cycles par opération soit 12 cycles/op. + +\subsection{Version déroulée} +\begin{minted}[linenos, breaklines, frame = single]{asm} +boucle: +lf f1, (r1) //f1 ← x[i] +lf f3, 4(r1) //f3 ← x[i+1] +lf f5, 8(r1) //f5 ← x[i+2] +lf f7, 12(r1) //f7 ← x[i+3] +lf f2, (r2) //f2 ← y[i] +lf f4, 4(r2) //f4 ← y[i+1] +lf f6, 8(r2) //f6 ← y[i+2] +lf f8, 12(r2) //f8 ← y[i+3] +fmul f1, f1, f0 //f1 ← x[i]*a +fmul f3, f3, f0 //f3 ← x[i+1]*a +fmul f5, f5, f0 //f5 ← x[i+2]*a +fmul f7, f7, f0 //f7 ← x[i+3]*a +fadd f2, f2, f1 //f2 ← y[i]+x[i]*a +fadd f4, f4, f3 //f4 ← y[i+1]+x[i+1]*a +fadd f6, f6, f5 //f6 ← y[i+2]+x[i+2]*a +fadd f8, f8, f7 //f8 ← y[i+3]+x[i+3]*a +addi r1, r1, 16 //x[i++] +addi r2, r2, 16 //x[i++] +addi r3, r3, -4 //i++ +sf f2, -12(r2) //y[i-3] ← f2 +sf f4, -8(r2) //y[i-2] ← f4 +sf f6, -4(r2) //y[i-1] ← f6 +sf f8, (r2) //y[i] ← f8 +bne r3, boucle //1000 itérations +\end{minted} + +On a 24 cycles pour 4 itérations, soit 6 cycles/itération. + +\subsection{Superscalaire} + +\begin{tabular}{r|c|c|c|c} + &E0 & E1 & FM & FA \\ + \hline + 1&lf f1,(r1) & & &\\ + 2&lf f2,(r2) & & & \\ + 3&addi r1,r1,4& addi r2,r2,4&fmul f1,f1,f0 & \\ + 4&addi r3,r3,-1&&&\\ + 5&&&&\\ + 6&&&&\\ + 7&& & & fadd f2,f2,f1\\ + 8&& & & \\ + 9&&&&\\ + 10&&&&\\ + 11& sf f2,-4(r2)&bne r3, boucle & & +\end{tabular} + +On ne gagne qu'un cycle avec cette version (11cycles/itération). + +\subsection{Superscalaire déroulé} + +\begin{tabular}{r|c|c|c|c} + &E0 & E1 & FM & FA \\ + \hline + 1&lf f1,(r1) & lf f3,4(r1) & &\\ + 2& lf f5,8(r1)& lf f7,12(r1) & &\\ + 3& lf f2,(r2)& lf f4,4(r2)& fmul f1,f1,f0&\\ + 4& lf f6,8(r2)& lf f8,12(r2)& fmul f3,f3,f0&\\ + 5& addi r1,r1,16& addi r2,r2,16& fmul f5,f5,f0 & \\ + 6& addi r3,r3,-4& & fmul f5,f5,f0& \\ + 7&&&& fadd f2,f2,f1\\ + 8&&&& fadd f4,f4,f3\\ + 9&&&& fadd f6,f6,f5\\ + 10&& & & fadd f8,f8,f7\\ + 11&sf f2,-12(r2) & & & \\ + 12&sf f4,-8(r2)&&&\\ + 13&sf f6,-4(r2)&&&\\ + 14&sf f8, (r2) &bne r3, boucle & & +\end{tabular} + +Cette fois-ci, on utilise 14 cycles pour 4 itérations, soit 3,5 cycles/itération. \ No newline at end of file diff --git a/T1/TD/[SETI]T1_TD/Content/useful_commands.tex b/T1/TD/[SETI]T1_TD/Content/useful_commands.tex new file mode 100644 index 0000000..17a1e79 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/Content/useful_commands.tex @@ -0,0 +1,69 @@ + +% -------------------- Plot -------------------- + +\begin{figure}[ht] + \centering + \includegraphics[width = 0.3\linewidth]{} + \caption{} +\end{figure} + +% -------------------- Subplot -------------------- + +\begin{figure}[ht] + \centering + \begin{subfigure}[b]{0.4\textwidth} + \includegraphics[width = \linewidth]{} + \caption{} + \end{subfigure} + \hfill + \begin{subfigure}[b]{0.4\textwidth} + \includegraphics[width = \linewidth]{} + \caption{} + \end{subfigure} + \caption{} +\end{figure} + +% -------------------- Bullet list -------------------- + +\begin{list}{\textbullet}{} + +\end{list} + +% -------------------- Code matlab -------------------- + +\begin{minted}[linenos, breaklines, frame = single]{matlab} + +\end{minted} + +% -------------------- Separate the sheet into smaller sheets ---------------- + +\begin{minipage}{0.55\linewidth} + +\end{minipage}\hfill +\begin{minipage}{0.45\linewidth} + \begin{figure}[H] + \centering + \includegraphics[width = 0.3\linewidth]{TitlePage/ens_logo.png} + \caption{} + \end{figure} +\end{minipage} + +% ------------------- Biblio ------------------ + +@article{Ref, + author = "", + title = "", + journal = "", + volume = "", + number = "", + pages = "", + year = "", + DOI = "", + keywords = "" +} + +@misc{ref, +author = "", +title = "", +url = {} +} \ No newline at end of file diff --git a/T1/TD/[SETI]T1_TD/TitlePage/ens_logo.png b/T1/TD/[SETI]T1_TD/TitlePage/ens_logo.png new file mode 100644 index 0000000..17e881f Binary files /dev/null and b/T1/TD/[SETI]T1_TD/TitlePage/ens_logo.png differ diff --git a/T1/TD/[SETI]T1_TD/TitlePage/titlepage.tex b/T1/TD/[SETI]T1_TD/TitlePage/titlepage.tex new file mode 100644 index 0000000..3a33270 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/TitlePage/titlepage.tex @@ -0,0 +1,48 @@ +\begin{titlepage} + \makeatletter + \begin{center} + + % ------- Main logo -------- + \null\vspace{1.1cm} + \includegraphics[width=.65\linewidth]{\@mainlogo}\\[2cm] + + % ------ Project type ------ + \ifdefined \@field {\large \@field}\\[0.2\baselineskip] \fi + \ifdefined \@project {\large \@project}\\ \fi + \vspace{.65cm} + + % ------- Top rule -------- + \hrule width \hsize height .5mm % Thick horizontal rule + \vspace{.035\textheight} % White space between the top rule and title + + % --------- Title ---------- + \begin{minipage}{.85\textwidth} + \bfseries\Huge\centering + \textcolor{black}{\@title} + \end{minipage} + + % ------ Bottom rule ------ + \vspace{.035\textheight} % White space between the bottom rule and title + \hrule width \hsize height 0.5mm % Thick horizontal rule + + \vspace{.065\textheight} + + % --------- Author --------- + \textsc{ + \Large + \begin{tabular}[t]{c} + \@author % Author name (array) + \end{tabular} + } + + \vspace{.02\textheight} % White space between the author name and date + + \vfill % White space between the date and publisher + + \end{center} + + % ---------- Bottom of the page ---------- + {\large\textsc{\@date}}\hfill % Date of publishing + + \makeatother +\end{titlepage} \ No newline at end of file diff --git a/T1/TD/[SETI]T1_TD/TitlePage/ups_logo.png b/T1/TD/[SETI]T1_TD/TitlePage/ups_logo.png new file mode 100644 index 0000000..0da8629 Binary files /dev/null and b/T1/TD/[SETI]T1_TD/TitlePage/ups_logo.png differ diff --git a/T1/TD/[SETI]T1_TD/main.aux b/T1/TD/[SETI]T1_TD/main.aux new file mode 100644 index 0000000..f23e546 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/main.aux @@ -0,0 +1 @@ +\relax diff --git a/T1/TD/[SETI]T1_TD/main.fdb_latexmk b/T1/TD/[SETI]T1_TD/main.fdb_latexmk new file mode 100644 index 0000000..06848e4 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/main.fdb_latexmk @@ -0,0 +1,24 @@ +# Fdb version 3 +["pdflatex"] 1666439580 "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.tex" "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.pdf" "main" 1666439580 + "/etc/texmf/web2c/texmf.cnf" 1666438621 475 c0e671620eb5563b2130f56340a5fde8 "" + "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/fouriernc.sty" 0 -1 0 "" + "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.aux" 1666439580 8 a94a2480d3289e625eea47cd1b285758 "" + "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.tex" 1666431070 923 abf7d419c375b72e4f4f9c709bb179f9 "" + "/usr/share/texlive/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 "" + "/usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr12.tfm" 1136768653 1288 655e228510b4c2a1abe905c368440826 "" + "/usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty" 1573336935 6902 30fdaf7dc5636b8e3afa306210c45cae "" + "/usr/share/texlive/texmf-dist/tex/generic/iftex/ifvtex.sty" 1572645307 1057 525c2192b5febbd8c1f662c9468335bb "" + "/usr/share/texlive/texmf-dist/tex/latex/base/report.cls" 1580683321 23082 a0e9a5941c744eda6abe56770037a201 "" + "/usr/share/texlive/texmf-dist/tex/latex/base/size12.clo" 1580683321 8447 5c4b8ee712f8e349df2722115bc8c513 "" + "/usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty" 1578002852 41601 9cf6c5257b1bc7af01a58859749dd37a "" + "/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty" 1580683321 2590 e3b24ff953e5b58d924f163d25380312 "" + "/usr/share/texlive/texmf-dist/web2c/texmf.cnf" 1581979058 38841 ce3692aa899bb693b90b87eaa5d4d84e "" + "/usr/share/texmf/web2c/texmf.cnf" 1581979058 38841 ce3692aa899bb693b90b87eaa5d4d84e "" + "/var/lib/texmf/web2c/pdftex/pdflatex.fmt" 1666439343 4810548 a74f27742f4cc733b879ee587b4a5a24 "" + "fouriernc.sty" 0 -1 0 "" + "main.tex" 1666431070 923 abf7d419c375b72e4f4f9c709bb179f9 "" + "setup.tex" 1666431070 6569 45b84894af7d35b3cf1be8404cef5ccb "" + (generated) + "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.pdf" + "/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.log" + "main.log" diff --git a/T1/TD/[SETI]T1_TD/main.fls b/T1/TD/[SETI]T1_TD/main.fls new file mode 100644 index 0000000..6f39c0b --- /dev/null +++ b/T1/TD/[SETI]T1_TD/main.fls @@ -0,0 +1,23 @@ +PWD /home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD +INPUT /etc/texmf/web2c/texmf.cnf +INPUT /usr/share/texmf/web2c/texmf.cnf +INPUT /usr/share/texlive/texmf-dist/web2c/texmf.cnf +INPUT /var/lib/texmf/web2c/pdftex/pdflatex.fmt +INPUT /home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.tex +OUTPUT /home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.log +INPUT /usr/share/texlive/texmf-dist/tex/latex/base/report.cls +INPUT /usr/share/texlive/texmf-dist/tex/latex/base/report.cls +INPUT /usr/share/texlive/texmf-dist/tex/latex/base/size12.clo +INPUT /usr/share/texlive/texmf-dist/tex/latex/base/size12.clo +INPUT /usr/share/texlive/texmf-dist/fonts/map/fontname/texfonts.map +INPUT /usr/share/texlive/texmf-dist/fonts/tfm/public/cm/cmr12.tfm +INPUT /home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/setup.tex +INPUT /home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/setup.tex +INPUT /usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty +INPUT /usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty +INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty +INPUT /usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty +INPUT /usr/share/texlive/texmf-dist/tex/generic/iftex/ifvtex.sty +INPUT /usr/share/texlive/texmf-dist/tex/generic/iftex/ifvtex.sty +INPUT /usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty +INPUT /usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty diff --git a/T1/TD/[SETI]T1_TD/main.log b/T1/TD/[SETI]T1_TD/main.log new file mode 100644 index 0000000..6260bfb --- /dev/null +++ b/T1/TD/[SETI]T1_TD/main.log @@ -0,0 +1,72 @@ +This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019/Debian) (preloaded format=pdflatex 2022.10.22) 22 OCT 2022 13:53 +entering extended mode + restricted \write18 enabled. + file:line:error style messages enabled. + %&-line parsing enabled. +**/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.tex +(/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/main.tex +LaTeX2e <2020-02-02> patch level 2 +L3 programming layer <2020-02-14> (/usr/share/texlive/texmf-dist/tex/latex/base/report.cls +Document Class: report 2019/12/20 v1.4l Standard LaTeX document class +(/usr/share/texlive/texmf-dist/tex/latex/base/size12.clo +File: size12.clo 2019/12/20 v1.4l Standard LaTeX file (size option) +) +\c@part=\count167 +\c@chapter=\count168 +\c@section=\count169 +\c@subsection=\count170 +\c@subsubsection=\count171 +\c@paragraph=\count172 +\c@subparagraph=\count173 +\c@figure=\count174 +\c@table=\count175 +\abovecaptionskip=\skip47 +\belowcaptionskip=\skip48 +\bibindent=\dimen134 +) (/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/setup.tex (/usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty +Package: geometry 2020/01/02 v5.9 Page Geometry + (/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 2014/10/28 v1.15 key=value parser (DPC) +\KV@toks@=\toks14 +) (/usr/share/texlive/texmf-dist/tex/generic/iftex/ifvtex.sty +Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead. + (/usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty +Package: iftex 2019/11/07 v1.0c TeX engine tests +)) +\Gm@cnth=\count176 +\Gm@cntv=\count177 +\c@Gm@tempcnt=\count178 +\Gm@bindingoffset=\dimen135 +\Gm@wd@mp=\dimen136 +\Gm@odd@mp=\dimen137 +\Gm@even@mp=\dimen138 +\Gm@layoutwidth=\dimen139 +\Gm@layoutheight=\dimen140 +\Gm@layouthoffset=\dimen141 +\Gm@layoutvoffset=\dimen142 +\Gm@dimlist=\toks15 +) + +! LaTeX Error: File `fouriernc.sty' not found. + +Type X to quit or to proceed, +or enter new name. (Default extension: sty) + +Enter file name: +/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/setup.tex:5: Emergency stop. + + +l.5 \usepackage + [utf8]{inputenc} % Required for inputting international UTF-8... +*** (cannot \read from terminal in nonstop modes) + + +Here is how much of TeX's memory you used: + 789 strings out of 483154 + 10866 string characters out of 5965022 + 241641 words of memory out of 5000000 + 15886 multiletter control sequences out of 15000+600000 + 532636 words of font info for 25 fonts, out of 8000000 for 9000 + 14 hyphenation exceptions out of 8191 + 33i,0n,27p,208b,36s stack positions out of 5000i,500n,10000p,200000b,80000s +/home/higepi/Documents/M2R_SETI/M2_SETI/T1/TD/[SETI]T1_TD/setup.tex:5: ==> Fatal error occurred, no output PDF file produced! diff --git a/T1/TD/[SETI]T1_TD/main.tex b/T1/TD/[SETI]T1_TD/main.tex new file mode 100644 index 0000000..7382bb8 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/main.tex @@ -0,0 +1,44 @@ +\documentclass[a4paper, 12pt, french]{report} +\input{setup.tex} + +\begin{document} + + % Title page placeholders + \title{T1 - Architecture avancée - TD} + \author{Saša Radosavljevic} + \date{\today} + \field{M2 E3A - SETI} + \mainlogo{TitlePage/ups_logo.png} + + + % Make title page + \include{TitlePage/titlepage} + \newpage + \ + \thispagestyle{empty} + \newpage + % Front matter - Page numbers in alphabetic style + \changepagenumbering{arabic} + + % TOC - links are black to ensure color integrity + { + \hypersetup{linkcolor=black} + \tableofcontents + } + + % Set new paragraph style after the TOC + \setlength{\parindent}{0em} % Indentation size to none + \setlength{\parskip}{1em} % Paragraph intervall size + + \include{Content/TD1} + + % Main matter - Include every chapter/part here + + + \printbibliography + + + + + +\end{document} diff --git a/T1/TD/[SETI]T1_TD/setup.tex b/T1/TD/[SETI]T1_TD/setup.tex new file mode 100644 index 0000000..a0837b0 --- /dev/null +++ b/T1/TD/[SETI]T1_TD/setup.tex @@ -0,0 +1,127 @@ +\usepackage[top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry} + +% ----------------- Fonts, encoding and language packages ------------------ +\usepackage{fouriernc} % Use the New Century Schoolbook font +\usepackage[utf8]{inputenc} % Required for inputting international UTF-8 characters +\usepackage[T1]{fontenc} % Output font encoding for international characters +\usepackage{babel} % Language package (language is defined in documentclass) +\usepackage{setspace} % Font/line (and others) spacing configuration +\usepackage{tocbibind} % Insert TOC reference link into TOC +\usepackage[section]{placeins} % Place figures in their section only + +% ------------- Tables, figures and other special environments ------------- +\usepackage{graphicx} % Import and manage graphics +\usepackage{tabularx} % Better table control (ie. auto cell's width) +\usepackage{multirow} % Allows multirow cells in tables +\usepackage{pdfpages} % Insert PDF documents +\usepackage{subcaption} % To use subfigures +\usepackage[export]{adjustbox} % Adjust figures position +\usepackage{marginnote} % Insert notes in doc margins + +% Table column types (gray italic column / centered expanding column) +\newcolumntype{\grayc}{>{\itshape\large\raggedright\arraybackslash\columncolor{gray90}}c} +\newcolumntype{\centerX}{>{\centering\arraybackslash}X} + +% --------------------- Codes and scripts environments --------------------- +\usepackage{listings} % Create lists with line numbers (used for code view) +\usepackage{minted} % Color syntax for scripts in multiple languages + +% ----------------------------- Color defines ------------------------------ +\usepackage{xcolor,colortbl} % Table cells color editing +\usepackage{color} % Main color package (define colors) +\definecolor{accentcolor}{RGB}{0,119,139} % Accent color used in the whole doc +\definecolor{gray75}{gray}{0.75} % Title lines main color +\definecolor{gray90}{gray}{0.90} % Table main rows/columns +\definecolor{darkgreen}{rgb}{.0, .5, .0} % EXTENDS command color + +% Insert links, color them and modify PDF settings +\usepackage[colorlinks=true,allcolors=accentcolor,bookmarks=true]{hyperref} + +\definecolor{ENSBlue}{RGB}{0, 119, 139} +\definecolor{ENSGrey}{rgb}{0.3, 0.3, 0.3} +\definecolor{ENSLightGrey}{RGB}{190, 200, 200} +\definecolor{ENSDarkBlue}{RGB}{10, 50, 80} +\definecolor{matlabGreen}{RGB}{28, 172, 0} % Pour le listing des codes +\definecolor{matlabLilas}{RGB}{170, 55, 241} + +% -------------------- Bibliography configuration -------------------------- +\usepackage[backend=biber,style=numeric,sorting=none]{biblatex} +\usepackage{csquotes} % To ensure quotes with biblatex are working well +\addbibresource{Bibliographie.bib} % Bibliography file to load + +% --------------------------- Title style editing -------------------------- +\usepackage{titlesec} % Lets modify header styles (chapter, section, etc) +\newcommand{\hspct}{\hspace{18pt}} % Horizontal space for chapter title +\newcommand{\hspst}{\hspace{9pt}} % Horizontal space for section title +\newcommand{\hspsst}{\hspace{4.5pt}} % Horizontal space for subsection title + +\titleformat{\chapter}[hang] + {\color{ENSBlue}\Huge\bfseries\raggedright} % Huge size and bold font + {\thechapter\hspct % Number and horizontal space + \textcolor{ENSBlue}{\rule[-0.25\baselineskip]{5pt}{\baselineskip}} + \hspct}{0pt}{} % Horizontal space then name + +\titleformat{\section}[hang] + {\color{ENSBlue}\Large\bfseries\raggedright} % Huge size and bold font + {\thesection\hspst\textcolor{ENSDarkBlue}{-}\hspst}{0pt}{} % Number, horizontal space then name + [\hrule height 0.5pt] + +\titleformat{\subsection}[hang] + {\color{ENSBlue}\large\bfseries\raggedright} % Color, Huge size and bold font + {\thesubsection\hspsst\textcolor{ENSDarkBlue}{-}\hspsst}{0pt}{} % Number, horizontal space then name + +\titleformat{\subsubsection}[hang] + {\color{ENSBlue}\large\bfseries\raggedright} % Color, Huge size and bold font + {\thesubsection\hspsst\textcolor{ENSDarkBlue}{-}\hspsst}{0pt}{} % Number, horizontal space then name + +\titleformat{\subsubsubsection}[hang] + {\color{ENSBlue}\large\bfseries\raggedright} % Color, Huge size and bold font + {\thesubsection\hspsst\textcolor{ENSDarkBlue}{-}\hspsst}{0pt}{} % Number, horizontal space then name + + +% -------------------------- Mathematic packages -------------------------- +\usepackage{amsmath} % Create matrices, subequations and more +\usepackage{amssymb} % Math font to create symbols from characters + +% Mathematic new commands +\newcommand{\sgn}{\text{sgn}} % Sign function as text + +% -------------------------- FRENCH translations -------------------------- + +\iflanguage{french}{ % Replace "Table" with "Tableau" in FRENCH only + \AtBeginDocument{\renewcommand\tablename{\textsc{Tableau}}} + \AtBeginDocument{\renewcommand\listingscaption{\textsc{Code}}} + \AtBeginDocument{\renewcommand\lstlistlistingname{Liste des codes}} +} + +% -------------------------- New useful commands -------------------------- +\newcommand{\todo}[1]{\textbf{\textcolor{blue}{(TODO: #1)}} \PackageWarning{setup}{#1}} % TODO command +\newcommand{\extend}[1]{\textbf{\textcolor{darkgreen}{(EXTEND: #1)}} \PackageWarning{setup}{#1}} % EXTENDS command +\newcommand{\draft}[1]{\textbf{\textcolor{red}{(DRAFT: #1)}} \PackageWarning{setup}{#1}} % DRAFT command + +% Reset page number and change page numbering style +\newcommand{\changepagenumbering}[1]{ + \setcounter{page}{1} + \pagenumbering{#1} +} + +\makeatletter +\newcommand*{\field}[1]{\gdef\@field{#1}} % Defines "field" variable used in title page +\newcommand*{\project}[1]{\gdef\@project{#1}} % Defines "project" variable used in title page +\newcommand*{\mainlogo}[1]{\gdef\@mainlogo{#1}} % Defines "mainlogo" variable used in title page +\newcommand*{\logoCN}[1]{\gdef\@logoCN{#1}} % Defines "optionallogo" variable used in title page +\newcommand*{\logoCNRS}[1]{\gdef\@logoCNRS{#1}} % Defines "optionallogo" variable used in title page +\makeatother + +% Existing environments configuration +\usepackage{etoolbox} % Allows to append commands to existing environements + +\iflanguage{english}{ + \AtBeginEnvironment{itemize}{\setlength{\baselineskip}{0em}} % Change itemize line skip + \AtBeginEnvironment{itemize}{\setlength{\parskip}{.7em}} % Change itemize line vertical space + + \AtBeginEnvironment{enumerate}{\setlength{\baselineskip}{0em}} % Change enumerate line skip + \AtBeginEnvironment{enumerate}{\setlength{\parskip}{.7em}} % Change enumerate line vertical space +} + +\AtBeginEnvironment{tabularx}{\def\arraystretch{1.6}} % Change array vertical padding within cells diff --git a/T1/tp1.pdf b/T1/TP/tp1.pdf similarity index 100% rename from T1/tp1.pdf rename to T1/TP/tp1.pdf diff --git a/T1/tp2.pdf b/T1/TP/tp2.pdf similarity index 100% rename from T1/tp2.pdf rename to T1/TP/tp2.pdf diff --git a/T1/tp3-programmes.zip b/T1/TP/tp3-programmes.zip similarity index 100% rename from T1/tp3-programmes.zip rename to T1/TP/tp3-programmes.zip diff --git a/T1/tp3.pdf b/T1/TP/tp3.pdf similarity index 100% rename from T1/tp3.pdf rename to T1/TP/tp3.pdf diff --git a/T2/T1_Cours.ipynb b/T2/T2_Cours.ipynb similarity index 100% rename from T2/T1_Cours.ipynb rename to T2/T2_Cours.ipynb