用JPlag在一組程序中尋找抄襲行爲(翻譯)

摘要:JPlag是一個Web服務,能夠在給定的集合中找到相似的程序對的程序。它在實踐中被成功地用於檢測學生Java程序提交中的剽竊行爲。能支持的語言除了java以外,還有C、C++和Scheme。咱們描述Jpalg架構和jplag的比較算法,這個算法是基於名爲「Greedy String Tiling」的已知算法。那麼,這篇論文的貢獻主要有三個方面:首先,對JPlag在幾個不一樣的集合上的表現進行評估的Java程序,證實抄襲很難經過JPlag的檢查。再一次測試中,在咱們的各類基準程序集中,77個剽竊者中有90%以上被可靠檢測到,其餘人中的大多數都會引發懷疑。運行時間僅爲幾百秒,用於提交每一個100個程序的100個程序。其次,參數研究代表,該方法在配置參數方面至關穩健。第三,咱們研究了用於假裝抄襲的種類,頻率和成功的種類。 前端

關鍵詞:剽竊,類似性,搜索,令牌,字符串拼貼
類別:GT算法,GT性能,F.2.2。 模式匹配,H.3.3,H.5.2。,
I.5.4。 文本處理,K.3.m.,K.5.1java

檢測相似的程序
1.全部要比較的程序都被解析(或根據輸入進行掃描)
語言)並轉換爲令牌字符串。
2.將這些標記字符串成對比較以肯定類似性
每一對。git

將程序轉換爲令牌字符串的前端過程是JPlag中惟一依賴於語言的過程。 目前存在三種前端實現:Java和Scheme的實現都是實現完整的解析器。 C ++(或C)的第三個前端只包含一個掃描器。程序員

做爲一項規則,應該選擇令牌,以便表徵程序結構的本質(剽竊者難以改變),而不是表面方面。 JPlag忽略空白,註釋和標識符的名稱。 此外,JPlag在可能的狀況下將語義信息放入令牌中,以減小純粹偶然發生的虛假子串匹配。 例如,在Java中,咱們使用Begin Method標記而不是僅僅一個Open Brace標記。 基於解析器的前端在這方面更勝一籌。 有關Java示例,請參見表1。 請參閱第4節以瞭解標記化方法的基本原理。github

咱們在第3.4節中的評估代表,JPlag對令牌集的更改很是有效web

Greedy-String-Tiling(String A, String B) {
     tiles = {};
     do {
         maxmatch = M;
         matches = {};
         Forall unmarked tokens Aa in A {
             Forall unmarked tokens Bb in B {
                 j = 0;
                 while (Aa+j == Bb+j && unmarked(Aa+j) && unmarked(Bb+j))
                 j + +;
                 if (j == maxmatch)
                     matches = matches ⊕ match(a, b, j);
                 else if (j > maxmatch) {
                     matches = {match(a, b, j)};
                     maxmatch = j;
                 }
             }
         }
         Forall match(a, b, maxmatch) ∈ matches {
             For j = 0 ...(maxmatch − 1) {
                 mark(Aa+j);
                 mark(Bb+j );
             }          
             tiles = tiles ∪ match(a, b, maxmatch);
         }
     } while (maxmatch > M);
         return tiles;
   }

表2:「貪婪字符串拼貼」算法[Wise,1993]。 第12行中的⊕運算符在匹配集合中添加匹配項,當且僅當它與集合中已有的匹配項之一不重疊時。 三重匹配(a,b,l)表示A和B的相同子串之間的關聯,分別從位置Aa和Bb開始,長度爲1。算法

用於比較兩個標記字符串的算法本質上是「貪婪字符串拼貼」[Wise,1993]。 比較兩個字符串A和B時,目標是找到一組具備如下屬性的連續子字符串:每一個子字符串都出如今A和B中,儘量長而且不涵蓋已由其餘某個其餘字符覆蓋的標記子。 爲了不虛假匹配,強制執行最小匹配長度M.編程

最小匹配長度M被強制執行。「貪婪字符串拼貼」是一種啓發式算法,由於保證找到的一組子字符串的最大值會使搜索過於昂貴。 這裏是粗略的草圖(參見表2的僞代碼)。 該算法重複如下兩個步驟:後端

步驟1(第5-18行):搜索兩個字符串以查找最大的連續匹配。 從概念上講,這是經過3個嵌套循環完成的:第一個循環遍歷A中的全部標記,第二個將當前標記與B中的每一個標記進行比較。若是它們相同,則最內部循環搜索Prechelt L.,Malpohl G.,Philippsen M .: Finding Plagiarisms ... 1021比賽結束。 這些嵌套循環收集全部最長的公共子串集合數組

