Skip to content

dict.fromkeys behavior different than dictionary comprehension #137364

@hunterhogan

Description

@hunterhogan

Bug report

Bug description:

To me: complex and confusing

I wish I had the ability to simplify the example code, but I don't. Nevertheless, I believe I have marked the issue well enough that real programmers (unlike me) will be able to separate the wheat from the chaff.

Equivalent statements?

I believe that these two code blocks should behave the same.

Comprehension

dictionaryCurveLocations: dict[int, dict[int, int]] = {n: {} for n in range(bridges + 1)}

dictionaryCurveLocations[bridges] = startingCurveLocations.copy()

fromkeys()

dictionaryCurveLocations: dict[int, dict[int, int]] = {}.fromkeys(range(bridges + 1), {})

dictionaryCurveLocations[bridges] = startingCurveLocations.copy()

I'm sure I am using the wrong terminology, but I think .fromkeys is creating pointers (views?) to dictionaries so that updating one dictionary will update dictionaries that were created before the dictionary being updated.

Code with print for comparisons and a better explanation

Dictionary comprehension

I know the following is annoying, but it is the best I can do.

The print statements embedded in the code explain things better than what I am writing here. Especially when you compare the print statements in the module that is not behaving as I would expect.

fromkeys_comprehension.py

# fromkeys_comprehension.py
def count(bridges: int, startingCurveLocations: dict[int, int]) -> int:
	listCurveMaximums: list[tuple[int, int, int]] = [
	(16, 0x2a, 0x15),
	(64, 0xaa, 0x55),
	(256, 0x2aa, 0x155),
	(1024, 0xaaa, 0x555),
	(4096, 0x2aaa, 0x1555),
	(16384, 0xaaaa, 0x5555),
	(65536, 0x2aaaa, 0x15555),
	(262144, 0xaaaaa, 0x55555),
	(1048576, 0x2aaaaa, 0x155555),
	(4194304, 0xaaaaaa, 0x555555),
	(16777216, 0x2aaaaaa, 0x1555555),
	(67108864, 0xaaaaaaa, 0x5555555),
	(268435456, 0x2aaaaaaa, 0x15555555),
	(1073741824, 0xaaaaaaaa, 0x55555555),
	(4294967296, 0x2aaaaaaaa, 0x155555555),
	(17179869184, 0xaaaaaaaaa, 0x555555555),
	(68719476736, 0x2aaaaaaaaa, 0x1555555555),
	(274877906944, 0xaaaaaaaaaa, 0x5555555555),
	(1099511627776, 0x2aaaaaaaaaa, 0x15555555555),
	(4398046511104, 0xaaaaaaaaaaa, 0x55555555555),
	(17592186044416, 0x2aaaaaaaaaaa, 0x155555555555),
	(70368744177664, 0xaaaaaaaaaaaa, 0x555555555555),
	(281474976710656, 0x2aaaaaaaaaaaa, 0x1555555555555),
	(1125899906842624, 0xaaaaaaaaaaaaa, 0x5555555555555),
	(4503599627370496, 0x2aaaaaaaaaaaaa, 0x15555555555555),
	(18014398509481984, 0xaaaaaaaaaaaaaa, 0x55555555555555),
	(72057594037927936, 0x2aaaaaaaaaaaaaa, 0x155555555555555),
	(288230376151711744, 0xaaaaaaaaaaaaaaa, 0x555555555555555),
	(1152921504606846976, 0x2aaaaaaaaaaaaaaa, 0x1555555555555555),
	(4611686018427387904, 0xaaaaaaaaaaaaaaaa, 0x5555555555555555),
	(18446744073709551616, 0x2aaaaaaaaaaaaaaaa, 0x15555555555555555),
	(73786976294838206464, 0xaaaaaaaaaaaaaaaaa, 0x55555555555555555),
	(295147905179352825856, 0x2aaaaaaaaaaaaaaaaa, 0x155555555555555555),
	(1180591620717411303424, 0xaaaaaaaaaaaaaaaaaa, 0x555555555555555555),
	(4722366482869645213696, 0x2aaaaaaaaaaaaaaaaaa, 0x1555555555555555555),
	(18889465931478580854784, 0xaaaaaaaaaaaaaaaaaaa, 0x5555555555555555555),
	(75557863725914323419136, 0x2aaaaaaaaaaaaaaaaaaa, 0x15555555555555555555),
	(302231454903657293676544, 0xaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555),
	(1208925819614629174706176, 0x2aaaaaaaaaaaaaaaaaaaa, 0x155555555555555555555),
	(4835703278458516698824704, 0xaaaaaaaaaaaaaaaaaaaaa, 0x555555555555555555555),
	(19342813113834066795298816, 0x2aaaaaaaaaaaaaaaaaaaaa, 0x1555555555555555555555),
	(77371252455336267181195264, 0xaaaaaaaaaaaaaaaaaaaaaa, 0x5555555555555555555555),
	(309485009821345068724781056, 0x2aaaaaaaaaaaaaaaaaaaaaa, 0x15555555555555555555555),
	(1237940039285380274899124224, 0xaaaaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555555),
	(4951760157141521099596496896, 0x2aaaaaaaaaaaaaaaaaaaaaaa, 0x155555555555555555555555),
	(19807040628566084398385987584, 0xaaaaaaaaaaaaaaaaaaaaaaaa, 0x555555555555555555555555),
	]

	listCurveMaximums = listCurveMaximums[0:bridges]

	dictionaryCurveLocations: dict[int, dict[int, int]] = {n: {} for n in range(bridges + 1)}
	dictionaryCurveLocations[bridges] = startingCurveLocations.copy()

	print("\nAfter creating dictionary; before entering loop.")
	print(dictionaryCurveLocations)

	while bridges > 0:

		bridges -= 1

		print("\nAfter decrementing bridges.")#; before executing statement.")
		print(dictionaryCurveLocations)
		# dictionaryCurveLocations[bridges] = {}
		print(dictionaryCurveLocations)
		print("^^^After NOT executing statement. (No change.)")

		print("\nExecuted statement:")
		print("`dictionaryCurveLocations[bridges] = {}`")

		curveLocationsMAXIMUM, bifurcationEvenLocator, bifurcationOddLocator = listCurveMaximums[bridges]

		while True:
			try:
				curveLocations, distinctCrossings = dictionaryCurveLocations[bridges+1].popitem()
			except KeyError:
				break
			bifurcationEven = (curveLocations & bifurcationEvenLocator) >> 1
			bifurcationOdd = (curveLocations & bifurcationOddLocator)
			bifurcationEvenFinalZero = (bifurcationEven & 0b1) == 0
			bifurcationEvenHasCurves = bifurcationEven != 1
			bifurcationOddFinalZero = (bifurcationOdd & 0b1) == 0
			bifurcationOddHasCurves = bifurcationOdd != 1

			if bifurcationEvenHasCurves:
				curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			if bifurcationOddHasCurves:
				curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
			if curveLocationAnalysis < curveLocationsMAXIMUM:
				dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			if bifurcationEvenHasCurves and bifurcationOddHasCurves and (bifurcationEvenFinalZero or bifurcationOddFinalZero):
				XOrHere2makePair = 0b1
				findUnpairedBinary1 = 0

				if bifurcationEvenFinalZero and not bifurcationOddFinalZero:
					while findUnpairedBinary1 >= 0:
						XOrHere2makePair <<= 2
						findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
					bifurcationEven ^= XOrHere2makePair

				elif bifurcationOddFinalZero and not bifurcationEvenFinalZero:
					while findUnpairedBinary1 >= 0:
						XOrHere2makePair <<= 2
						findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
					bifurcationOdd ^= XOrHere2makePair

				curveLocationAnalysis = ((bifurcationEven >> 2) << 1) | (bifurcationOdd >> 2)
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

	return sum(dictionaryCurveLocations[bridges].values())

