3による可分性のための回路の構築


12

TCS のブール回路は、基本的にAnd、Or、Notゲートで構成されるDAGであり、「機能的完全性」が知られていることにより、可能なすべての機能を計算できます。例えば、これはALUの基本原則です。

課題:8進数の数字が3で割り切れるかどうかを判断する回路を作成し、何らかの方法で結果を視覚化します(つまり、何らかの画像で)

投票者の判断基準は、回路を生成するコードが任意のサイズの数値にうまく一般化されているかどうか、およびアルゴリズムで作成された視覚化がコンパクト/バランスが取れているがまだ人間が読み取れるかどうかに基づいています(つまり、手作業による視覚化は許可されていません)。すなわち、視覚化はn = 8のみに対して行われますが、コードはすべての「n」に対して理想的に機能します。入賞作品はトップ投票のみです。

やや似た質問:NAND論理ゲートを使用して乗算機を構築する


2
ずっといい。しかし、「一般化」と「美観」は客観的ではありません。すべての質問には、客観的な勝利基準が必要です。これらの特性を適用する場合は、popularity-contestを使用してください。最短のコードが必要な場合は、code-golfを使用してください。2つの組み合わせを作成する場合は、コードチャレンジを使用しますが、式を指定します。たとえば、1.25 *投票-この質問のように0.25 *長さ:codegolf.stackexchange.com/questions/23581/eiffel-tower-in-3d/…–
Level River St

OK、それらのchgsを要求しました。フィードバックのためのthx。
vzn 14年

ああ、私はすべての最適化が最も短い答えを与えるべきだった後にコンパイルされたVHDLまたはVerilogを推測します。後で試します。
キリルクラコフ14年

1
より良い勝利の基準は次のようになり、ゲート-ゴルフ
TheDoctor

@医者 ???何gate-golfですか?そのタグは存在しません。参加者への注意:使用している言語/視覚化ツールを明記してください。他の人がplzコメントを入力したい場合。そうでなければ、勝者のトナイトを受け入れます。これまでのところ、これは予想以上に「BTE」になりました。
vzn

回答:


7

3を法とする数を計算する回路

グラフは各レベルiで3つのブール値を維持します。これらは、数値の上位iビットが0、1、または2 mod 3に等しいという事実を表します。各レベルで、前の3ビットと次の入力ビットに基づいて次の3ビットを計算します。

グラフを生成したPythonコードは次のとおりです。Nを変更して異なるビット数を取得するか、Kを変更して異なるモジュラスを取得するだけです。pythonプログラムの出力をドットで実行して、画像を生成します。

N = 8
K = 3
v = ['0']*(K-1) + ['1']
ops = {}

ops['0'] = ['0']
ops['1'] = ['1']
v = ['0']*(K-1) + ['1']
for i in xrange(N):
  ops['bit%d'%i] = ['bit%d'%i]
  ops['not%d'%i] = ['not','bit%d'%i]
  for j in xrange(K):
    ops['a%d_%d'%(i,j)] = ['and','not%d'%i,v[(2*j)%K]]
    ops['b%d_%d'%(i,j)] = ['and','bit%d'%i,v[(2*j+1)%K]]
    ops['o%d_%d'%(i,j)] = ['or','a%d_%d'%(i,j),'b%d_%d'%(i,j)]
  v = ['o%d_%d'%(i,j) for j in xrange(K)]

for i in xrange(4):
  for n,op in ops.items():
    for j,a in enumerate(op[1:]):
      if ops[a][0]=='and' and ops[a][1]=='0': op[j+1]='0'
      if ops[a][0]=='and' and ops[a][2]=='0': op[j+1]='0'
      if ops[a][0]=='and' and ops[a][1]=='1': op[j+1]=ops[a][2]
      if ops[a][0]=='and' and ops[a][2]=='1': op[j+1]=ops[a][1]
      if ops[a][0]=='or' and ops[a][1]=='0': op[j+1]=ops[a][2]
      if ops[a][0]=='or' and ops[a][2]=='0': op[j+1]=ops[a][1]

for i in xrange(4):
  used = set(['o%d_0'%(N-1)])|set(a for n,op in ops.items() for a in op[1:])
  for n,op in ops.items():
    if n not in used: del ops[n]