步驟2(第19-25行):標記步驟1中發現的全部最大長度的非重疊匹配。這意味着它們的全部標記都被標記,所以可能不會用於後續迭代步驟1中的進一步匹配。 在Wise的術語中,經過標記全部的標記,匹配成爲一個貼圖。

重複這兩個步驟直到找不到進一步的匹配。 因爲在每一步中標記了更多的標記,因此算法老是終止。 它返回咱們須要計算類似性度量的瓦片列表。 這項措施應該反映原始程序中由比賽覆蓋的部分代幣。 咱們將其定義爲sim(A,B)= 2·coverage(tiles)/(| A | + | B |)其中coverage(tiles)=? 匹配(a,b,長度)∈tiles長度。

這種啓發式算法的運行時複雜度仍然至關高。 在最壞的狀況下,全部三個嵌套循環都會執行到最大限度。 儘管在後面的迭代中匹配長度遞減,但若是在每次迭代中只標記一個最短的可設想的匹配,則這可能致使與Θ((| A | + | B |)3)同樣大的步驟, 最後涵蓋了字符串[Wise,1993; Prechelt等,2000]。 在最好的狀況下,根本不存在來自A的單個令牌,而且搜索須要Θ((| A | + | B |)2)個步驟。

2.2.3 Wise和JPlag的運行時間優化

儘管最壞狀況下的複雜度不能下降,但經過應用Karp-Rabin模式匹配算法[Karp and Rabin,1987]的想法,實際狀況下的平均複雜度能夠提升到幾乎Θ(| A | + | B |。

經過使用哈希函數來處理更長的字符串(「文本」T)。 爲此,全部長度爲| P |的子串的哈希值 在T中計算。 這能夠經過使用可以根據h(Tt-1Tt ... Tt + | P | -1)的值計算h(TtTt + 1..Tt + | P | -1)的值的散列函數h以線性時間完成。 -2),Tt-1和Tt + | P | -1。 而後將全部散列值與P的值進行比較。若是兩個值相同,則進行字符對比以驗證T中P的出現已被找到。 這種算法在實踐中的複雜性幾乎是線性的。

咱們修改Wise的貪婪字符串拼貼如下列方式應用Karp-Rabin匹配的基本思想:
1.對於時間Θ(| A | + | B |)中的全部長度爲s的子串計算散列值。 JPlag使用s = M,Wise的算法以下所述調整s。
2.而後未來自A的每一個散列值與來自B的每一個散列值進行比較。若是兩個值相同,則經過用令牌比較子串標記來驗證匹配。 而後該算法試圖將匹配儘量地擴展到散列函數覆蓋的範圍以外。
3.使用散列表來定位來自B的具備與來自A的給定子字符串相同的散列值的子字符串。

這個算法的最壞狀況下的複雜度仍然是Θ((| A | + | B |)3),由於全部的子字符串均可能必須經過令牌比較令牌,但實際上覆雜度遠低於Θ((| A | + | B |)2)一般被觀察到。

JPlag預先執行全部散列計算(兩個字符串的散列值加上字符串B的散列表),即在平鋪過程以前僅進行一次散列計算。 當找到匹配而且標記了一個貼圖時,靜態哈希表中的相應條目再也不適用於後續迭代。 因爲JPlag離開表中的受影響條目,因此驗證子步驟(上面的編號2)變得稍微複雜一些。

相比之下,Wise會在每次迭代中從新計算全部散列值和散列表,以便找到的任何匹配都是有效的。
在這兩種方法中,咱們發現靜態預計算加上稍微更昂貴的有效性檢查對於JPlag的默認參數和典型的標記字符串來講更快。

3 JPlag系統的評估

在本節中,咱們將研究JPlag的歧視性能及其對程序結構的敏感性,剽竊頻率以及JPlag算法的自由參數。 咱們提出一個基於多套真實學生課程加上一些明確製做的剽竊的實證研究。

3.1設置咱們的研究

本節介紹了一組程序,用於量化結果的標準以及評估中考慮的自由參數集。

3.1.1使用的原始程序集:簡單,堅硬,乾淨,大

咱們在研究中使用了四種不一樣的程序做爲基準。 其中三門是來自第二學期信息學課程的編程練習,第四門是從一門研究生高級程序設計課程,向有經驗的學生介紹Java和AWT。 有關概述,請參閱表3,如今忽略最右邊的兩列