def initializeA000682(n: int) -> dict[int, int]:
	curveLocationsMAXIMUM = 1 << (2 * n + 4)

	curveSeed: int = 5 - (n & 0b1) * 4
	listCurveLocations = [(curveSeed << 1) | curveSeed]

	while listCurveLocations[-1] < curveLocationsMAXIMUM:
		curveSeed = (curveSeed << 4) | 0b101
		listCurveLocations.append((curveSeed << 1) | curveSeed)

	return dict.fromkeys(listCurveLocations, 1)

def A000682(n: int) -> int:
	return count(n - 1, initializeA000682(n - 1))

if __name__ == '__main__':
	n = 5

	print("\nDemonstration of dictionary comprehension.")

	print("\nStart module execution. IF it completes, it will print, 'Module complete.'")

	print(f"\nModule complete.\n{A000682(n) = }")

fromkeys with an extra line that prevents problems

I tried to keep the code as identical as possible.

fromkeys.py

# fromkeys.py
def count(bridges: int, startingCurveLocations: dict[int, int]) -> int:
	listCurveMaximums: list[tuple[int, int, int]] = [
	(16, 0x2a, 0x15),
	(64, 0xaa, 0x55),
	(256, 0x2aa, 0x155),
	(1024, 0xaaa, 0x555),
	(4096, 0x2aaa, 0x1555),
	(16384, 0xaaaa, 0x5555),
	(65536, 0x2aaaa, 0x15555),
	(262144, 0xaaaaa, 0x55555),
	(1048576, 0x2aaaaa, 0x155555),
	(4194304, 0xaaaaaa, 0x555555),
	(16777216, 0x2aaaaaa, 0x1555555),
	(67108864, 0xaaaaaaa, 0x5555555),
	(268435456, 0x2aaaaaaa, 0x15555555),
	(1073741824, 0xaaaaaaaa, 0x55555555),
	(4294967296, 0x2aaaaaaaa, 0x155555555),
	(17179869184, 0xaaaaaaaaa, 0x555555555),
	(68719476736, 0x2aaaaaaaaa, 0x1555555555),
	(274877906944, 0xaaaaaaaaaa, 0x5555555555),
	(1099511627776, 0x2aaaaaaaaaa, 0x15555555555),
	(4398046511104, 0xaaaaaaaaaaa, 0x55555555555),
	(17592186044416, 0x2aaaaaaaaaaa, 0x155555555555),
	(70368744177664, 0xaaaaaaaaaaaa, 0x555555555555),
	(281474976710656, 0x2aaaaaaaaaaaa, 0x1555555555555),
	(1125899906842624, 0xaaaaaaaaaaaaa, 0x5555555555555),
	(4503599627370496, 0x2aaaaaaaaaaaaa, 0x15555555555555),
	(18014398509481984, 0xaaaaaaaaaaaaaa, 0x55555555555555),
	(72057594037927936, 0x2aaaaaaaaaaaaaa, 0x155555555555555),
	(288230376151711744, 0xaaaaaaaaaaaaaaa, 0x555555555555555),
	(1152921504606846976, 0x2aaaaaaaaaaaaaaa, 0x1555555555555555),
	(4611686018427387904, 0xaaaaaaaaaaaaaaaa, 0x5555555555555555),
	(18446744073709551616, 0x2aaaaaaaaaaaaaaaa, 0x15555555555555555),
	(73786976294838206464, 0xaaaaaaaaaaaaaaaaa, 0x55555555555555555),
	(295147905179352825856, 0x2aaaaaaaaaaaaaaaaa, 0x155555555555555555),
	(1180591620717411303424, 0xaaaaaaaaaaaaaaaaaa, 0x555555555555555555),
	(4722366482869645213696, 0x2aaaaaaaaaaaaaaaaaa, 0x1555555555555555555),
	(18889465931478580854784, 0xaaaaaaaaaaaaaaaaaaa, 0x5555555555555555555),
	(75557863725914323419136, 0x2aaaaaaaaaaaaaaaaaaa, 0x15555555555555555555),
	(302231454903657293676544, 0xaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555),
	(1208925819614629174706176, 0x2aaaaaaaaaaaaaaaaaaaa, 0x155555555555555555555),
	(4835703278458516698824704, 0xaaaaaaaaaaaaaaaaaaaaa, 0x555555555555555555555),
	(19342813113834066795298816, 0x2aaaaaaaaaaaaaaaaaaaaa, 0x1555555555555555555555),
	(77371252455336267181195264, 0xaaaaaaaaaaaaaaaaaaaaaa, 0x5555555555555555555555),
	(309485009821345068724781056, 0x2aaaaaaaaaaaaaaaaaaaaaa, 0x15555555555555555555555),
	(1237940039285380274899124224, 0xaaaaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555555),
	(4951760157141521099596496896, 0x2aaaaaaaaaaaaaaaaaaaaaaa, 0x155555555555555555555555),
	(19807040628566084398385987584, 0xaaaaaaaaaaaaaaaaaaaaaaaa, 0x555555555555555555555555),
	]

	listCurveMaximums = listCurveMaximums[0:bridges]

	dictionaryCurveLocations: dict[int, dict[int, int]] = {}.fromkeys(range(bridges + 1), {})

	dictionaryCurveLocations[bridges] = startingCurveLocations.copy()

	print("\nAfter creating dictionary; before entering loop.")
	print(dictionaryCurveLocations)

	while bridges > 0:

		bridges -= 1

		print("\nAfter decrementing bridges; before executing statement.")
		print(dictionaryCurveLocations)
		dictionaryCurveLocations[bridges] = {}
		print(dictionaryCurveLocations)
		print("^^^After executing statement. (No change.)")

		print("\nExecuted statement:")
		print("`dictionaryCurveLocations[bridges] = {}`")


		curveLocationsMAXIMUM, bifurcationEvenLocator, bifurcationOddLocator = listCurveMaximums[bridges]

		while True:
			try:
				curveLocations, distinctCrossings = dictionaryCurveLocations[bridges+1].popitem()
			except KeyError:
				break
			bifurcationEven = (curveLocations & bifurcationEvenLocator) >> 1
			bifurcationOdd = (curveLocations & bifurcationOddLocator)
			bifurcationEvenFinalZero = (bifurcationEven & 0b1) == 0
			bifurcationEvenHasCurves = bifurcationEven != 1
			bifurcationOddFinalZero = (bifurcationOdd & 0b1) == 0
			bifurcationOddHasCurves = bifurcationOdd != 1

			if bifurcationEvenHasCurves:
				curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			if bifurcationOddHasCurves:
				curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
			if curveLocationAnalysis < curveLocationsMAXIMUM:
				dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			if bifurcationEvenHasCurves and bifurcationOddHasCurves and (bifurcationEvenFinalZero or bifurcationOddFinalZero):
				XOrHere2makePair = 0b1
				findUnpairedBinary1 = 0

				if bifurcationEvenFinalZero and not bifurcationOddFinalZero:
					while findUnpairedBinary1 >= 0:
						XOrHere2makePair <<= 2
						findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
					bifurcationEven ^= XOrHere2makePair

				elif bifurcationOddFinalZero and not bifurcationEvenFinalZero:
					while findUnpairedBinary1 >= 0:
						XOrHere2makePair <<= 2
						findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
					bifurcationOdd ^= XOrHere2makePair

				curveLocationAnalysis = ((bifurcationEven >> 2) << 1) | (bifurcationOdd >> 2)
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

	return sum(dictionaryCurveLocations[bridges].values())

