ค้นหาว่าเมทริกซ์สมมาตรสองตัวเท่ากันหรือไม่โดยขึ้นอยู่กับการเรียงสับเปลี่ยนของแถว/คอลัมน์

ฉันมีเมทริกซ์ A และ B แบบสมมาตร (รายการเกิดขึ้นร่วม) สองตัว และต้องการทราบว่าเมทริกซ์เหล่านี้อธิบายการเกิดร่วมกันแบบเดียวกันหรือไม่ โดยเปลี่ยนเฉพาะป้ายกำกับแถว/คอลัมน์เท่านั้น (ต้องใช้การเรียงสับเปลี่ยนเดียวกันกับแถวและคอลัมน์เพื่อรักษาคุณสมบัติสมมาตร/การเกิดขึ้นร่วม)

ตัวอย่างเช่น เมทริกซ์ทั้งสองนี้ควรจะเท่ากันในการทดสอบของฉัน:

a = np.array([
    #1 #2 #3 #4 #5 #6 #7
    [0, 1, 1, 0, 0, 0, 1], #1
    [1, 0, 1, 2, 1, 1, 2], #2
    [1, 1, 0, 0, 0, 0, 1], #3
    [0, 2, 0, 0, 4, 0, 4], #4
    [0, 1, 0, 4, 0, 1, 2], #5
    [0, 1, 0, 0, 1, 0, 0], #6
    [1, 2, 1, 4, 2, 0, 0]  #7
])
b = np.array([
    #5 #7 #1,3#3,1#2 #4 #6
    [0, 2, 0, 0, 1, 4, 1], #5
    [2, 0, 1, 1, 2, 4, 0], #7
    [0, 1, 0, 1, 1, 0, 0], #1,3 could be either
    [0, 1, 1, 0, 1, 0, 0], #1,3 could be either
    [1, 2, 1, 1, 0, 2, 1], #2
    [4, 4, 0, 0, 2, 0, 0], #4
    [1, 0, 0, 0, 1, 0, 0]  #6
])

ขณะนี้ฉันทดสอบว่าค่าลักษณะเฉพาะเหมือนกันหรือไม่โดยใช้ numpy.linalg.eigvals (ฉันไม่แน่ใจด้วยซ้ำว่านี่เป็นเงื่อนไขที่เพียงพอ) แต่ฉันต้องการค้นหาการทดสอบที่ไม่เกี่ยวข้องกับความแม่นยำเชิงตัวเลข เนื่องจากฉันกำลังจัดการกับจำนวนเต็มที่นี่


person C. Yduqoli    schedule 29.10.2018    source แหล่งที่มา
comment
ปัญหานี้เทียบเท่ากับกราฟมอร์ฟิซึม: คำตอบที่แน่นอนมีแนวโน้มที่จะช้า ดูเช่น คำถามนี้   -  person Maxim    schedule 29.10.2018
comment
ฉันสงสัยว่าคุณสร้าง b โดยไม่รู้ดัชนี [5, 7, 1, 3, 2, 4, 6] ได้อย่างไรตั้งแต่แรก   -  person Andreas K.    schedule 29.10.2018
comment
ฉันคำนวณการเกิดขึ้นร่วมของวัตถุตามรายการของวัตถุ ออบเจ็กต์เหล่านี้ได้รับดัชนีสุ่มที่กำหนด (อยู่นอกเหนือการควบคุมของฉัน) ก่อนที่จะสร้างเมทริกซ์ร่วมที่เกิดขึ้น วิธีนี้จะสร้างเมทริกซ์ co-oc ที่แตกต่างกันทุกครั้ง สำหรับตัวอย่างของฉัน ฉันใช้เมทริกซ์สองตัวนี้และกำหนดดัชนีสำหรับเมทริกซ์ตัวที่สองด้วยมือ   -  person C. Yduqoli    schedule 30.10.2018
comment
ฉันขอแนะนำให้อ่านปัญหากราฟ isomorphism และตรวจดูว่าคุณมีรสชาติเฉพาะของ กราฟคือปัญหาที่แก้ไขได้ ถ้าไม่เช่นนั้น คุณก็คงต้องใช้กำลังอันรุนแรง   -  person Daniel F    schedule 30.10.2018
comment
หากในหลายกรณีเมทริกซ์ของคุณไม่เท่ากัน อันดับแรกควรทำแบบทดสอบเพื่อบอกคุณว่าไม่เท่ากันหรือไม่ แต่จะไม่บอกคุณว่าเท่ากันหรือไม่ ตัวอย่างเช่น คุณสามารถคำนวณมัลติเซ็ตของแต่ละแถวสำหรับแต่ละเมทริกซ์ได้ (เช่น แถวแรกของ a จะเป็น {(4,0), (3,1)}) จากนั้นจึงสร้างมัลติเซ็ตของมัลติเซ็ตแถว หากมัลติเซ็ตทั้งสองชุดนี้ (หนึ่งชุดสำหรับ a หนึ่งชุดสำหรับ b) ไม่เท่ากัน แสดงว่าเมทริกซ์ไม่เท่ากัน   -  person dmuir    schedule 30.10.2018