「簡單」:最大化流量。 用於計算經過具備容量加權邊的有向圖的最大流量的算法。 該程序基於一個不包含在此處調查的源中的可重用GraphSearch類。 該程序集在程序長度和結構上顯示出至關大的變化性。 平均長度爲236個非空的非註釋行代碼(LOC)。 它包括2個剽竊他人的程序(即4個程序構成2個抄襲對)。 咱們經過對全部程序進行仔細的手動比較來肯定這個程序集和其餘程序集內的抄襲對,即咱們應用了人類審查人員能夠作的最好的檢查。 因爲這些程序存在至關大的結構變化,咱們認爲這個程序爲JPlag設置了一個相對簡單的任務,所以該程序的名稱爲Simple。

「硬」:乘法排列。 將兩個置換表示爲置換矩陣,由整數數組實現,指示每行的1的位置。 這是一個很是短的程序(平均長度43 LOC),具備至關固定的結構。 咱們可能指望即便是獨立編寫的程序看起來也很是類似。 所以,這個程序集對於JPlag來講是一個很是嚴格的測試,所以將被命名爲Hard。 在節目集中有12個節目造成6個抄襲對。

e命名爲Hard。 在節目集中有12個節目造成6個抄襲對。 「清潔」:k-均值。 一維k均值聚類程序,使用絕對距離做爲距離函數,並在數據範圍內以等距方式進行初始化。 平均節目長度是118 LOC。 這個程序集根本不包含任何剽竊行爲,所以將其命名爲Clean。

「大」:跳箱。 一個簡單的圖形遊戲,玩家必須將鼠標移動到屏幕上跳轉的方塊。 這套節目平均時間最長,也是節目設計中最大的節目; 平均節目長度是263 LOC。 在節目集中有4個抄襲對。 它還包含另外兩個具備不少類似性的對,但咱們不認爲它們是實際的剽竊。 其中之一,這兩個程序員顯然在早期階段一塊兒工做,但後來獨立完成了他們的程序。 另外一方面,這兩個程序共享一個共同的分數做爲基礎,並從早期的AWT編程練習中得到。

3.1.2人工程序集:Hard.P,Large.P等

爲了更仔細地調查JPlag的行爲,咱們的程序集中的實際剽竊數量不足。 所以,咱們經過在網站上公開發布「尋求剽竊」並經過電子郵件收集意見書來收集進一步的剽竊。 回答咱們的電話的學生和其餘程序員從咱們的網頁下載了一個源程序,對其進行了修改並將其發回。 他們被告知要像一個剽竊並試圖欺騙剽竊檢測計劃的學生行事,特別是不要花費過多的時間。 中間80%的剽竊者最終使用了7到40分鐘的自我報告時間。

對於發佈的12個原始程序(從硬件程序集6和大型程序集6中隨機選擇)中的每個,咱們所以收集了14個剽竊版本,致使多達105個額外的抄襲對。基於這些額外的剽竊,咱們爲JPlag的評估造成了額外的程序集(請參閱表3):
Hard.all基於Hard和其餘一系列剽竊行爲的結合
收集它。
Hard.P基於Hard.all,但僅包含全部這些程序
也存在抄襲(原創或收集)。在這個程序集中,一個很大的
全部節目對中的一小部分是抄襲對。
Large.all和Large.P是基於Large和
爲此收集了更多的剽竊品。

請注意,爲了簡潔,Hard.all和Large.all將在3.2和3.3節中分別討論,但包含在3.4和3.5節中,其中咱們還使用了Hard.all中的兩個較高抄襲內容的較小子集和另外兩個來自Large.all

3.1.3評估標準,定義

JPlag能夠被視爲一個具備固定查詢的信息檢索系統:給定一組程序對,檢索全部那些是剽竊的對,但沒有其餘的。 對於這樣的操做模式,咱們只須要經過應用截止閾值將每對產生的類似度值轉化爲是/否決策:具備高於閾值的類似度的全部對將被認爲是抄襲對。

爲了表徵JPlag輸出的正確性,咱們可使用通用信息檢索質量度量「精度」(P)和「回憶」(R)。 這些措施的定義以下。 假設咱們有一組n個節目,其中p = n·(n-1)/ 2對,這些對中的g是抄襲對,即一個節目從另外一個抄襲或者兩個抄襲都是(直接或間接)抄襲 一些共同的祖先也是程序集的一部分。