def initializeA000682(n: int) -> dict[int, int]:
	curveLocationsMAXIMUM = 1 << (2 * n + 4)

	curveSeed: int = 5 - (n & 0b1) * 4
	listCurveLocations = [(curveSeed << 1) | curveSeed]

	while listCurveLocations[-1] < curveLocationsMAXIMUM:
		curveSeed = (curveSeed << 4) | 0b101
		listCurveLocations.append((curveSeed << 1) | curveSeed)

	return dict.fromkeys(listCurveLocations, 1)

def A000682(n: int) -> int:
	return count(n - 1, initializeA000682(n - 1))

if __name__ == '__main__':
	n = 5

	print("\nDemonstration that `dict.fromkeys()` works IF combined with:")
	print("`dictionaryCurveLocations[bridges] = {}`")

	print("\n`fromkeys` statement:")
	print("`dictionaryCurveLocations: dict[int, dict[int, int]] = {}.fromkeys(range(bridges + 1), {})`")

	print("\nStart module execution. When it completes, it will print, 'Module complete.'")

	print(f"\nModule complete.\n{A000682(n) = }")

fromkeys with pointers

fromkeys_hang.py

# fromkeys_hang.py
def count(bridges: int, startingCurveLocations: dict[int, int]) -> int:
	listCurveMaximums: list[tuple[int, int, int]] = [
	(16, 0x2a, 0x15),
	(64, 0xaa, 0x55),
	(256, 0x2aa, 0x155),
	(1024, 0xaaa, 0x555),
	(4096, 0x2aaa, 0x1555),
	(16384, 0xaaaa, 0x5555),
	(65536, 0x2aaaa, 0x15555),
	(262144, 0xaaaaa, 0x55555),
	(1048576, 0x2aaaaa, 0x155555),
	(4194304, 0xaaaaaa, 0x555555),
	(16777216, 0x2aaaaaa, 0x1555555),
	(67108864, 0xaaaaaaa, 0x5555555),
	(268435456, 0x2aaaaaaa, 0x15555555),
	(1073741824, 0xaaaaaaaa, 0x55555555),
	(4294967296, 0x2aaaaaaaa, 0x155555555),
	(17179869184, 0xaaaaaaaaa, 0x555555555),
	(68719476736, 0x2aaaaaaaaa, 0x1555555555),
	(274877906944, 0xaaaaaaaaaa, 0x5555555555),
	(1099511627776, 0x2aaaaaaaaaa, 0x15555555555),
	(4398046511104, 0xaaaaaaaaaaa, 0x55555555555),
	(17592186044416, 0x2aaaaaaaaaaa, 0x155555555555),
	(70368744177664, 0xaaaaaaaaaaaa, 0x555555555555),
	(281474976710656, 0x2aaaaaaaaaaaa, 0x1555555555555),
	(1125899906842624, 0xaaaaaaaaaaaaa, 0x5555555555555),
	(4503599627370496, 0x2aaaaaaaaaaaaa, 0x15555555555555),
	(18014398509481984, 0xaaaaaaaaaaaaaa, 0x55555555555555),
	(72057594037927936, 0x2aaaaaaaaaaaaaa, 0x155555555555555),
	(288230376151711744, 0xaaaaaaaaaaaaaaa, 0x555555555555555),
	(1152921504606846976, 0x2aaaaaaaaaaaaaaa, 0x1555555555555555),
	(4611686018427387904, 0xaaaaaaaaaaaaaaaa, 0x5555555555555555),
	(18446744073709551616, 0x2aaaaaaaaaaaaaaaa, 0x15555555555555555),
	(73786976294838206464, 0xaaaaaaaaaaaaaaaaa, 0x55555555555555555),
	(295147905179352825856, 0x2aaaaaaaaaaaaaaaaa, 0x155555555555555555),
	(1180591620717411303424, 0xaaaaaaaaaaaaaaaaaa, 0x555555555555555555),
	(4722366482869645213696, 0x2aaaaaaaaaaaaaaaaaa, 0x1555555555555555555),
	(18889465931478580854784, 0xaaaaaaaaaaaaaaaaaaa, 0x5555555555555555555),
	(75557863725914323419136, 0x2aaaaaaaaaaaaaaaaaaa, 0x15555555555555555555),
	(302231454903657293676544, 0xaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555),
	(1208925819614629174706176, 0x2aaaaaaaaaaaaaaaaaaaa, 0x155555555555555555555),
	(4835703278458516698824704, 0xaaaaaaaaaaaaaaaaaaaaa, 0x555555555555555555555),
	(19342813113834066795298816, 0x2aaaaaaaaaaaaaaaaaaaaa, 0x1555555555555555555555),
	(77371252455336267181195264, 0xaaaaaaaaaaaaaaaaaaaaaa, 0x5555555555555555555555),
	(309485009821345068724781056, 0x2aaaaaaaaaaaaaaaaaaaaaa, 0x15555555555555555555555),
	(1237940039285380274899124224, 0xaaaaaaaaaaaaaaaaaaaaaaa, 0x55555555555555555555555),
	(4951760157141521099596496896, 0x2aaaaaaaaaaaaaaaaaaaaaaa, 0x155555555555555555555555),
	(19807040628566084398385987584, 0xaaaaaaaaaaaaaaaaaaaaaaaa, 0x555555555555555555555555),
	]

	listCurveMaximums = listCurveMaximums[0:bridges]

	dictionaryCurveLocations: dict[int, dict[int, int]] = {}.fromkeys(range(bridges + 1), {})

	dictionaryCurveLocations[bridges] = startingCurveLocations.copy()
	dictionaryCurveLocations[bridges] = {88552200:996633}

	print("\nAfter creating dictionary; before entering loop.")
	print(dictionaryCurveLocations)

	while bridges > 0:

		bridges -= 1

		print("\nAfter decrementing bridges.")#; before executing statement.")
		print(dictionaryCurveLocations)
		# dictionaryCurveLocations[bridges] = {}
		# print(dictionaryCurveLocations)
		print("^^^`996633` should not be in all of the dictionaries.")

		print("\nExecuted statement:")
		print("`dictionaryCurveLocations[bridges] = {}`")

		curveLocationsMAXIMUM, bifurcationEvenLocator, bifurcationOddLocator = listCurveMaximums[bridges]

		while True:
			try:
				curveLocations, distinctCrossings = dictionaryCurveLocations[bridges+1].popitem()
			except KeyError:
				break
			bifurcationEven = (curveLocations & bifurcationEvenLocator) >> 1
			bifurcationOdd = (curveLocations & bifurcationOddLocator)
			bifurcationEvenFinalZero = (bifurcationEven & 0b1) == 0
			bifurcationEvenHasCurves = bifurcationEven != 1
			bifurcationOddFinalZero = (bifurcationOdd & 0b1) == 0
			bifurcationOddHasCurves = bifurcationOdd != 1

			if bifurcationEvenHasCurves:
				curveLocationAnalysis = (bifurcationEven >> 1) | (bifurcationOdd << 2) | bifurcationEvenFinalZero
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			if bifurcationOddHasCurves:
				curveLocationAnalysis = (bifurcationOdd >> 2) | (bifurcationEven << 3) | (bifurcationOddFinalZero << 1)
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			curveLocationAnalysis = ((bifurcationOdd | (bifurcationEven << 1)) << 2) | 3
			if curveLocationAnalysis < curveLocationsMAXIMUM:
				dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

			if bifurcationEvenHasCurves and bifurcationOddHasCurves and (bifurcationEvenFinalZero or bifurcationOddFinalZero):
				XOrHere2makePair = 0b1
				findUnpairedBinary1 = 0

				if bifurcationEvenFinalZero and not bifurcationOddFinalZero:
					while findUnpairedBinary1 >= 0:
						XOrHere2makePair <<= 2
						findUnpairedBinary1 += 1 if (bifurcationEven & XOrHere2makePair) == 0 else -1
					bifurcationEven ^= XOrHere2makePair

				elif bifurcationOddFinalZero and not bifurcationEvenFinalZero:
					while findUnpairedBinary1 >= 0:
						XOrHere2makePair <<= 2
						findUnpairedBinary1 += 1 if (bifurcationOdd & XOrHere2makePair) == 0 else -1
					bifurcationOdd ^= XOrHere2makePair

				curveLocationAnalysis = ((bifurcationEven >> 2) << 1) | (bifurcationOdd >> 2)
				if curveLocationAnalysis < curveLocationsMAXIMUM:
					dictionaryCurveLocations[bridges][curveLocationAnalysis] = dictionaryCurveLocations[bridges].get(curveLocationAnalysis, 0) + distinctCrossings

	return sum(dictionaryCurveLocations[bridges].values())