คำตอบ (3)


นี่คือโซลูชันแบบเวกเตอร์ตาม sorting และการใช้ประโยชน์ searchsorted -

import pandas as pd

# Sort rows for a and b
aS = np.sort(a,axis=1)
bS = np.sort(b,axis=1)

# Scale down each row to a scalar each
scale = np.r_[(np.maximum(aS.max(0),bS.max(0))+1)[::-1].cumprod()[::-1][1:],1]
aS1D = aS.dot(scale)
bS1D = bS.dot(scale)

# Use searchsorted to get the correspondence on indexing
sidx = aS1D.argsort()
searchsorted_idx = np.searchsorted(aS1D,bS1D,sorter=sidx)
searchsorted_idx[searchsorted_idx==len(aS1D)] = len(aS1D)-1
df = pd.DataFrame({'A':searchsorted_idx})
new_order = sidx[df.groupby('A').cumcount().values+searchsorted_idx]
# new_order is the permuted order, i.e. [5, 7, 1, 3, 2, 4, 6]

# Finally index into a with the new_order and compare against b
out = np.array_equal(a[new_order[:,None], new_order],b)
person Divakar    schedule 29.10.2018
comment
ดี แต่ช้ากว่าวิธีแก้ปัญหาที่มีค่าลักษณะเฉพาะมาก - person Andreas K.; 29.10.2018
comment
@AndyK คุณกำลังทดสอบขนาดใด? - person Divakar; 29.10.2018
comment
ดูเหมือนจะไม่ถูกต้อง ฉันลอง a = scipy.linalg.toeplitz(np.arange(8)) และ b เวอร์ชันสับเปลี่ยนแล้ว และได้รับ False ตลอดเวลา - person Paul Panzer; 29.10.2018
comment
@AndyK ฉันค่อนข้างแน่ใจว่าค่าลักษณะเฉพาะยังไม่เพียงพอ ตัวอย่างเช่น [[4 0] [0 0]] และ [[2 2] [2 2]] มีค่าลักษณะเฉพาะที่เหมือนกัน แต่เห็นได้ชัดว่าไม่สามารถสับเปลี่ยนเข้าหากันได้ - person Paul Panzer; 29.10.2018
comment
แล้วnp.array([[12, 8, 11],[8, 0, 12],[11, 12, 8]]) np.array([[0, 12, 8],[12, 8, 11],[8, 11, 12]])ล่ะ สิ่งนี้ควรคืนค่าเป็น True แต่วิธีการของคุณคืนค่าเป็นเท็จในการทดสอบของฉัน - person C. Yduqoli; 30.10.2018
comment
นอกจากนี้ยังทำให้เกิดข้อยกเว้นสำหรับ [[12 8] [ 8 4]] [[ 6 5] [ 5 14]]: new_order = sidx[df.groupby('A').cumcount().values+searchsorted_idx] IndexError: index 2 is out of bounds for axis 1 with size 2 - person C. Yduqoli; 30.10.2018

ฉันจะถือว่าคุณมีรายการการเรียงสับเปลี่ยนของแถว/คอลัมน์ของ a ซึ่งให้ b เช่น บางอย่างเช่นนี้