如今假設JPlag返回f個標記爲剽竊對的程序對。 若是這些對中的t是真正的抄襲對,而其餘的f - t不是,那麼咱們將精確度和回憶定義爲P:= 100·t / f和R:= 100·t / g,即精度是 實際抄襲對和召回標記對的百分比是實際標記的全部抄襲對的百分比。

此外,咱們將100·g / p定義爲剽竊內容,即全部抄襲對的分數(見表3的「%」欄)。

3.1.4其餘參數在研究中有所不一樣

如第2.2節所述,JPlag算法中有兩個自由參數:最小匹配長度M和使用的令牌集。 這兩種狀況在咱們的研究中也有所不一樣。

默認標記集「normal」包含描述主要程序結構(變量聲明,類/方法的開始/結束等)和控制流(返回,中斷,繼續,拋出,if,while,等等的開始/結束)的標記。 ),加上2個令牌(分配)和方法調用(應用)。 它忽略了表達式(操做符,操做數)內的全部結構以及方法的標識等。除了默認的標記集,咱們還使用了一個至關小的標記集(稱爲「struc」),其中只包含與控制流和程序塊結構相關的標記 但不包括變量聲明)。 此外,咱們使用了包含全部可能令牌的最大令牌集(稱爲「滿」)。
咱們使用了最小匹配長度3,4,5,7,9,11,14,17,20,25,30和40. 9是默認值。

3.2基本結果

爲簡要總結JPlag的性能,咱們將首先報告使用標準參數(最小匹配長度9,正常標記集)和50%截止閾值時咱們每一個數據集的精度和召回率的值。 摘要顯示在表3最右邊的兩列中。

正如咱們所看到的,JPlag的性能對於簡單,清潔和大型來講是完美的; 對於咱們四個真實世界的數據集中有三個咱們不但無一例外地得到全部的抄襲對,並且輸出也徹底沒有非抄襲對

對於困難的數據集Hard,咱們錯過了6個抄襲對中的2個(R = 0.67),並錯誤地檢索了7個非抄襲對以及4個正確的抄襲對。 不徹底召回固然能夠經過下降截止門限來改善,但這也會致使更多不正確的輸出。 這個折衷將在3.3節中分析。

具備高剽竊密度的人造數據集的結果也很是好:JPlag檢測到兩種病例(Large.P和Large.all)中全部剽竊對的92%,另外兩種(Hard.P 和Hard.all),除一個案例(Hard.all)外,結果徹底沒有虛假輸出。

鑑於咱們在第4節中介紹的程序設計者嘗試的各類假裝嘗試,這些結果至關使人印象深入。

3.3類似度值的分佈; 精確/回憶權衡

理想狀況下,JPlag會報告任何非抄襲對的0%和任何抄襲對的100%的類似度。 但實際上,這種區別幾乎沒有那麼清楚。 所以,爲了判斷先前顯示的結果的穩健性,咱們如今回顧JPlag爲抄襲對產生的類似性值的分佈,並將其與非抄襲對的分佈進行比較。 若是兩個分佈重疊,則一個或多個節目對將被錯誤地判斷

簡單:「最大化流量」程序。 咱們的第一個例子是程序集Simple。 結果顯示在圖2中。該程序集致使總共378個程序對,其中只有2個是實際的抄襲對。 圖的上半部分顯示了376個非抄襲對的類似度值分佈,即2個抄襲對的底部。

JPlag在至關普遍的截止門檻範圍內將剽竊與其餘節目完美區分開來。 圖3的左側部分顯示了當咱們逐漸增長截止閾值時回想如何改變:只有在至關高的截止閾值時,咱們纔會錯過任何剽竊行爲。 精確度和召回率之間的折中結果顯示在圖的右側。 咱們老是至少有完美的精確度或完美的召回率,對於適當選擇的截止閾值,咱們甚至能夠同時獲得二者,即曲線到達曲線的右上角(100/100,理想點)。

總結起來,JPlag的行爲對於這個程序集是完美的。
硬:「多重排列」計劃。 請記住,該算法的簡單性代表了一個有點規範的程序結構。 所以咱們能夠指望這個程序對JPlag來講是一個很是困難的測試。