def initializeA000682(n: int) -> dict[int, int]:
	curveLocationsMAXIMUM = 1 << (2 * n + 4)

	curveSeed: int = 5 - (n & 0b1) * 4
	listCurveLocations = [(curveSeed << 1) | curveSeed]

	while listCurveLocations[-1] < curveLocationsMAXIMUM:
		curveSeed = (curveSeed << 4) | 0b101
		listCurveLocations.append((curveSeed << 1) | curveSeed)

	return dict.fromkeys(listCurveLocations, 1)

def A000682(n: int) -> int:
	return count(n - 1, initializeA000682(n - 1))

if __name__ == '__main__':
	n = 5

	print("\nDemonstration that `dict.fromkeys()` does not act the same as dictionary comprehension.")

	print("\n`fromkeys` statement:")
	print("`dictionaryCurveLocations: dict[int, dict[int, int]] = {}.fromkeys(range(bridges + 1), {})`")

	print("\nStart module execution. IF it completes, it will print, 'Module complete.'")

	print(f"\nModule complete.\n{A000682(n) = }")

"Bad" output

996633 should not be in all of the dictionaries. The code didn't update all of them.

(.venv) C:\apps\mapFolding>C:\apps\mapFolding\.venv\Scripts\python.exe c:/apps/mapFolding/fromkeys_hang.py