print 'digraph {'
for n,op in ops.items():
  if op[0]=='and': print '%s [shape=invhouse]' % n
  if op[0]=='or': print '%s [shape=circle]' % n
  if op[0]=='not': print '%s [shape=invtriangle]' % n
  if op[0].startswith('bit'): print '%s [color=red]' % n
  print '%s [label=%s]' % (n,op[0])
  for a in op[1:]: print '%s -> %s' % (a,n)
print '}'

すごい!graphvizも使用しています...小さなめき、ダイアグラムには未使用のAND / ORがあります。また、多分その場所を示すために、異なる色で入力ビットを強調することをお勧め
vzn

@vzn:OK、修正済み。
キースランドール14年

12

深さ:7(対数)、18x AND、6x OR、7x XOR、31ゲート(線形)

3を法とする基数4の桁合計を計算します。

階層構造がはっきりと見える7層回路

Logisimで描かれた回路

一般化、正式(できれば多少読みやすい):

balance (l, h) = {
  is1: l & not h,
  is2: h & not l,
}

add (a, b) = 
  let aa = balance (a.l, a.h)
      bb = balance (b.l, b.h)
  in  { l:(a.is2 & b.is2) | (a.is1 ^ b.is1),
        h:(a.is1 & b.is1) | (a.is2 ^ b.is2)}

pairs [] = []
pairs [a] = [{h:0, l:a}]
pairs [rest.., a, b] = [pairs(rest..).., {h:a, l:b}]

mod3 [p] = p
mod3 [rest.., p1, p2] = [add(p1, p2), rest..]

divisible3 number =
  let {l: l, h: h} = mod3 $ pairs number
  in  l == h

今英語で:

数値に3ビット以上ある場合、最下位の2つのビットペアを取得し、それらを3を法として合計し、結果を数値の後ろに追加し、最後のペアが3を法としてゼロの場合に戻ります。数の中のビット数、余分なゼロビットを先頭に追加し、定数値の伝播で磨きます。

前面ではなく背面に追加すると、追加ツリーがリンクリストではなくバランスの取れたツリーになります。これにより、ビット数の対数深度が保証されます。5つのゲートとペアキャンセル用の3つのレベル、最後に追加のゲートがあります。

もちろん、おおよその平面性が必要な場合は、最上部のペアを前面にラップするのではなく、変更せずに次のレイヤーに渡します。ただし、これは実装(擬似コードでも)よりも簡単です。ただし、数値のビット数が2の累乗である場合(2014年3月現在の最新のコンピューターシステムの場合)、孤立したペアは発生しません。

レイアウト担当者がローカリティを保持し、ルート長の最小化を実行する場合、回路を読み取り可能に保つ必要があります。

このRubyコードは、任意のビット数(1ビットでも)の回路図を生成します。印刷するには、Logisimで開き、画像としてエクスポートします。

require "nokogiri"

Port = Struct.new :x, :y, :out
Gate = Struct.new :x, :y, :name, :attrs
Wire = Struct.new :sx, :sy, :tx, :ty

puts "Please choose the number of bits: "
bits = gets.to_i

$ports = (1..bits).map {|x| Port.new 60*x, 40, false};
$wires = [];
$gates = [];

toMerge = $ports.reverse;

def balance a, b
y = [a.y, b.y].max
$wires.push Wire.new(a.x   , a.y , a.x   , y+20),
          Wire.new(a.x   , y+20, a.x   , y+40),
          Wire.new(a.x   , y+20, b.x-20, y+20),
          Wire.new(b.x-20, y+20, b.x-20, y+30),
          Wire.new(b.x   , b.y , b.x   , y+10),
          Wire.new(b.x   , y+10, b.x   , y+40),
          Wire.new(b.x   , y+10, a.x+20, y+10),
          Wire.new(a.x+20, y+10, a.x+20, y+30)
$gates.push Gate.new(a.x+10, y+70, "AND Gate", negate1: true),
          Gate.new(b.x-10, y+70, "AND Gate", negate0: true)
end

def sum (a, b, c, d)
y = [a.y, b.y, c.y, d.y].max
$wires.push Wire.new(a.x   , a.y , a.x   , y+40),
          Wire.new(a.x   , y+40, a.x   , y+50),
          Wire.new(a.x   , y+40, c.x-20, y+40),
          Wire.new(c.x-20, y+40, c.x-20, y+50),
          Wire.new(b.x   , b.y , b.x   , y+30),
          Wire.new(b.x   , y+30, b.x   , y+50),
          Wire.new(b.x   , y+30, d.x-20, y+30),
          Wire.new(d.x-20, y+30, d.x-20, y+50),
          Wire.new(c.x   , c.y , c.x   , y+20),
          Wire.new(c.x   , y+20, c.x   , y+50),
          Wire.new(c.x   , y+20, a.x+20, y+20),
          Wire.new(a.x+20, y+20, a.x+20, y+50),
          Wire.new(d.x   , d.y , d.x   , y+10),
          Wire.new(d.x   , y+10, d.x   , y+50),
          Wire.new(d.x   , y+10, b.x+20, y+10),
          Wire.new(b.x+20, y+10, b.x+20, y+50)