硬:「多重排列」計劃。請記住,該算法的簡單性代表了一個有點規範的程序結構。所以咱們能夠指望這個程序對JPlag來講是一個很是困難的測試。圖4確實代表Hard程序集的行爲不太理想:類似性值分佈有至關多的重疊。讓咱們首先考慮一下,注意在絕對數量中,剽竊對的分佈幾乎能夠忽略不計,由於剽竊的內容只有0.3%。儘管存在困難,但非剽竊的類似度值的分佈幾乎與Simple相同。另外一方面,除了一個例外,Hard中的6個抄襲對僅表現出中等類似度,即便對於人類觀察者也是如此。看看源程序,咱們獲得了這樣的印象,即學生們大部分都在一塊兒工做,但不管如何均可能獨立完成他們的程序。可是,鑑於節目規模較小,沒法肯定。因此人們能夠說,這些根本不是剽竊。可是爲了獲得一種最壞的狀況分析,讓咱們假設這6對確實都是真正的剽竊。而後,精度/回憶權衡是遠遠不理想的(參見圖5底部),但中等截斷閾值仍然致使合理的妥協,如前所述回收67例。

3.4令牌集合和最小匹配長度的影響

到目前爲止全部的數據都使用了JPlag的默認參數:「正常」標記集和標準最小匹配長度爲9.可是,咱們也感興趣的是JPlag如何抵抗這些參數的變化以及這些變化如何與 程序集進行分析。 所以,下面介紹性能測量,咱們將研究JPlag的性能如何針對不一樣的最小匹配長度,截止閾值,令牌集和程序集進行更改。

咱們經過精確度和召回率的加權和來衡量JPlag的總抄襲鑑別性能。 咱們選擇3的回憶(相對於精確度)的相對權重,由於懲罰假陰性(非檢測到的抄襲)遠遠大於誤報,這僅僅爲人類用戶的最終判斷提供了更多的工做。 所以,績效指標變爲P + 3R。 確切的值3並不重要,重量爲2或4的結果將是類似的。

咱們將在這裏省略分析的大量細節,僅提供結果; 更多的細節能夠在[Prechelt et al。,2000]中找到。 當分析使用「正常」標記集合和截止閾值50時最小匹配長度M與P + 3R量度之間的相關性時,咱們作出如下觀察:

1. M的最佳值可能取決於所選擇的截止閾值。 這並不奇怪,由於較小的M會致使一般較高的類似性值。
2.所以,增長M的整體表現趨勢多是向上,向下或山形。所以,任何固定的M都必須被認爲是妥協。
4.低的最小匹配長度每每會產生虛假匹配,從而下降精度。
5.高的最小匹配長度傾向於錯過更多的抄襲區域,從而減小回憶,特別是對於抄襲內容更高的人工程序集。
6.整體而言,除非所選擇的價值遠離最優價值,不然性能損失很小。

咱們得出這樣的結論:JPlag對M的適度非最佳選擇是強有力的

使用小型「struc」標記集的相同分析發現,因爲標記字符串較短,較大​​的M值不太可取。不然,結果與默認令牌集的結果很是類似。

最後,對於最大可能的令牌集,稱爲「完整」,咱們發現因爲較長的令牌字符串,更大的M可能更容易被容忍,但適度的值仍然傾向於優越。不然,結果再次與缺省和縮減的標記集類似。

咱們得出這樣的結論:JPlag對於不一樣的令牌集合的選擇是高度可靠的。這頗有用,由於它代表JPlag對於許多其餘編程語言也能夠相似地工做,若是它們容許相似結構的標記集合。

此外,咱們得出結論:默認的標記集合和默認的最小匹配長度9是JPlag針對各類程序集的合理和可靠的參數選擇。

3.5截止標準的影響

一般,咱們會看JPlag找到的最類似的一對節目,並分別爲每一對節目決定它是不是抄襲對。 人們將以這種方式朝着較低的類似度值前進,直到人們確信發現了全部的剽竊行爲。

然而,在某些狀況下,基於類似性閾值的全自動決策是優選的:具備該類似性或更高類似性的對將被視爲剽竊,而具備較低類似性的對將被視爲獨立。 咱們稱這樣一個標準爲截止標準。 截止標準接收類似值的向量s做爲輸入,而且如上所述計算截止閾值T.

爲了在全自動模式下評估JPlag,咱們使用了許多不一樣的截止標準。 它們中的大多數適應於正在調查的程序集的類似性分佈。 從上面的討論中咱們已經知道在30到60範圍內的截止閾值一般會產生最好的結果。 可是,目前還不清楚是否存在幾乎老是最佳的固定閾值。 考慮當前類似度分佈的適應性標準可能會更成功。 這些是咱們探索的截止標準:

脫粒。 截斷標準的threshT系列使用最簡單的方法:它根本不查看輸入矢量,而是應用固定的截止門限來作出決定。 咱們已經使用了從30%到95%的各類閾值T,從而致使閾值thresh30到thresh95。