Demonstration that `dict.fromkeys()` does not act the same as dictionary comprehension.

`fromkeys` statement:
`dictionaryCurveLocations: dict[int, dict[int, int]] = {}.fromkeys(range(bridges + 1), {})`

Start module execution. IF it completes, it will print, 'Module complete.'

After creating dictionary; before entering loop.
{0: {}, 1: {}, 2: {}, 3: {}, 4: {88552200: 996633}}

After decrementing bridges.
{0: {}, 1: {}, 2: {}, 3: {}, 4: {88552200: 996633}}
^^^`996633` should not be in all of the dictionaries.

Executed statement:
`dictionaryCurveLocations[bridges] = {}`

After decrementing bridges.
{0: {194: 996633}, 1: {194: 996633}, 2: {194: 996633}, 3: {194: 996633}, 4: {}}
^^^`996633` should not be in all of the dictionaries.

Executed statement:
`dictionaryCurveLocations[bridges] = {}`

Good output

The values sort of move to the left one step at a time, and the values change when they "move".

(.venv) C:\apps\mapFolding>C:\apps\mapFolding\.venv\Scripts\python.exe c:/apps/mapFolding/fromkeys_comprehension.py

Demonstration of dictionary comprehension.

Start module execution. IF it completes, it will print, 'Module complete.'