$gates.push Gate.new(a.x+10, y+90, "XOR Gate"),
          Gate.new(b.x+10, y+80, "AND Gate"),
          Gate.new(c.x-10, y+80, "AND Gate"),
          Gate.new(d.x-10, y+90, "XOR Gate")
$wires.push Wire.new(a.x+10, y+90, a.x+10, y+100),
          Wire.new(b.x+10, y+80, b.x+10, y+90 ),
          Wire.new(b.x+10, y+90, a.x+30, y+90 ),
          Wire.new(a.x+30, y+90, a.x+30, y+100),
          Wire.new(d.x-10, y+90, d.x-10, y+100),
          Wire.new(c.x-10, y+80, c.x-10, y+90 ),
          Wire.new(c.x-10, y+90, d.x-30, y+90 ),
          Wire.new(d.x-30, y+90, d.x-30, y+100)
$gates.push Gate.new(d.x-20, y+130, "OR Gate"),
          Gate.new(a.x+20, y+130, "OR Gate")
end

def sum3 (b, c, d)
y = [b.y, c.y, d.y].max
$wires.push Wire.new(b.x   , b.y , b.x   , y+20),
          Wire.new(b.x   , y+20, b.x   , y+30),
          Wire.new(b.x   , y+20, d.x-20, y+20),
          Wire.new(d.x-20, y+20, d.x-20, y+30),
          Wire.new(c.x   , c.y , c.x   , y+60),
          Wire.new(c.x   , y+60, b.x+30, y+60),
          Wire.new(b.x+30, y+60, b.x+30, y+70),
          Wire.new(d.x   , d.y , d.x   , y+10),
          Wire.new(d.x   , y+10, d.x   , y+30),
          Wire.new(d.x   , y+10, b.x+20, y+10),
          Wire.new(b.x+20, y+10, b.x+20, y+30),
          Wire.new(b.x+10, y+60, b.x+10, y+70)
$gates.push Gate.new(b.x+10, y+60 , "AND Gate"),
          Gate.new(d.x-10, y+70 , "XOR Gate"),
          Gate.new(b.x+20, y+100, "OR Gate" )
end

while toMerge.count > 2  
puts "#{toMerge.count} left to merge"
nextToMerge = []
while toMerge.count > 3
 puts "merging four"
 d, c, b, a, *toMerge = toMerge
 balance a, b
 balance c, d
 sum *$gates[-4..-1]
 nextToMerge.push *$gates[-2..-1] 
end
if toMerge.count == 3
 puts "merging three"
 c, b, a, *toMerge = toMerge
 balance b, c
 sum3 a, *$gates[-2..-1]
 nextToMerge.push *$gates[-2..-1]
end
nextToMerge.push *toMerge
toMerge = nextToMerge
puts "layer done"
end

if toMerge.count == 2
b, a = toMerge
x = (a.x + b.x)/2
x -= x % 10
y = [a.y, b.y].max
$wires.push Wire.new(a.x , a.y , a.x , y+10),
          Wire.new(a.x , y+10, x-10, y+10),
          Wire.new(x-10, y+10, x-10, y+20),
          Wire.new(b.x , b.y , b.x , y+10),
          Wire.new(b.x , y+10, x+10, y+10),
          Wire.new(x+10, y+10, x+10, y+20)
$gates.push Gate.new(x, y+70, "XNOR Gate")
toMerge = [$gates[-1]]
end

a = toMerge[0]
$wires.push Wire.new(a.x, a.y, a.x, a.y+10)
$ports.push Port.new(a.x, a.y+10, true)

def xy (x, y)
"(#{x},#{y})"
end
circ = Nokogiri::XML::Builder.new encoding: "UTF-8" do |xml|
xml.project version: "1.0" do
xml.lib name: "0", desc: "#Base"
xml.lib name: "1", desc: "#Wiring"
xml.lib name: "2", desc: "#Gates"
xml.options
xml.mappings
xml.toolbar do
  xml.tool lib:'0', name: "Poke Tool"
  xml.tool lib:'0', name: "Edit Tool"