mplus。 mplusD家族的截止標準有點適應於系統中較高或較低的s類似度值。 它返回向量中類似值的中值(50%分位數,q50)加上距中值到100的距離的D百分比:T = q50(s)+ D / 100 *(100-q50(s))。 與固定閾值相比,這些標準能夠適應不一樣的「基本類似性」; 他們認爲中位數類似度表明了一個典型的非抄襲對,由於遠遠不到全部配對的一半都是抄襲對。 咱們使用了mplus25,mplus50和mplus75。

qplus。 qplusD家族至關於mplusD家族,除了偏移量的起點是第三個四分位數:T = q75(s)+ D / 100 *(100-q75(s))。 這個想法是q75可能表明一個更大的意外類似的狀況,因此即便是小的D值也不該該致使誤報。 咱們使用了qplus25,qplus50和qplus75。

K均值。 kmeans截止標準使用一維k-均值聚類將矢量分紅兩類。 具備較高類似性值的類將被視爲抄襲對。

avginf。 avginf家族的截斷標準考慮具備大體相同的類似度值的對的信息內容。這裏的想法是,剽竊行爲應該是罕見的,所以代表剽竊行爲的類似性值的範圍必須具備很高的信息含量(在信息理論意義上)。所以,咱們選擇閾值T做爲具備此類似度或更高類似度的對的平均信息內容Cv≥T至少比總體平均值C高百分之P的最小閾值。爲此,avginf標準將類似度值組合成重疊寬度爲5%的類:給定全部對的類似度值的向量s,令Sv爲s的值爲v ... v + 5的類似度集合。而後,每一個這樣的對的信息內容爲Cv:= - log2(| Sv | / | s |)和空類被定義爲沒有信息內容,即,若是Sv = C,則Cv:= 0。基於這些值Cv,能夠肯定閾值。咱們使用了avginf050,avginf100,avginf200和avginf400。

圖9比較了截止標準的性能分佈,基於性能測量P + 3R。 對於原始程序集,最好的標準是thresh50,thresh60,qplus50和mplus50。 他們對於P + 3R的中位數都是400(即至少有一半的結果是完美的),平均值約爲330,第一個四分位數約爲280.對於人工程序集,沒有一個標準可以達到。 最好的是thresh40,qplus25和mplus25。 這是一個好消息:出於實際目的(剽竊數量一般很小),像閾值這樣簡單的規則彷佛會產生最好的結果。

3.6 JPlag和MOSS的比較

咱們還經過MOSS [Aiken,1998]運行咱們的基準程序集,對結果進行後處理,使用與JPlag相同的類似性度量,而後計算各類截止閾值的精度和召回率。 結果如表4所示。

表中的左邊部分假設了理想化的截止標準,在每種狀況下都選擇最佳閾值。 請注意,MOSS一般會返回比JPlag至關低的類似值。 正如咱們所看到的,就簡單,清潔和大型(或其變體)而言,MOSS的性能與JPlag基本相同。 惟一的區別是MOSS必須比JPlag更強烈地依賴於截斷閾值的可變性。

然而,對於Hard程序集的變體,JPlag顯然是優越的:對於Hard.P和Hard.all,JPlag以更好的精度實現相同的召回。 請注意,對於Hard.all,當t = 30時,JPlag達到P = 46,R = 88,可是這具備較低的P + 3R。 並且,對於原始程序集Hard,MOSS沒法找到三分之一以上的抄襲對,即便使用最低截止閾值10時也是如此。

若是咱們爲每一個系統選擇一個固定的閾值,就會出現相似的狀況,如表格的右半部分所示:咱們將JPlag的類似度下降了50%,MOSS下降了30%。 這些閾值是合理的,每每會平衡精確度和回憶。 結果代表,JPlag的精確度或召回率比MOSS差,可是其中不少狀況下,MOSS明顯比JPlag更差 - 特別是對於hard程序集。 如前所述,沒有關於MOSS算法的書面描述。 所以,咱們沒法解釋結果.

若是咱們爲每一個系統選擇一個固定的閾值,就會出現相似的狀況,如表格的右半部分所示:咱們將JPlag的類似度下降了50%,MOSS下降了30%。 這些閾值是合理的,每每會平衡精確度和回憶。 結果代表,JPlag的精確度或召回率比MOSS差,可是其中不少狀況下,MOSS明顯比JPlag更差 - 特別是對於硬件程序集。 如前所述,沒有關於MOSS算法的書面描述。 所以,咱們沒法解釋結果

3.7運行時效率