p = np.array([5, 7, 1, 3, 2, 4, 6]) - 1

จากนั้น คุณสามารถทำสิ่งต่อไปนี้บน a

a_p = a[p]
a_p = a_p[:, p]

และตรวจสอบว่า b และ a_p ที่ดัดแปรแล้วเท่ากันหรือไม่:

(a_p == b).all()

แก้ไข: เนื่องจากคุณไม่มีรายการเหมือนที่ด้านบน p คุณจึงสามารถ (อย่างน้อยสำหรับอาร์เรย์ขนาดเล็ก a และ b) สร้างการเรียงสับเปลี่ยนของดัชนีและตรวจสอบแต่ละรายการ:

from itertools import permutations

def a_p(a, b, p):
    p = np.array(p)
    a_p = a[p]
    a_p = a_p[:, p]
    return a_p

for p in permutations(range(a.shape[0])):
    if (a_p(a, b, p) == b).all():
        print('True')
        break
else:
    print('False')

โปรดทราบว่าวิธีเดรัจฉานบังคับนี้ใช้ได้กับเมทริกซ์ที่ไม่สมมาตรเช่นกัน แต่เนื่องจากจำนวนการเรียงสับเปลี่ยนมีมากสำหรับอาร์เรย์ขนาดใหญ่ a และ b วิธีนี้อาจช้ามาก ดังนั้นวิธีแก้ปัญหาของคุณด้วยค่าลักษณะเฉพาะในการคำนวณจึงดีกว่ามาก

นี่คือเกณฑ์มาตรฐาน:

def Yduqoli(a, b):
    ''' I suppose your solution is similar'''
    if (np.array(np.unique(a, return_counts=True)) == np.array(np.unique(b, return_counts=True))).all():
        a_eigs = np.sort(np.linalg.eigvals(a))
        b_eigs = np.sort(np.linalg.eigvals(b))
        return np.allclose(a_eigs, b_eigs)
    else:
        return False

def AndyK(a, b):
    for p in permutations(range(a.shape[0])):
        if (a_p(a, b, p) == b).all():
            return True
    return False  

%timeit AndyK(a,b)
103 ms ± 4.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit Yduqoli(a,b)
408 µs ± 65.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

โดยที่ฉันใช้เมทริกซ์สมมาตร a และ b ที่ได้รับจาก OP

อัปเดต: ตามที่ Paul Panzer กล่าวไว้ เพียงการตรวจสอบค่าลักษณะเฉพาะก็สามารถให้ผลลัพธ์ที่ไม่ถูกต้องได้ในบางกรณี เช่น a = np.array([[4, 0], [0, 0]]), b = np.array([[2, 2], [2, 2]]) มีค่าลักษณะเฉพาะที่เหมือนกัน แต่ไม่สามารถสับเปลี่ยนค่าลักษณะเฉพาะเป็นค่าอื่นได้ ดังนั้นก่อนอื่นเราจำเป็นต้องตรวจสอบก่อนว่าอาร์เรย์ a และ b มีองค์ประกอบเดียวกันหรือไม่ (ไม่ว่าตำแหน่งจะเป็นอย่างไร)

person Andreas K.    schedule 29.10.2018
comment
ขออภัย ฉันไม่มีรายการนั้น - person C. Yduqoli; 29.10.2018
comment
คุณหมายถึง a = np.array([[4, 0], [0, 0]])? มันสมมาตรเพราะ a = a.T แต่มันก็เป็นตัวอย่างตามอำเภอใจ - person Andreas K.; 30.10.2018

คุณสามารถเรียงลำดับเมทริกซ์ตามบรรทัดฐานแถวและดูว่ามันต่างกันหรือไม่ หากสองแถวมีบรรทัดฐานเดียวกัน คุณจะต้องตรวจสอบการเรียงสับเปลี่ยนของแถวที่มีบรรทัดฐานเดียวกัน แต่สิ่งนี้จะช่วยลดปัญหาให้เหลือเฉพาะแถวที่มีบรรทัดฐานเดียวกันเท่านั้น ในหลายกรณี คุณสามารถเรียงลำดับตาม 2-บรรทัดฐาน จากนั้นจึงใช้ 1-บรรทัดฐาน และสุดท้ายก็ใช้การเรียงสับเปลี่ยนที่เหลือแบบเดรัจฉาน

