diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f8f7813 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: python +python: + - "3.6" + - "3.7" + +install: + - pip install -r requirements.txt + +script: + - pytest unit4/ \ No newline at end of file diff --git a/README.md b/README.md index 07ea68d..a8212b7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # SES2020spring ## Another day + +## The third day \ No newline at end of file diff --git a/elevator_project/Project10-1.pdf b/elevator_project/Project10-1.pdf new file mode 100644 index 0000000..e41044b Binary files /dev/null and b/elevator_project/Project10-1.pdf differ diff --git a/elevator_project/Readme.txt b/elevator_project/Readme.txt new file mode 100644 index 0000000..125ff48 --- /dev/null +++ b/elevator_project/Readme.txt @@ -0,0 +1,7 @@ +elevator.py是工程文件,直接运行 + +其中输出格式为: +Floor Customer Elevator +楼层号 ID, 上/下, 是否到达目的地 X + +test_elevator.py是测试文件,直接运行 \ No newline at end of file diff --git a/elevator_project/elevator.py b/elevator_project/elevator.py new file mode 100644 index 0000000..d2e4864 --- /dev/null +++ b/elevator_project/elevator.py @@ -0,0 +1,235 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri Apr 10 20:09:40 2020 + +@author: 85726 +""" + +""" +模拟电梯运行: +该代码模拟了某一楼层的电梯状态,为简化模型,假设要乘坐电梯的所有人在不同楼层同时按下了电梯键,电梯要做出最节省时间的方案将所有人运送到目标楼层 +电梯初始在随机的楼层,此时会根据电梯所在的楼层,如果在上半层,电梯默认初始往下运行,反之亦然 +如果电梯运行方向的楼层无乘客以及电梯内的乘客已经到达目标楼层时,电梯运行方向才会改变 +如果电梯运行途中的楼层有去向相同的乘客,则乘客进入电梯,如果电梯运行方向与乘客要去的方向相反,则乘客会在原楼层等待 +当电梯完成所有乘客的运输后,会停在最后一名乘客的目的楼层 +""" + +import random +import time + +class Building(): + def __init__(self, floors, customers): + self.floors = floors # 楼层数量 + # 创造一列乘客信息 + self.customer_list = [] + self.unfinished_customer_list = [] + for i in range(customers): + cur_floor = random.randint(1,floors) + choice_list = list(range(1, floors+1)) + choice_list.remove(cur_floor) #不会出现乘客乘坐电梯不移动楼层的情况,故去除当前层取值 + dst_floor = random.choice(choice_list) + UorD = int(abs(dst_floor-cur_floor) / (dst_floor-cur_floor)) + self.customer_list.append(Customer(cur_floor, dst_floor, i+1, UorD)) #电梯乘客包含当前楼层,目标楼层,乘客id,方向参数 + self.unfinished_customer_list = list(self.customer_list) #初始化所有要乘坐电梯的乘客 + + self.elevator = Elevator(floors) # 为楼层配置一个电梯,输入楼层数 + + + def run(self): + """operate the elevator""" + #先判断中途转向,再判断乘客进出 + + #电梯中途不改变方向的条件:运行方向上的任一楼层没有未进电梯的乘客 or 电梯内任一乘客没到达 + direction_change = [] #乘客进行投票,0为不同意,一旦有0就不改向 + + #取出运行方向上剩余的楼层号(不包括当前楼层) + if self.elevator.get_direction() > 0: + floors_list = list(range(self.elevator.get_cur_floor()+1, self.floors+1)) + else: + floors_list = list(range(1, self.elevator.get_cur_floor())) + + #遍历未finished的乘客 + for customer in self.unfinished_customer_list: + #对于在电梯里的乘客判断是否改向,默认电梯内customer.get_UorD() == self.elevator.get_direction() + if customer.get_ID() in self.elevator.get_register_list(): + #if customer.get_UorD() == self.elevator.get_direction(): + if customer.get_dst_floor() != self.elevator.get_cur_floor(): + direction_change.append(0) #同方向且乘客未到达,不同意改向 + + # 对于不在电梯里的乘客判断是否改向 + else: + #判断floors_list内是否有未进电梯的乘客 + if customer.get_cur_floor() in floors_list: + direction_change.append(0) + #判断当前层是否有未进电梯的乘客 + if customer.get_cur_floor() == self.elevator.get_cur_floor() : + if customer.get_UorD() == self.elevator.get_direction(): + direction_change.append(0) #若该乘客去的方向和电梯方向一致(即将入电梯),不同意改向 + + #中途改变运行方向 + if not 0 in direction_change: + self.elevator.direction *= -1 + print('change direction') + + # 检查每位乘客 + for customer in self.customer_list: + # 如果乘客在电梯内 + if customer.get_ID() in self.elevator.get_register_list(): + # 如果乘客到达了目标楼层 + if customer.get_dst_floor() == self.elevator.get_cur_floor(): + customer.move_out() + self.elevator.cancel_customer(customer.get_ID()) + self.unfinished_customer_list.remove(customer) + # 如果乘客不在电梯内 + else: + #增加第三个判断条件:如果电梯运行方向与乘客希望去的方向不一致,那么乘客暂时不进电梯;方向一致,进电梯 + if (not customer.has_finished()) and \ + (customer.get_cur_floor() == self.elevator.get_cur_floor()) and \ + (customer.get_UorD() == self.elevator.get_direction()): + customer.move_in() + self.elevator.register_customer(customer.get_ID()) + + # 电梯移动 + if not self.has_finished(): + self.elevator.move() + # 特殊情况限定电梯不会到达高于楼层的地方和地下 + if (self.elevator.get_cur_floor()+self.elevator.get_direction() < 1) or \ + (self.elevator.get_cur_floor()+self.elevator.get_direction() > self.floors): + self.elevator.direction *= -1 + + + def output(self): + """output the building""" + LEFT = 10 + CENTER = 60 + RIGHT = 10 + print ('-'*(LEFT+CENTER+RIGHT)) + print ("Floor".center(LEFT)+"Customer".center(CENTER)+"Elevator".center(RIGHT)) + print ('-'*(LEFT+CENTER+RIGHT)) + + for i in range(self.floors, 0, -1): + line = str(i).center(LEFT) + customer_print_list = [] + #customer打印格式: ID,up or down,finished or not + for customer in self.customer_list: + if (not customer.is_in_elevator()) and customer.get_cur_floor() == i: + customer_print_list.append(str(customer.get_ID())+','+str(customer.get_UorD())+','+str(customer.has_finished())) + line += '; '.join(customer_print_list).center(CENTER) + if i == self.elevator.get_cur_floor(): + line += 'X'.center(RIGHT) + print(line) #打印当前行的信息:floor + customer + elevator + print('-'*(LEFT+CENTER+RIGHT)) + + def get_customer_list(self):#得到全部乘客的信息 + """return the customer_list""" + return self.customer_list + + def has_finished(self):#判断电梯是否已经将所有人送到目的楼层,完成返回True + """check whether all customers have reached dst_floors""" + for customer in self.get_customer_list(): + if not customer.has_finished(): + return False + return True + +class Elevator(): + def __init__(self, floors): + self.floors = floors # 楼层数 + self.register_list = [] # 电梯内的乘客表 + self.cur_floor = random.randint(1,floors) # 模拟电梯初始楼层随机 + #若电梯的位置处于building的上半层,则往下;在下半层,则往上 + self.direction = -1 if self.cur_floor/self.floors >= 1/2 else 1 # 1:上; -1:下 + + def move(self): + """move the elevator by 1 floor""" + #移动电梯 + self.cur_floor += self.direction + + def register_customer(self, customer):#移动某位乘客进入电梯序列中 + """put the customer into register_list (ID)""" + self.register_list.append(customer) + + def cancel_customer(self, customer):#删除电梯序列中的某位乘客 + """remove the customer from register_list (ID)""" + self.register_list.remove(customer) + + def in_register_list(self, customer):#检查某位乘客是否在电梯内 + """check whether the customer is in register_list: in -> 1 ; out -> 0""" + return customer in self.register_list + + def get_register_list(self):#得到目前在电梯内的乘客表 + """return register_list""" + return self.register_list + + def get_cur_floor(self):#电梯目前所在楼层 + """return current floor""" + return self.cur_floor + + def get_direction(self):#电梯完成运输后最后所在的楼层 + """return current floor""" + return self.direction + +class Customer():#乘客信息 + def __init__(self, cur_floor, dst_floor, ID, UorD): + self.cur_floor = cur_floor + self.dst_floor = dst_floor + self.ID = ID + self.in_elevator = False # 初始乘客不在电梯内 + self.finished = False # 初始乘客未到达目标楼层 + self.UorD = UorD # 1表示乘客向上,-1表示向下 + + def get_cur_floor(self):#获得乘客当前所在楼层 + """return current floor""" + return self.cur_floor + + def get_dst_floor(self):#获得乘客目标楼层 + """return destination floor""" + return self.dst_floor + + def get_ID(self): + """return customer's ID""" + return self.ID + + def get_UorD(self): + """return customer's ID""" + return self.UorD + + def move_in(self):#当前乘客进入了电梯 + """move the customer into the elevator""" + self.in_elevator = True + + def move_out(self):#乘客离开电梯 + """move the customer out of the elevator""" + self.in_elevator = False + self.finished = True + self.cur_floor = self.dst_floor + + def has_finished(self):#返回乘客是否到达了目标楼层,到达返回True + """check whether the customer has reached the dst_floor""" + return self.finished + + def is_in_elevator(self):#返回乘客是否在电梯内,在返回True + """check whether the customer is in the elevator""" + return self.in_elevator + +def main(): + floors = input("Please input how many floors in this building: ") + while not floors.isdigit(): + floors = input("Please input how many floors in this building: ") + customers = input("Please input how many customers in this building: ") + while not customers.isdigit(): + customers = input("Please input how many customers in this building: ") + building = Building(int(floors), int(customers)) + building.output() + + # 电梯移动直到最后的一位乘客到达目标楼层 + count = 0 + while not building.has_finished(): + time.sleep(1) + building.run() + building.output() + count += 1 + print('the total floors that the elevator moves: '+str(count)) + +if __name__ == '__main__': + main() + diff --git a/elevator_project/test_elevator.py b/elevator_project/test_elevator.py new file mode 100644 index 0000000..67ac32f --- /dev/null +++ b/elevator_project/test_elevator.py @@ -0,0 +1,35 @@ +import unittest +from elevator2 import Building +from elevator2 import Elevator +from elevator2 import Customer + +# assertEqual(a,b) a==b assertNotEqual(a,b) a!=b +# assertIn(item,list) item in list assertNotIn(item,list) item not in list +# assertTrue(x) x为True assertFalse(x) x为False + +class TestElevator(unittest.TestCase): + #测试 elevator中的类Elevator + def setUp(self): + # 做些初始化操作 + # 创建类并设置属性 + # Python 将先运行它,各个方法中创建的对象,在此方法中创建,并且就创建一次,其他方法中都不用创建。 + self.my_Elevator = Elevator(6) + self.tempfloor=self.my_Elevator.cur_floor + self.tempdirection=self.my_Elevator.direction + + def test_move(self): + self.my_Elevator.move() + self.assertEqual(self.my_Elevator.cur_floor,self.tempfloor+self.tempdirection) + + def test_register_customer(self): + self.my_Elevator.register_customer(1) + self.assertIn(1,self.my_Elevator.register_list) + + def test_cancel_customer(self): + self.my_Elevator.register_customer(1) + self.my_Elevator.cancel_customer(1) + self.assertNotIn(1,self.my_Elevator.register_list) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/lr_torch.py b/lr_torch.py new file mode 100644 index 0000000..34ea93f --- /dev/null +++ b/lr_torch.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon May 11 09:18:01 2020 + +@author: gylao +""" + +import numpy as np +import torch +from torch.autograd import Variable +import pandas as pd + +def undersampling(data): + data0 = data[data[:,0]==0] + data1 = data[data[:,0]==1] + size0 = data0.shape[0] + size1 = data1.shape[0] + if size0 >= size1: + index= np.random.choice(size0,size1,replace=False,p=None) + data0 = data0[index,:] + else: + index= np.random.choice(size1,size0,replace=False,p=None) + data1 = data1[index,:] + x = np.concatenate((data0[:, 1:31], data1[:, 1:31]), axis=0) + y = np.concatenate((data0[:, 0:1], data1[:, 0:1]), axis=0) + return x, y + +def oversampling(data): + data0 = data[data[:,0]==0] + data1 = data[data[:,0]==1] + size0 = data0.shape[0] + size1 = data1.shape[0] + if size0 >= size1: + index= np.random.choice(size1,size0-size1,replace=False,p=None) + data1 = np.concatenate((data1, data1[index,:]), axis=0) + else: + index= np.random.choice(size0,size1-size0,replace=False,p=None) + data0 = np.concatenate((data0, data0[index,:]), axis=0) + x = np.concatenate((data0[:, 1:31], data1[:, 1:31]), axis=0) + y = np.concatenate((data0[:, 0:1], data1[:, 0:1]), axis=0) + return x, y + +def pre_process(dataset): + data = dataset.iloc[:, 1:32].values + data[data=='M'] = 1 + data[data=='B'] = 0 + data = data.astype(np.float64) + + #x, y = undersampling(data) + x, y = oversampling(data) + size = x.shape[0] + index = np.random.permutation(size) + x = x[index] + y = y[index] + + mu = np.mean(x, axis=0) + sigma = np.std(x, axis=0) + x = (x - mu) / sigma + + split = int(len(y)*0.7) + x_train = x[:split] + y_train = y[:split] + x_test = x[split:] + y_test = y[split:] + return x_train, y_train, x_test, y_test + +def cal_acc(x, y, y_pred): + size = x.shape[0] + y_pred = np.array([0 if y_pred[i] < 0.5 else 1 for i in range(size)]) + acc = np.mean([1 if y[i] == y_pred[i] else 0 for i in range(size)]) + return acc + +class Model(torch.nn.Module): + def __init__(self): + super(Model, self).__init__() + self.linear = torch.nn.Linear(30, 1) + + def forward(self, x): + y_pred = torch.sigmoid(self.linear(x)) + #y_pred = self.linear(x).sigmoid() + return y_pred + + +dataset = pd.read_csv('./data/data.csv') +x_train, y_train, x_test, y_test = pre_process(dataset) +x_train = Variable(torch.Tensor(x_train)) +y_train = Variable(torch.Tensor(y_train)) +x_test = Variable(torch.Tensor(x_test)) +y_test = Variable(torch.Tensor(y_test)) + +# Our model +model = Model() +criterion = torch.nn.BCELoss(reduction="mean") +optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + +# Training loop +for epoch in range(1000): + optimizer.zero_grad() + y_pred = model(x_train) + loss = criterion(y_pred, y_train) + loss.backward() + optimizer.step() + if epoch % 100 == 0: + print('Loss is : ', loss.data.item(), ' Acc is : ', cal_acc(x_train, y_train, y_pred)) + +y_test_pred = model(x_test) +test_acc = cal_acc(x_test, y_test, y_test_pred) +print('Test Acc is:', test_acc) + +for f in model.parameters(): + print('data is') + print(f.data) + print(f.grad) + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f5e81a0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +numpy==1.16.4 +matplotlib==2.2.3 +scipy==1.1.0 diff --git a/unit1/readme.md b/unit1/readme.md index 3cff53f..8cb3e78 100644 --- a/unit1/readme.md +++ b/unit1/readme.md @@ -50,3 +50,9 @@ The same set of video could also be found on bilibili.com. 1. Ian Sommerville, Software Engineering (10th Edition), 2015. 2. Scott Chacon, Ben Straub, Pro Git (2nd Edition), 2014. + +<<<<<<< HEAD +### Master change +======= +### NOTHING CHANGE +>>>>>>> feature1 diff --git a/unit2/English-Redistributable-Intro-Scrum.pdf b/unit2/English-Redistributable-Intro-Scrum.pdf new file mode 100644 index 0000000..8bcd906 Binary files /dev/null and b/unit2/English-Redistributable-Intro-Scrum.pdf differ diff --git a/unit2/count_words.py b/unit2/count_words.py new file mode 100644 index 0000000..a4adadf --- /dev/null +++ b/unit2/count_words.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Feb 25 09:39:33 2020 + +@author: 85726 +""" + +import os.path + +def count_word(file): + with open(file, 'r') as f: + words = 0 + for line in f: + for char in ('#', '\n'): + line = line.replace(char," ") + word = line.split() + words += len(word) + return words + +file = './readme.md' + +if os.path.isfile(file): + words = count_word(file) + print('{} words in file'.format(words)) +else: + print('it is not a file') diff --git a/unit2/python_intro.py b/unit2/python_intro.py new file mode 100644 index 0000000..b046599 --- /dev/null +++ b/unit2/python_intro.py @@ -0,0 +1,128 @@ +# Variable + +x = 1 +x +type(x) +x = 1.1 +x +type(x) +1+1j +x + 1 +x = 'abc' +x +x = "abc" +x = """abc""" +x = 'abc"abc"' +x +x + 'bcd' +x = " sfdsf " +x.strip() +x +dir(x) +help(x.strip) +help(help) +help(dir) +# this is a comment. +print("Hello class!") + +# Control flow, branching +x = 1 +if x == 1: + print("x is {}".format(x)) +else: + print("No way") + +if x == 1: + print('x==1') +elif x == 0: + print('x == 0') +else: + print('x') + +type(x==1) +x == 1 and 2 == int('2') +x == 1 or 2 == int('1') +not x == 1 +a = [1, 2, 3] +1 in a +x = None +x == 1 +x == 0 +type(x) +x is None +x is not None + +# List, tuple, and dict + +x = [1, 2, 3, 4, 5] +x +type(x) +x[0] +x[0] = -1 +x +x[:2] +type(x[:2]) +for elem in x: + print(str(elem + 1)) + +for index in range(len(x)): + print(str(x[index])) + +[print(str(x[index])) for index in range(len(x))] +x +y = tuple(x) +y +y[0] +y[0] = 1 +y = list(x) +y +z = dict() +z = {} +z[0] = 1 +z[1] = 2 +z +z[0] +for key, value in z.items(): + print(str(key), str(value)) + + + +dir(z) +-1 in z +1 in z + +# Control flow, loop + +for x in [1, 2, 3, 4, 5]: + if x == 2: + continue + elif x == 4: + break + else: + print(x) +else: + print('no find') + +for x in [1, 2]: + print(x) +else: + print('no find') + +i = 0 +while i < 5: + print(i) + i += 1 + +# Function and module + +def count_char(fn,): + import os.path + if os.path.isfile(fn): + with open(fn, 'r') as fh: + total = 0 + for line in fh: + total += len(line) + return total + +count_char('./unit2/readme.md') +import os.path diff --git a/unit2/readme.md b/unit2/readme.md new file mode 100644 index 0000000..c55adf0 --- /dev/null +++ b/unit2/readme.md @@ -0,0 +1,67 @@ +This unit is about introduction to an agile development process called Scrum and introduction to a programming language called Python. + +Please go through the video and slides first. +Please install the Python runtime before the official classtime. + +## Introduction to Scrum + +Scrum is an agile development process aiming to deliver business value over shortest time. +It's widely used and often mixed with other agile development process. + +Video 1: Introduction to Scrum + +https://www.acfun.cn/v/ac13145403 + +Video 2: The Sprint in Scrum + +https://www.acfun.cn/v/ac13145466 + +Video 3: Roles, Meetings, and Documents in Scrum + +https://www.acfun.cn/v/ac13145616 + +Slide: English-Redistributable-Intro-Scrum.pdf + +## Introduction to Python + +Install Python using miniconda + +https://docs.conda.io/en/latest/miniconda.html + +Video 1: Variables + +https://www.acfun.cn/v/ac13164403_1 + +Video 2: Control flow, branching + +https://www.acfun.cn/v/ac13164403_2 + +video 3: List, tuple, and dict + +https://www.acfun.cn/v/ac13164403_3 + +Video 4: Control flow, loop + +https://www.acfun.cn/v/ac13164403_4 + +Video 5: Function and Module + +https://www.acfun.cn/v/ac13164403_5 + + +### Exercise + +1. Write a Python code to count the words in this readme. +2. Use Git to commit your code in unit2 directory and push to your repository. Also comment on the issue with the link to your code. + +## Reference + +1. Kenneth S. Rubin, Essential Scrum: A Practical Guide to the Most Popular Agile Process, 2012 +2. Eric Matthes, Python Crash Course, 2nd Edition: A Hands-On, Project-Based Introduction to Programming (2nd Edition), 2019 +3. Mark Pilgrim, Dive Into Python 3, 2009 + +## Notes + +1. The same set of video could also be found on bilibili.com. +2. Students without computers at your disposal are suggested to read till chapter 7 of "Dive Into Python 3", which is available online at https://diveintopython3.problemsolving.io, or section 1, 2, 3, 4, 5, 9 of Official Python tutorial at https://docs.python.org/3/tutorial/. +3. This unit doesn't require students to team up. diff --git a/unit3/FindMCircle.py b/unit3/FindMCircle.py new file mode 100644 index 0000000..92a45fb --- /dev/null +++ b/unit3/FindMCircle.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +""" +Created on Thu Mar 5 10:00:30 2020 + +@author: 85726 +""" + +""" +思想:保证每一个圆在当前可行域内都取得最大的半径,可取值为圆心到四边的距离和圆心到各个圆边的距离,取其中最小的一个 +就是当前最大半径 + +实现:在保证新取的圆心处于可行域的范围内,使用scipy的优化器,在邻域内不断优化圆心的位置,直至找到最大的半径 + +结果: +m=10, sum of r^2 =1.14 +m=50, sum of r^2 =1.21 +m=100, sum of r^2 =1.23 +保存的图在unit3中 +""" + +import numpy as np +import random +import matplotlib.pyplot as plt +from scipy.optimize import minimize + +#定义圆类 +class circle: + def __init__(self, radius = 0, x = 0, y = 0): + self.radius = radius + self.x = x + self.y = y + + def print_circle(self): + print('radius={}, coordinate=({},{})'.format(self.radius, self.x, self.y)) + + #计算两圆心之间距离 + def distance(self, c2): + dis = ((self.x-c2.x)**2+(self.y-c2.y)**2)**0.5 + return dis + + #判断新圆与现存圆是否相交,相交为0,全不相交为1 + def ifcross(self, c_list): + for i in range (len(c_list)): + c2 = c_list[i] + r1 = self.radius + r2 = c2.radius + rr = r1+r2 + dis = self.distance(c2) + if dis < rr: + return 0 + return 1 + + #判断圆是否越界,越界为0,不越界为1 + def ifexcess(self): + r = self.radius + x = self.x + y = self.y + if x + r > 1 or x - r < -1 or y + r > 1 or y - r < -1: + return 0 + else: + return 1 + +#找出可行的最大半径 +def MaxR(c1, c_list): + x = c1.x + y = c1.y + R_list = [1-x,1+x,1-y,1+y] + for i in range (len(c_list)): + c2 = c_list[i] + dis = c1.distance(c2) + R_list.append(dis-c2.radius) + return min(R_list) + +#需要优化的目标函数 +def func(c_list): + return lambda x : 1 - MaxR(circle(x[0], x[1], x[2]), c_list) + +#找出最优圆心 +def opt_center(c, c_list): + r = c.radius + x = c.x + y = c.y + rxy = [r,x,y] + bd_r = (0, 1) + bd_x = (-1, 1) + bd_y = (-1, 1) + bds = (bd_r, bd_x, bd_y) + res = minimize(func(c_list), rxy, method='SLSQP', bounds=bds) + c.x = res.x[1] + c.y = res.x[2] + c.radius = MaxR(c, c_list) + return c + +#找m个圆,使得每个圆在邻域内半径最大 +def FindMaxCircuit(m): + c_list = [] + for i in range (m): + r = 0 + x = random.uniform(-1, 1) + y = random.uniform(-1, 1) + c = circle(r, x, y) + while not c.ifcross(c_list): + x = random.uniform(-1, 1) + y = random.uniform(-1, 1) + c = circle(r, x, y) + c = opt_center(c, c_list) + c_list.append(c) + return c_list + +def plot(c_list): + plt.figure() + plt.axes().set_aspect('equal') + plt.xlim([-1,1]) + plt.ylim([-1,1]) + theta = np.linspace(0,2*np.pi,50) + for c in c_list: + plt.plot(c.x+c.radius*np.cos(theta),c.y+c.radius*np.sin(theta),'b') + plt.show() + +if __name__ == "__main__": + m = 10 + c_list = FindMaxCircuit(m) + RR = 0 + for c in c_list: + RR += c.radius**2 + c.print_circle() + print('for {} circles, the maximize sum of r^2 = {}'.format(m, RR)) + + plot(c_list) + + + + + + + + + + + \ No newline at end of file diff --git a/unit3/m=10.png b/unit3/m=10.png new file mode 100644 index 0000000..b50cec3 Binary files /dev/null and b/unit3/m=10.png differ diff --git a/unit3/m=100.png b/unit3/m=100.png new file mode 100644 index 0000000..4297c1f Binary files /dev/null and b/unit3/m=100.png differ diff --git a/unit3/m=50.png b/unit3/m=50.png new file mode 100644 index 0000000..b7b91d5 Binary files /dev/null and b/unit3/m=50.png differ diff --git a/unit4/FindMCircle.py b/unit4/FindMCircle.py new file mode 100644 index 0000000..977b5ec --- /dev/null +++ b/unit4/FindMCircle.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +""" +Created on Thu Mar 5 10:00:30 2020 + +@author: 85726 +""" + +""" +思想:保证每一个圆在当前可行域内都取得最大的半径,可取值为圆心到四边的距离和圆心到各个圆边的距离,取其中最小的一个 +就是当前最大半径 + +实现:在保证新取的圆心处于可行域的范围内,使用scipy的优化器,在邻域内不断优化圆心的位置,直至找到最大的半径 + +结果: +m=10, sum of r^2 =1.14 +m=50, sum of r^2 =1.21 +m=100, sum of r^2 =1.23 +保存的图在unit3中 +""" + +import numpy as np +import random +import matplotlib.pyplot as plt +from scipy.optimize import minimize + +#定义圆类 +class circle: + def __init__(self, radius = 0, x = 0, y = 0): + self.radius = radius + self.x = x + self.y = y + + def print_circle(self): + print('radius={}, coordinate=({},{})'.format(self.radius, self.x, self.y)) + + #计算两圆心之间距离 + def distance(self, c2): + dis = ((self.x-c2.x)**2+(self.y-c2.y)**2)**0.5 + return dis + + #判断新圆与现存圆是否相交,相交为0,全不相交为1 + def ifcross(self, c_list): + for i in range (len(c_list)): + c2 = c_list[i] + r1 = self.radius + r2 = c2.radius + rr = r1+r2 + dis = self.distance(c2) + if dis < rr: + return 0 + return 1 + + #判断圆是否越界,越界为0,不越界为1 + def ifexcess(self): + r = self.radius + x = self.x + y = self.y + if x + r > 1 or x - r < -1 or y + r > 1 or y - r < -1: + return 0 + else: + return 1 + +#找出可行的最大半径 +def MaxR(c1, c_list): + x = c1.x + y = c1.y + R_list = [1-x,1+x,1-y,1+y] + for i in range (len(c_list)): + c2 = c_list[i] + dis = c1.distance(c2) + R_list.append(dis-c2.radius) + return min(R_list) + +#需要优化的目标函数 +def func(c_list): + return lambda x : 1 - MaxR(circle(x[0], x[1], x[2]), c_list) + +#找出最优圆心 +def opt_center(c, c_list): + r = c.radius + x = c.x + y = c.y + rxy = [r,x,y] + bd_r = (0, 1) + bd_x = (-1, 1) + bd_y = (-1, 1) + bds = (bd_r, bd_x, bd_y) + res = minimize(func(c_list), rxy, method='SLSQP', bounds=bds) + c.x = res.x[1] + c.y = res.x[2] + c.radius = MaxR(c, c_list) + return c + +#找m个圆,使得每个圆在邻域内半径最大 +def FindMaxCircuit(m): + c_list = [] + for i in range (m): + r = 0 + x = random.uniform(-1, 1) + y = random.uniform(-1, 1) + c = circle(r, x, y) + while not c.ifcross(c_list): + x = random.uniform(-1, 1) + y = random.uniform(-1, 1) + c = circle(r, x, y) + c = opt_center(c, c_list) + c_list.append(c) + return c_list + +def plot(c_list): + plt.figure() + plt.axes().set_aspect('equal') + plt.xlim([-1,1]) + plt.ylim([-1,1]) + theta = np.linspace(0,2*np.pi,50) + for c in c_list: + plt.plot(c.x+c.radius*np.cos(theta),c.y+c.radius*np.sin(theta),'b') + plt.show() + +if __name__ == "__main__": + m = 10 + c_list = FindMaxCircuit(m) + RR = 0 + for c in c_list: + RR += c.radius**2 + c.print_circle() + print('for {} circles, the maximize sum of r^2 = {}'.format(m, RR)) + + plot(c_list) + + + + + + + + + + + \ No newline at end of file diff --git a/unit4/m=10.png b/unit4/m=10.png new file mode 100644 index 0000000..b50cec3 Binary files /dev/null and b/unit4/m=10.png differ diff --git a/unit4/m=100.png b/unit4/m=100.png new file mode 100644 index 0000000..4297c1f Binary files /dev/null and b/unit4/m=100.png differ diff --git a/unit4/m=50.png b/unit4/m=50.png new file mode 100644 index 0000000..b7b91d5 Binary files /dev/null and b/unit4/m=50.png differ diff --git a/unit4/unit_test.py b/unit4/unit_test.py new file mode 100644 index 0000000..d1d3ff3 --- /dev/null +++ b/unit4/unit_test.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Mar 17 09:38:27 2020 + +@author: 85726 +""" + +import unittest +import numpy as np +from FindMCircle import circle +from FindMCircle import * + +class TestCircle(unittest.TestCase): + def setUp(self): + self.c1 = circle(1,0,0) + self.c2 = circle(0.5,0.5,0.5) + self.c3 = circle(1,1,1) + self.c4 = circle(0,-0.5,-0.5) + self.c_list = [] + self.c_list.append(self.c2) + self.c_list.append(self.c3) + + def test_dis(self): + dis_c = self.c1.distance(self.c2) + dis = np.linalg.norm([self.c1.x-self.c2.x,self.c1.y-self.c2.y]) + self.assertEqual(dis_c,dis) + + def test_cross(self): + self.assertEqual(self.c1.ifcross(self.c_list),0) + + def test_excess(self): + self.assertEqual(self.c1.ifexcess(),1) + self.assertFalse(self.c3.ifexcess(),1) + + def test_MaxR(self): + MR = MaxR(self.c4,self.c_list) + print(MR) + self.assertLessEqual(MR,2) + + def test_FindMaxCircle(self): + m = 10 + c_list = FindMaxCircuit(m) + RR = 0 + for c in c_list: + RR += c.radius**2 + self.assertGreaterEqual(RR,1) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file