After creating dictionary; before entering loop.
{0: {}, 1: {}, 2: {}, 3: {}, 4: {15: 1, 255: 1, 4095: 1, 65535: 1}}

After decrementing bridges.
{0: {}, 1: {}, 2: {}, 3: {}, 4: {15: 1, 255: 1, 4095: 1, 65535: 1}}
{0: {}, 1: {}, 2: {}, 3: {}, 4: {15: 1, 255: 1, 4095: 1, 65535: 1}}
^^^After NOT executing statement. (No change.)

Executed statement:
`dictionaryCurveLocations[bridges] = {}`

After decrementing bridges.
{0: {}, 1: {}, 2: {}, 3: {382: 1, 701: 1, 1023: 1, 22: 1, 41: 1, 63: 1}, 4: {}}
{0: {}, 1: {}, 2: {}, 3: {382: 1, 701: 1, 1023: 1, 22: 1, 41: 1, 63: 1}, 4: {}}
^^^After NOT executing statement. (No change.)

Executed statement:
`dictionaryCurveLocations[bridges] = {}`

After decrementing bridges.
{0: {}, 1: {}, 2: {94: 2, 173: 2, 255: 3, 15: 2, 167: 1, 91: 1}, 3: {}, 4: {}}
{0: {}, 1: {}, 2: {94: 2, 173: 2, 255: 3, 15: 2, 167: 1, 91: 1}, 3: {}, 4: {}}
^^^After NOT executing statement. (No change.)

Executed statement:
`dictionaryCurveLocations[bridges] = {}`

After decrementing bridges.
{0: {}, 1: {60: 2, 22: 4, 41: 4, 63: 6}, 2: {}, 3: {}, 4: {}}
{0: {}, 1: {60: 2, 22: 4, 41: 4, 63: 6}, 2: {}, 3: {}, 4: {}}
^^^After NOT executing statement. (No change.)

Executed statement:
`dictionaryCurveLocations[bridges] = {}`

Module complete.
A000682(n) = 10

CPython versions tested on:

3.13, 3.12

Operating systems tested on:

Windows, Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions