[Python]Relation(관계 관련 알고리즘)

관계(Relation)

  • 행렬을 사용하기 좋게끔 numpy라이브러리를 기본적으로 사용할것이다.
  • 관계 R에 대한 P닫힘이란? R1이 R을 포함하고, 성질 P를(반사,대칭,추이 등) 갖는것.
    • R* 는 관계 R의 추이폐포(닫힘=폐포)
  • 부울곱, 추이, 대칭, 반사, 동치, 플로이드 워셜 알고리즘


부울곱(Boolean Product)

  • 절대!! 행렬의 곱하기와 햇갈리지 말것!! 이것은 Boolean 곱이다!!
def my_boolean_product(R, S):
  '''
  주어진 관계 매트릭스로부터 부울곱 (Boolean Product)한 결과를 계산하시오
  :param R: NxN Boolean 기반 관계행렬
  :param S: NxN Boolean 기반 관계행렬
  :return: NxN Boolean 기반 관계행렬
  '''
  # NxN 정방행렬에서 얘기하는 중이므로 N 구하기
  N = len(R)
  # NxN 부울곱한 관계행렬인 M 초기화
  M = np.full((N,N), False)
  # 부울곱 알고리즘 시작
  for i in range(N): 
    for j in range(N):
      for q in range(N):
        if(R[i,q] and S[q,j]): # 둘다 1, 1이면 True조건문 (한번이라도 1이나오면 됨. 결국 합집합으로 합하기 때문.(예:0or1=1))
          M[i,j] = True
  return M # M은 관계행렬


추이 관계(Transitive Relation)

  • 추이관계와 거듭제곱의 관계 -> R=R2=R3=…이면 추이관계이다.

  • (a,b) 와 (b,c)가 True 라면 (a,c)가 True여야한다.

def is_transitive_relation(M):
  '''
  추이 관계인지를 확인하는 함수
  :param M: NxN Boolean 기반 관계행렬
  :return: True / False
  '''
  N = len(M)
  check = 0
  for i in range(N):
    for j in range(N):
      for q in range(N):
        if(M[i,j] and M[j,q]): # (i,j) 와 (j,q)가 True 라면 (i,q)가 True여야한다.
          if(M[i,q] == True):
            check = 1 # 추이관계가 하나라도 존재하긴 하는지 유무를 판단(i,j와j,q가 True인 경우가 아예 없을수도 있어서.)
          else:
            return False # (i,q)가 True가 아니면 추이관계 성립X
  if(check == 1):
    return True
  else:
    return False


대칭 관계(Symmetric Relation)

  • (a,b) 와 (b,a)가 같아야 대칭이다.
def is_symmetric_relation(M):
  '''
  대칭 관계인지를 확인하는 함수
  :param M: NxN Boolean 기반 관계행렬
  :return: True / False
  '''
  N = len(M)
  for i in range(N):
    for j in range(N):
      if(M[i,j] != M[j,i]):
        return False
  return True


반사 관계(Reflexive Relation)

  • (a,a), (b,b), (c,c) … 주대각 원소가 1(True)여야 반사이다.
def is_reflexive_relation(M):
  '''
  반사 관계인지를 확인하는 함수
  :param M: NxN Boolean 기반 관계행렬
  :return: True / False
  '''
  # 주대각 원소가 1인지 확인 하면 됨.
  N = len(M)
  for i in range(N):
    if(M[i,i] == False):
      return False
  return True


동치 관계(Equivalence Relation)

  • 위의 3가지(추이, 대칭, 반사) 관계가 성립한다면 동치이다.
def is_equivalence_relation(M):
  '''
  동치 관계인지를 확인하는 함수
  :param M: NxN Boolean 기반 관계행렬
  :return: True / False
  '''
  # 반사, 대칭, 추이 이기만 하면 동치관계인지 증명할 수 있다.
  if(is_transitive_relation(M) and is_symmetric_relation(M) and is_reflexive_relation(M)):
    return True
  return False


플로이드 워셜 알고리즘(Floyd Washall Algorithm)

  • 워셜 알고리즘은 연결관계를 구하는 방법이다.
    • R*
  • 주어진 관계행렬을 만족하는 가장 작은 동치 관계(Equivalence relation)를 구할 수 있다.
    • (RUS)*
  • 간단한 설명(Equivalence relation 구하기)
    • 제일 처음 관계행렬이 W0로 초기화 되며, 최종 Wn을 구하면 그것이 답이 된다.
    • 각각 해당 열의 True, 해당 행의 True값을 보관후 그것으로 나타낼 수 있는 모든 경우의수를 다시 newList로 보관한다.
    • newList로 나타낸 모든 경우를 W행렬에 반영해주고, 이를 n번 반복하면 끝이다.
def floyd_washall(R, S):
  '''
  관계행렬 R과 S를 입력으로 받아서 플로이드 워셜 알고리즘을 통해 가장 작은 동치 관계행렬을 반환한다
  :param R: NxN의 관계행렬
  :param S: NxN의 관계행렬
  :return: NxN의 관계행렬
  '''
  # NxN 관계행렬을 2개 받기 때문에 N을 구하기 간단.
  n = len(R)
  W0 = np.logical_or(R,S) # W0 초기화
  Wn = W0
  for k in range(n):
    colList = [] # 열 리스트
    ranList = [] # 행 리스트
    newList = []
    Wn = Wn
    for i in range(n):
      if(Wn[i][k] == True): # 1열의 논리값 1찾기
        colList.append(i)
      if(Wn[k][i] == True): # 1행의 논리값 1찾기
        ranList.append(i)
    for i in range(len(colList)): # newList에 앞서 저장한 논리값들 정리.
      for j in range(len(ranList)):
        newList += [[colList[i],ranList[j]]]
    for i in range(len(newList)):
      Wn[newList[i][0]][newList[i][1]] = True
  E = Wn
  return E # 가장작은 동치 관계행렬을 반환

댓글남기기