JPlag的運行時間隨着程序集中程序數量的增長而呈二次曲線增加,而且與程序的大小略微超線性。

可是,由此產生的運行時間一般很小。 咱們最大的節目集Large.all包含99個節目,平均約250個LOC。 JPlag用於閱讀和解析這些程序以及執行全部配對比較的總運行時間是Pentium III上的掛鐘時間大約6秒

4成功和不成功的剽竊攻擊

本節分析假裝技術和咱們在用於評估的計劃中看到的攻擊類型。 任何單一的攻擊事件最多都會致使咱們稱之爲JPlag的局部混亂。 考慮應用假裝技術所需的最短代碼段。 若是JPlag沒有肯定原始代碼段和攻擊結果之間的任何類似性,咱們說JPlag在本地是混亂的。 局部混淆關鍵取決於所使用的令牌集和最小匹配長度。

例如,若是將單行代碼(或單個令牌)插入到最小匹配長度的代碼段中,可能會致使本地混淆。 插入後,JPlag一般不會再找到具備足夠的令牌來匹配的相應代碼段。 再舉一個例子,若是最小匹配長度的代碼段被分紅兩部分而後交換,JPlag也被欺騙了。

除非程序很是短,不然在剽竊逃避檢測以前須要進行一些局部混淆(取決於截止標準)。 完美的攻擊將須要在原始代碼的每一個片斷中以最小匹配長度來實現局部混淆。 JPlag將會成功,除非剽竊者既富有創造性,足以發現足夠的假裝技術,能夠在整個給定的程序中應用(大多數技術只適用於某些狀況),而後渴望足夠頻繁地應用它們。

4.1無效攻擊

本節討論的攻擊根本不起做用,由於它們不會對JPlag生成並考慮的令牌列表進行任何修改。 幾乎每一個剽竊者都至少使用過這些徒勞的假裝技術之一。

  • 經過改變換行符,空格和TAB來修改代碼格式[48 times3]
  • 插入,修改或刪除評論[30次]
  • 程序輸出或其格式的修改[33次,2次成功]在2個程序中,修改後的輸出格式致使額外的方法調用。
  • 更改變量,方法或類的名稱[44次]
  • 分割或合併變量聲明列表[6次]
  • 修改器,如私人,最終等[6次]
  • 常數值的修改[3次]
  • 有些學生根本沒有試圖假裝他們的做弊,並提交了相同的副本。 若是提交次數過大,沒法手動比較全部數據而且沒有自動系統,則可能會發生這種「攻擊」。[4次]

正如咱們從這個列表中看到的,JPlag對格式化,評論,文字和名稱的徹底無知是其成功的關鍵。 爲默認令牌集選擇的粗粒度(例如,忽略修飾符)也是有用的。

4.2對粒度敏感的攻擊

粗略地說,Java類由方法和變量的聲明組成。 聲明的排序是可有可無的。 所以,一個有前途的攻擊行是從新排序實現中的聲明。 可是,若是從新排序的代碼段長於最小匹配長度,則JPlag信號將阻止移動,而不是在本地混淆。 所以,這種攻擊的成功與否關鍵取決於其應用的粒度。

剽竊者常用這種類型的從新排序[55次]。 可是,他們中只有大約15%實際上混淆了JPlag。

  • 在變量聲明塊內從新排序[25次,6次成功]
  • 變量和方法聲明的全局從新排序[30次,3次成功]

4.3局部混淆攻擊