end #toolbar
xml.main name: "main"
xml.circuit name: "main" do
  $wires.each do |wire|
    xml.wire from: xy(wire.sx, wire.sy), to: xy(wire.tx, wire.ty)
  end #each 
  $gates.each do |gate|
    xml.comp lib: "2", name: gate.name, loc: xy(gate.x, gate.y) do
      xml.a name: "facing", val: "south"
      xml.a name: "size", val: "30"
      xml.a name: "inputs", val: "2"
      if gate.attrs
        gate.attrs.each do |name, value|
          xml.a name: name, val: value 
        end #each
      end #if
    end #comp
  end #each
  $ports.each.with_index do |port, index|
    xml.comp lib: "1", name: "Pin", loc: xy(port.x, port.y) do
      xml.a name: "tristate", val: "false"
      xml.a name: "output",   val: port.out.to_s
      xml.a name: "facing",   val: port.out ? "north" : "south"
      xml.a name: "labelloc", val: port.out ? "south" : "north"
      xml.a name: "label",    val: port.out ? "out" : "B#{index}"
    end #port
  end #each
end #circuit
end #project
end #builder

File.open "divisibility3.circ", ?w do |file|
file << circ.to_xml
end

puts "done"

最後に、32ビットの出力を作成するように求められたときに、私のレイアウト担当者がこれを生成します。確かに、非常に幅の広い入力にはあまりコンパクトではありません。

無駄なスペースがたくさんある13層の怪物


これまでのところ本当に素晴らしいと最高の回路/レイアウトに見えます。コードは何語ですか?もしあれば、どのレイアウターを使用しましたか?レイは言及されない限り(手のレイアウト)を使用していなかったアルゴリズムであり、そのアルゴリズムを想定する必要があるように要求された...
vzn

@vznレイアウトも実装する必要がありましたか?この制限は、ダイアグラムを手動で描画できることを意味すると理解しましたが、読みやすさはダイアグラムの描画方法に依存してはなりません。TimWollaの回路は間違いなく手作業で作成されています。擬似コードは、主にJavascriptyオブジェクトが追加されたHaskellに基づいています。
ジョン・ドヴォルザーク

アルゴリズムで作成された視覚化とは、基本的にアルゴリズムレイアウトを意味することを意味していましたが、今ではあいまいに解釈できることを認めています。クリスタルの透明度が不足して申し訳ありません。手のレイアウトとほぼ同様の結果を得ることができる自動レイアウト機能を知っていますか?
vzn 14年

残念だけど違う。yEdには優れたレイアウト機能がありますが、向きは無視されます。私はドットに精通したことは一度もありませんし、その出力を正確に見つけることができません。この擬似コードをRubyに(簡単に)変換し、ロジシム回路をエクスポートする独自の特化したレイアウター(あまり難しくはないが複雑)を書くことができると思います(XMLであり、gzipで圧縮されていないため、非常に簡単です)。私は(したい)、別の回答として投稿する必要がありますか?また、それは手動で設計されたものとしてカウントされますか?
ジョンドヴォルザーク14年

すべて良い答えですが、これはこれまでで最もエレガントなように見えます
デジタルトラウマ14年

5

2×24 NOT、2×10 + 5 AND、2×2 + 5 OR、2×2 NOR

これはまったくスケーリングしません。全然好きではない。たぶん私はそれを改善しようとします。

私はこれを30までの数についてテストしましたが、うまくいきました。

これらの2つの大きな回路は、アクティブな入力の数をカウントしています。

  • 右上は、偶数のパワー(0〜4)のビット数をカウントします
  • 左下は、奇数のべき乗(0〜4)のビット数をカウントします

それらの数の差がである03、数がで割り切れる場合3。右下の回路は、基本的に(各有効な組み合わせをマッピングし4,44,13,33,02, 21, 10, 0またはに)。

中央の小さな円は、数字が3で割り切れる場合に点灯し、それ以外の場合に消灯するLEDです。


すごい/速い!... plzはコードへのリンクを配置するか、インライン化します...また、視覚化をどのように行ったかを詳述します...?
vzn 14年

@vzn視覚化はlogisimで行われました。私の手で作成されましたが、一般的なアルゴリズムはプログラムでも簡単に実行できます。その答えの一部は説明されています。
ティムウォラ14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.