import numpy as np

def get_row_norm(a):
    """
    Sort by 2-norm
    """
    row_norms = np.sum(a**2, axis=1)
    return row_norms

def sort(a):
    """
    Return the matrix a sorted by 2-norm
    """
    n = a.shape[0]
    # Get the norms
    row_norms = get_row_norm(a)
    # Get the order
    order = np.argsort(row_norms)[::-1]

    sorted_a = a.copy()

    for m in range(n):
        i = order[m]
        for k in range(m+1): 
            j = order[k]
            sorted_a[m, k] = a[i, j]
            sorted_a[k, m] = a[i, j]

    return sorted_a


a = np.array([
    #1 #2 #3 #4 #5 #6 #7
    [0, 1, 1, 0, 0, 0, 1], #1
    [1, 0, 1, 2, 1, 1, 2], #2
    [1, 1, 0, 0, 0, 0, 1], #3
    [0, 2, 0, 0, 4, 0, 4], #4
    [0, 1, 0, 4, 0, 1, 2], #5
    [0, 1, 0, 0, 1, 0, 0], #6
    [1, 2, 1, 4, 2, 0, 0]  #7
])  
b = np.array([
    #5 #7 #1,3#3,1#2 #4 #6 
    [0, 2, 0, 0, 1, 4, 1], #5
    [2, 0, 1, 1, 2, 4, 0], #7
    [0, 1, 0, 1, 1, 0, 0], #1,3 could be either
    [0, 1, 1, 0, 1, 0, 0], #1,3 could be either
    [1, 2, 1, 1, 0, 2, 1], #2
    [4, 4, 0, 0, 2, 0, 0], #4
    [1, 0, 0, 0, 1, 0, 0]  #6
])

# Sort a and b
A = sort(a)
B = sort(b)
# Print the norms
print(get_row_norm(a)) # [ 3. 12.  3. 36. 22.  2. 26.]
print(get_row_norm(A)) # [36. 26. 22. 12.  3.  3.  2.]
print(get_row_norm(B)) # [36. 26. 22. 12.  3.  3.  2.]
# Assert that they are equal
print( (A == B).all())

โปรดทราบว่าหากไม่เท่ากัน คุณยังต้องตรวจสอบการเรียงสับเปลี่ยนของแถวที่ห้าและหก เนื่องจากบรรทัดฐานเท่ากัน

person user2653663    schedule 29.10.2018
comment
ต่อไปนี้เป็นตัวอย่างเคาน์เตอร์: a = np.array([[2, 2], [0, 1]]), b = np.array([[1, 0], [2, 2]]) โดยที่ b คือ a โดยมีแถวและคอลัมน์สลับกัน - person Andreas K.; 29.10.2018
comment
@AndyK แต่นั่นเป็นเมทริกซ์ที่แตกต่างกันโดยสิ้นเชิงใช่ไหม - person user2653663; 29.10.2018
comment
ฉันหมายถึง b คือ a โดยสลับแถว 0 ‹-› 1 และคอลัมน์ 0 ‹-› 1 - person Andreas K.; 29.10.2018
comment
แต่เมทริกซ์เหล่านั้นไม่สมมาตร และนั่นคือสิ่งที่สหกรณ์ขอ - person user2653663; 29.10.2018
comment
แน่นอนคุณพูดถูก ฉันลืมไปว่าพวกมันควรจะสมมาตร - person Andreas K.; 29.10.2018
comment
แล้ว [[0 1] [1 1]] [[1 1] [1 0]] ล่ะ? ไม่เปรียบเทียบเท่ากันหลังจากการเรียงลำดับ แต่ไม่มีบรรทัดฐานของแถวที่ซ้ำกัน - person C. Yduqoli; 30.10.2018
comment
@ C.Yduqoli คุณพูดถูก มีข้อผิดพลาดในลูปที่ทำการเรียงลำดับ for k in range(m): ควรจะเป็น for k in range(m+1) ฉันแก้ไขมันในโค้ดด้านบน - person user2653663; 30.10.2018