如下類型的攻擊一般在本地成功,至少使用默認的令牌集。 在134次這些襲擊中,只有12次不成功。 然而,只有極少數的剽竊者在一個特定的程序中實現瞭如此之多的局部混淆以逃避被發現。

  • 修改控制結構[35次,所有成功]

    •用while循環代替for循環,反之亦然[8次]
       •經過用主迭代變量[3次]表達它們來消除輔助指標變量
       •用無限循環代替常規循環[1次]
       •用一系列if語句替換switch-statement [6次]
       •爲switch語句的每一個case添加冗餘break-statements [1次]
  • 臨時變量和子表達式[28次,所有成功]

    •將子表達式轉換爲新的輔助變量[16次]
       •反之亦然[7次]
       •經過賦值列表替換數組初始值設定項[2次]
       •從聲明中移除初始化[2次]
       •用默認值[1次]顯式初始化
  • 內聯和重構[20次,16次成功]

    •內聯小方法[5次]
       •將現有方法的部分重構爲新方法[11次]
  • 修改範圍[9次,所有成功]

    •將合理性測試或試驗塊的開始/結束移向方法的開始和/或結束[3次]
       •將臨時變量移動到周圍的塊中[3次]
       •在內部塊中添加臨時變量的冗餘聲明[1次]
       •若是隻有一個實例存在,則用實例變量替換類變量[2次]
  • 從新排序基本塊內的獨立語句[8次,6次成功]
  • 利用數學身份[5次,2次成功]
  • 自願引入程序缺陷[5次,3次成功] 3名剽竊者刪除代碼或添加其餘語句。 兩次不成功的嘗試涉及修改後的常量。
  • 修改數據結構[6次,5次成功]

    •用char數組替換字符串[1次]
       •用兩個單獨的int [1次]替換int [2]
       •用數組替換幾個相同類型的變量[3次]
       •提高整數[1次,不成功]
    • 冗餘[15次,14次成功]
      •添加或刪除未使用的代碼[7次]
      •使用徹底限定的軟件包名稱[2次]
      •插入虛擬方法的調用[1次]
      •導入額外的軟件包和類[1次]
      •將呼叫插入到Thread.yield()[1次]
      •在void方法結束時插入return [1次]
      •複製右側無反作用的賦值語句[1次]
      •訪問實例變量時添加或刪除此事件[1次,不成功]做爲對策措施,JPlag的默認令牌集將忽略此設置。
  • 代碼結構從新設計[3次,所有成功]

    •將狀態改變方法轉換爲單獨的新類[2次]
       •建立並返回一個新對象,而不是改變現有狀態[1次]

    在這個列表中,最後三種類型的攻擊是很是聰明的,即便對於讀者來講也很難檢測:修改數據結構,添加或刪除冗餘,或從新設計代碼結構。

    5 Summary and conclusions

咱們使用4套真實Java程序和另外幾套包含額外剽竊的Java程序集對JPlag進行的實證評估可總結以下:

  • 對於清楚剽竊的節目,即徹底採用節目並進行修改以隱藏起源的節目,JPlag的結果幾乎完美 - 即便節目長度少於100行也是如此。
  • 即便只有部分剽竊節目,就像咱們的硬盤節目集合同樣,JPlag將指出類似之處,而且一般能夠很好地區分它們與意外類似之處。
  • 剽竊者從真實程序集中選擇的假裝(若是有的話)對JPlag徹底沒用。
  • 即便是知情剽竊者選擇的攻擊在全部案例中的成功率都不到10%。 這些人知道他們必須欺騙一個程序,並無其餘目標(除了只用一點時間來完成)。
  • 對JPlag檢測的成功攻擊須要不少工做,或者會產生一個對任何人員檢查員來講都很荒謬的程序結構。
  • JPlag很是適合對其兩個自由參數,令牌集和最小匹配長度的非最優選擇。
  • 給定JPlag計算的類似度值,一個固定的截止閾值就足以做爲一種判別標準,它將剽竊的程序對與非剽竊的程序對分離,而且具備接近最佳的回憶率,但仍具備良好的精確度。

咱們並不確切知道這些結果轉移到其餘狀況的程度。 它們可能適用於C和C ++的較小程度,由於這些語言目前還沒有解析,但僅由JPlag掃描。 對於不一樣結構的(或更大的)程序,若是這些攻擊使某些攻擊更加有效,或者對於不一樣的攻擊者(若是那些攻擊者仍然使用不一樣的攻擊)

可是,整體而言,若是JPlag的有效性遠遠低於證實的效果,咱們會感到驚訝。 看起來基於標記的字符串類似性方法對尋找剽竊很是有效,至少若是令牌字符串忽略了足夠的細節。 對於用Java,C,C ++和Scheme編寫的程序,JPlag是一種易於使用的實現方法.

原則上,JPlag也能夠用於其餘目的。 若是一家軟件公司懷疑競爭對手竊取了部分源代碼,那麼在法院命令或雙方協議後JPlag能夠比較兩個有問題的大型程序系統並指出相似的區域。 JPlag已經成功應用於這種狀況下(其各方但願保持匿名).

經過指出不一樣的區域,而不是那些類似的區域,JPlag能夠用做程序差別引擎(如Unix diff)。與基於字符的差別相比,JPlag差別忽略了不少細節,所以產生了更小的(儘管 也不太精確)的差別,這在某些狀況下可能有用。

文獻名稱: Lutz Prechelt , Guido Malpohl , Michael Philippsen. Finding Plagiarisms among a Set of Programs with JPlag[J]

前端VUe代碼的github地址

後端地址SSM

相關文章
相關標籤/搜索